diff --git a/Dockerfile b/Dockerfile index 06753f267..dff7d643b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,27 +12,14 @@ RUN --mount=type=cache,target=/root/.cache/go-build \ # Cosmwasm - download correct libwasmvm version RUN WASMVM_VERSION=$(go list -m github.com/CosmWasm/wasmvm | cut -d ' ' -f 2) && \ wget https://github.com/CosmWasm/wasmvm/releases/download/${WASMVM_VERSION}/libwasmvm_muslc.$(uname -m).a \ - -O /lib/libwasmvm_muslc.a && \ - wget https://github.com/CosmWasm/wasmvm/releases/download/${WASMVM_VERSION}/checksums.txt -O /tmp/checksums.txt && \ + -O /lib/libwasmvm_muslc.a && \ + wget https://github.com/CosmWasm/wasmvm/releases/download/${WASMVM_VERSION}/checksums.txt -O /tmp/checksums.txt && \ sha256sum /lib/libwasmvm_muslc.a | grep $(cat /tmp/checksums.txt | grep $(uname -m) | cut -d ' ' -f 1) COPY . . RUN --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/root/go/pkg/mod \ - VERSION=$(echo $(git describe --tags) | sed 's/^v//') && \ - COMMIT=$(git log -1 --format='%H') && \ - go build \ - -mod=readonly \ - -tags "netgo,ledger,muslc,pebbledb" \ - -ldflags "-X github.com/cosmos/cosmos-sdk/version.Name="quicksilver" \ - -X github.com/cosmos/cosmos-sdk/version.AppName="quicksilverd" \ - -X github.com/cosmos/cosmos-sdk/version.Version=$VERSION \ - -X github.com/cosmos/cosmos-sdk/version.Commit=$COMMIT \ - -X github.com/cosmos/cosmos-sdk/version.BuildTags='netgo,ledger,muslc' \ - -w -s -linkmode=external -extldflags '-Wl,-z,muldefs -static'" \ - -trimpath \ - -o /src/app/build/ \ - ./... + LINK_STATICALLY=true make build # Add to a distroless container FROM alpine:3.17 diff --git a/Makefile b/Makefile index 0deaa55b7..0a550b161 100755 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ #!/usr/bin/make -f DOCKER_BUILDKIT=1 -COSMOS_BUILD_OPTIONS ?= "pebbledb" +COSMOS_BUILD_OPTIONS ?= "" PACKAGES_NOSIMULATION=$(shell go list ./... | grep -v '/simulation') PACKAGES_SIMTEST=$(shell go list ./... | grep '/simulation') VERSION=$(shell git describe --tags | head -n1) @@ -94,6 +94,7 @@ endif ifeq ($(LINK_STATICALLY),true) ldflags += -linkmode=external -extldflags "-Wl,-z,muldefs -static" + build_tags += muslc endif build_tags += $(BUILD_TAGS) @@ -438,11 +439,11 @@ proto-check-breaking: @$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main -TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.21/proto/tendermint +TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.25/proto/tendermint GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/cosmos -CONFIO_URL = https://raw.githubusercontent.com/confio/ics23/v0.7.1 -SDK_PROTO_URL = https://raw.githubusercontent.com/cosmos/cosmos-sdk/v0.46.1/proto/cosmos -IBC_PROTO_URL = https://raw.githubusercontent.com/cosmos/ibc-go/v5.0.0-rc2/proto +CONFIO_URL = https://raw.githubusercontent.com/confio/ics23/v0.9.0 +SDK_PROTO_URL = https://raw.githubusercontent.com/cosmos/cosmos-sdk/v0.46.8/proto/cosmos +IBC_PROTO_URL = https://raw.githubusercontent.com/cosmos/ibc-go/v5.2.0/proto TM_CRYPTO_TYPES = third_party/proto/tendermint/crypto TM_ABCI_TYPES = third_party/proto/tendermint/abci diff --git a/app/upgrades.go b/app/upgrades.go index 9cb7bb2f0..1f53c149c 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -1,34 +1,53 @@ package app import ( - "errors" "fmt" - "strings" + "time" sdkmath "cosmossdk.io/math" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - icqtypes "github.com/ingenuity-build/quicksilver/x/interchainquery/types" + "github.com/ingenuity-build/quicksilver/utils" icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" - "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" + icstypes "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" tokenfactorytypes "github.com/ingenuity-build/quicksilver/x/tokenfactory/types" ) // upgrade name consts: vMMmmppUpgradeName (M=Major, m=minor, p=patch) const ( ProductionChainID = "quicksilver-2" - InnuendoChainID = "innuendo-4" + InnuendoChainID = "innuendo-5" DevnetChainID = "quicktest-1" + TestChainID = "testchain1" - v010300UpgradeName = "v1.3.0" - v010400UpgradeName = "v1.4.0" + v010300UpgradeName = "v1.3.0" + v010400UpgradeName = "v1.4.0" + v010400rc6UpgradeName = "v1.4.0-rc6" ) +func isTest(ctx sdk.Context) bool { + return ctx.ChainID() == TestChainID +} + +func isDevnet(ctx sdk.Context) bool { + return ctx.ChainID() == DevnetChainID +} + +func isTestnet(ctx sdk.Context) bool { + return ctx.ChainID() == InnuendoChainID +} + +//nolint:all //function useful for writing network specific upgrade handlers +func isMainnet(ctx sdk.Context) bool { + return ctx.ChainID() == ProductionChainID +} + func setUpgradeHandlers(app *Quicksilver) { app.UpgradeKeeper.SetUpgradeHandler(v010300UpgradeName, noOpHandler(app)) app.UpgradeKeeper.SetUpgradeHandler(v010400UpgradeName, v010400UpgradeHandler(app)) + app.UpgradeKeeper.SetUpgradeHandler(v010400rc6UpgradeName, v010400rc6UpgradeHandler(app)) // When a planned update height is reached, the old binary will panic // writing on disk the height and name of the update that triggered it @@ -68,7 +87,7 @@ func noOpHandler(app *Quicksilver) upgradetypes.UpgradeHandler { func v010400UpgradeHandler(app *Quicksilver) upgradetypes.UpgradeHandler { return func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { // upgrade zones - app.InterchainstakingKeeper.IterateZones(ctx, func(index int64, zone types.Zone) (stop bool) { + app.InterchainstakingKeeper.IterateZones(ctx, func(index int64, zone icstypes.Zone) (stop bool) { zone.DepositsEnabled = true zone.ReturnToSender = false zone.UnbondingEnabled = false @@ -84,72 +103,16 @@ func v010400UpgradeHandler(app *Quicksilver) upgradetypes.UpgradeHandler { r.Completed = &time app.InterchainstakingKeeper.SetReceipt(ctx, r) } - if ctx.ChainID() == "innuendo-5" || ctx.ChainID() == "testchain1" { - - // clear uni-5 unbondings - app.InterchainstakingKeeper.IteratePrefixedUnbondingRecords(ctx, []byte("uni-5"), func(_ int64, record types.UnbondingRecord) (stop bool) { - app.InterchainstakingKeeper.DeleteUnbondingRecord(ctx, record.ChainId, record.Validator, record.EpochNumber) - return false - }) - - // clear uni-5 redelegations - app.InterchainstakingKeeper.IteratePrefixedRedelegationRecords(ctx, []byte("uni-5"), func(_ int64, _ []byte, record types.RedelegationRecord) (stop bool) { - app.InterchainstakingKeeper.DeleteRedelegationRecord(ctx, record.ChainId, record.Source, record.Destination, record.EpochNumber) - return false - }) - - // remove uni-5 zone and related records - app.InterchainstakingKeeper.IterateZones(ctx, func(index int64, zone types.Zone) (stop bool) { - if zone.ChainId == "uni-5" { - // remove uni-5 delegation records - app.InterchainstakingKeeper.IterateAllDelegations(ctx, &zone, func(delegation types.Delegation) (stop bool) { - err := app.InterchainstakingKeeper.RemoveDelegation(ctx, &zone, delegation) - if err != nil { - panic(err) - } - return false - }) - - // remove uni-5 performance delegation records - app.InterchainstakingKeeper.IterateAllPerformanceDelegations(ctx, &zone, func(delegation types.Delegation) (stop bool) { - err := app.InterchainstakingKeeper.RemoveDelegation(ctx, &zone, delegation) - if err != nil { - panic(err) - } - return false - }) - // remove uni-5 receipts - app.InterchainstakingKeeper.IterateZoneReceipts(ctx, &zone, func(index int64, receiptInfo types.Receipt) (stop bool) { - app.InterchainstakingKeeper.DeleteReceipt(ctx, icskeeper.GetReceiptKey(receiptInfo.ChainId, receiptInfo.Txhash)) - return false - }) - - // remove zone withdrawal records - app.InterchainstakingKeeper.IterateZoneWithdrawalRecords(ctx, zone.ChainId, func(index int64, record types.WithdrawalRecord) (stop bool) { - app.InterchainstakingKeeper.DeleteWithdrawalRecord(ctx, zone.ChainId, record.Txhash, record.Status) - return false - }) - - app.InterchainstakingKeeper.DeleteZone(ctx, zone.ChainId) - - } - return false - }) + if isTestnet(ctx) || isTest(ctx) { - // remove uni-5 queries in state - app.InterchainQueryKeeper.IterateQueries(ctx, func(_ int64, queryInfo icqtypes.Query) (stop bool) { - if queryInfo.ChainId == "uni-5" { - app.InterchainQueryKeeper.DeleteQuery(ctx, queryInfo.Id) - } - return false - }) + app.InterchainstakingKeeper.RemoveZoneAndAssociatedRecords(ctx, "uni-5") // burn uqjunox - addr1, err := AccAddressFromBech32("quick17v9kk34km3w6hdjs2sn5s5qjdu2zrm0m3rgtmq", "quick") + addr1, err := utils.AccAddressFromBech32("quick17v9kk34km3w6hdjs2sn5s5qjdu2zrm0m3rgtmq", "quick") if err != nil { return nil, err } - addr2, err := AccAddressFromBech32("quick16x03wcp37kx5e8ehckjxvwcgk9j0cqnhcccnty", "quick") + addr2, err := utils.AccAddressFromBech32("quick16x03wcp37kx5e8ehckjxvwcgk9j0cqnhcccnty", "quick") if err != nil { return nil, err } @@ -164,7 +127,7 @@ func v010400UpgradeHandler(app *Quicksilver) upgradetypes.UpgradeHandler { return nil, err } - err = app.BankKeeper.SendCoinsFromModuleToModule(ctx, types.EscrowModuleAccount, tokenfactorytypes.ModuleName, sdk.NewCoins(sdk.NewCoin("uqjunox", sdkmath.NewInt(400000)))) + err = app.BankKeeper.SendCoinsFromModuleToModule(ctx, icstypes.EscrowModuleAccount, tokenfactorytypes.ModuleName, sdk.NewCoins(sdk.NewCoin("uqjunox", sdkmath.NewInt(400000)))) if err != nil { return nil, err } @@ -178,21 +141,58 @@ func v010400UpgradeHandler(app *Quicksilver) upgradetypes.UpgradeHandler { } } -// AccAddressFromBech32 creates an AccAddress from a Bech32 string. -func AccAddressFromBech32(address, prefix string) (addr sdk.AccAddress, err error) { - if len(strings.TrimSpace(address)) == 0 { - return sdk.AccAddress{}, errors.New("empty address string is not allowed") - } +func v010400rc6UpgradeHandler(app *Quicksilver) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + if isTestnet(ctx) { + app.InterchainstakingKeeper.RemoveZoneAndAssociatedRecords(ctx, "regen-redwood-1") + // re-register regen-redwood-1 with new connection + regenProp := icstypes.NewRegisterZoneProposal("register regen-redwood-1 zone", + "register regen-redwood-1 (regen-testnet) zone with multisend and lsm disabled", + "connection-8", + "uregen", + "uqregen", + "regen", + false, + true, + true, + false, + 6) + err := icskeeper.HandleRegisterZoneProposal(ctx, app.InterchainstakingKeeper, regenProp) + if err != nil { + return nil, err + } + } - bz, err := sdk.GetFromBech32(address, prefix) - if err != nil { - return nil, err - } + // remove expired failed redelegation records + app.InterchainstakingKeeper.IterateRedelegationRecords(ctx, func(_ int64, key []byte, record icstypes.RedelegationRecord) (stop bool) { + if record.CompletionTime.Equal(time.Time{}) { + app.InterchainstakingKeeper.DeleteRedelegationRecord(ctx, record.ChainId, record.Source, record.Destination, record.EpochNumber) + } + return false + }) - err = sdk.VerifyAddressFormat(bz) - if err != nil { - return nil, err - } + // remove and refund failed unbondings + app.InterchainstakingKeeper.IterateWithdrawalRecords(ctx, func(index int64, record icstypes.WithdrawalRecord) (stop bool) { + if record.Status == icskeeper.WithdrawStatusUnbond && record.CompletionTime.Equal(time.Time{}) { + delegatorAcc, err := utils.AccAddressFromBech32(record.Delegator, "quick") + if err != nil { + panic(err) + } + if err = app.InterchainstakingKeeper.BankKeeper.SendCoinsFromModuleToAccount(ctx, icstypes.EscrowModuleAccount, delegatorAcc, sdk.NewCoins(record.BurnAmount)); err != nil { + panic(err) + } + app.InterchainstakingKeeper.DeleteWithdrawalRecord(ctx, record.ChainId, record.Txhash, record.Status) + } + return false + }) - return bz, nil + if isTestnet(ctx) || isDevnet(ctx) { + app.InterchainstakingKeeper.IterateZones(ctx, func(index int64, zoneInfo icstypes.Zone) (stop bool) { + app.InterchainstakingKeeper.OverrideRedemptionRateNoCap(ctx, zoneInfo) + return false + }) + } + + return app.mm.RunMigrations(ctx, app.configurator, fromVM) + } } diff --git a/app/upgrades_test.go b/app/upgrades_test.go index f4777774e..63eeeab13 100644 --- a/app/upgrades_test.go +++ b/app/upgrades_test.go @@ -1,13 +1,14 @@ package app import ( + "testing" + "time" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ingenuity-build/quicksilver/utils" icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" tokenfactorytypes "github.com/ingenuity-build/quicksilver/x/tokenfactory/types" - "testing" - "time" "github.com/cosmos/cosmos-sdk/x/upgrade/types" ibctesting "github.com/cosmos/ibc-go/v5/testing" @@ -149,6 +150,16 @@ func (suite *AppTestSuite) initTestZone() { } suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetRedelegationRecord(suite.chainA.GetContext(), rdRecord) + rdRecord = icstypes.RedelegationRecord{ + ChainId: "osmosis-1", + EpochNumber: 1, + Source: "osmovaloper1zxavllftfx3a3y5ldfyze7jnu5uyuktsfx2jcc", + Destination: "osmovaloper13eq5c99ym05jn02e78l8cac2fagzgdhh4294zk", + Amount: 3000000, + CompletionTime: time.Time{}, + } + suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetRedelegationRecord(suite.chainA.GetContext(), rdRecord) + delRecord := icstypes.Delegation{ Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewInt(17000)), DelegationAddress: "juno1z89utvygweg5l56fsk8ak7t6hh88fd0azcjpz5", @@ -177,11 +188,11 @@ func (suite *AppTestSuite) initTestZone() { if err != nil { return } - addr1, err := AccAddressFromBech32("quick17v9kk34km3w6hdjs2sn5s5qjdu2zrm0m3rgtmq", "quick") + addr1, err := utils.AccAddressFromBech32("quick17v9kk34km3w6hdjs2sn5s5qjdu2zrm0m3rgtmq", "quick") if err != nil { return } - addr2, err := AccAddressFromBech32("quick16x03wcp37kx5e8ehckjxvwcgk9j0cqnhcccnty", "quick") + addr2, err := utils.AccAddressFromBech32("quick16x03wcp37kx5e8ehckjxvwcgk9j0cqnhcccnty", "quick") if err != nil { return } @@ -198,7 +209,6 @@ func (suite *AppTestSuite) initTestZone() { if err != nil { return } - } func (s *AppTestSuite) TestV010400UpgradeHandler() { @@ -253,5 +263,20 @@ func (s *AppTestSuite) TestV010400UpgradeHandler() { _, found = app.InterchainstakingKeeper.GetWithdrawalRecord(ctx, "uni-5", "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", icskeeper.WithdrawStatusQueued) s.Require().False(found) +} + +func (s *AppTestSuite) TestV010400rc6UpgradeHandler() { + app := s.GetQuicksilverApp(s.chainA) + handler := v010400rc6UpgradeHandler(app) + ctx := s.chainA.GetContext() + + redelegations := app.InterchainstakingKeeper.ZoneRedelegationRecords(ctx, "osmosis-1") + s.Require().Equal(1, len(redelegations)) + + _, err := handler(ctx, types.Plan{}, app.mm.GetVersionMap()) + s.Require().NoError(err) + + redelegations = app.InterchainstakingKeeper.ZoneRedelegationRecords(ctx, "osmosis-1") + s.Require().Equal(0, len(redelegations)) } diff --git a/go.mod b/go.mod index 531584dd0..fb6ba8752 100644 --- a/go.mod +++ b/go.mod @@ -6,20 +6,20 @@ require ( cosmossdk.io/math v1.0.0-beta.4 github.com/CosmWasm/wasmd v0.29.2 github.com/cosmos/cosmos-proto v1.0.0-alpha8 - github.com/cosmos/cosmos-sdk v0.46.8 + github.com/cosmos/cosmos-sdk v0.46.9 github.com/cosmos/ibc-go/v5 v5.2.0 github.com/gogo/protobuf v1.3.3 github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/iqlusioninc/liquidity-staking-module v1.0.0 - github.com/prometheus/client_golang v1.13.0 + github.com/prometheus/client_golang v1.14.0 github.com/rakyll/statik v0.1.7 github.com/spf13/cast v1.5.0 - github.com/spf13/cobra v1.6.0 + github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.13.0 github.com/stretchr/testify v1.8.1 - github.com/tendermint/tendermint v0.34.25 + github.com/tendermint/tendermint v0.34.26 github.com/tendermint/tm-db v0.6.8-0.20220506192307-f628bb5dc95b go.opencensus.io v0.23.0 golang.org/x/exp v0.0.0-20220914170420-dc92f8653013 @@ -56,7 +56,6 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/bgentry/speakeasy v0.1.1-0.20220910012023-760eaf8b6816 // indirect - github.com/btcsuite/btcd v0.22.2 // indirect github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect @@ -73,7 +72,7 @@ require ( github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogoproto v1.4.2 // indirect github.com/cosmos/gorocksdb v1.2.0 // indirect - github.com/cosmos/iavl v0.19.4 // indirect + github.com/cosmos/iavl v0.19.5 // indirect github.com/cosmos/ledger-cosmos-go v0.12.2 // indirect github.com/creachadair/taskgroup v0.3.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect @@ -140,7 +139,7 @@ require ( 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_model v0.2.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/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect @@ -158,12 +157,12 @@ require ( github.com/ulikunitz/xz v0.5.8 // indirect github.com/zondax/hid v0.9.1 // indirect go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/crypto v0.4.0 // indirect - golang.org/x/net v0.4.0 // indirect + golang.org/x/crypto v0.5.0 // indirect + golang.org/x/net v0.5.0 // indirect golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + golang.org/x/sys v0.4.0 // indirect + golang.org/x/term v0.4.0 // indirect + golang.org/x/text v0.6.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.102.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -181,7 +180,7 @@ replace ( github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.8.1 github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 github.com/iqlusioninc/liquidity-staking-module => github.com/notional-labs/liquidity-staking-module v0.0.3-0.20220914043211-d4675d9af6ae - github.com/tendermint/tendermint => github.com/informalsystems/tendermint v0.34.25 + github.com/tendermint/tendermint => github.com/informalsystems/tendermint v0.34.26 // pebbledb - https://gist.github.com/faddat/673107b72eccdd869b242338dd17e9d9 github.com/tendermint/tm-db => github.com/notional-labs/tm-db v0.6.7-0.20220731185452-136c7b65fb62 ) diff --git a/go.sum b/go.sum index 01167d975..681fa9c24 100644 --- a/go.sum +++ b/go.sum @@ -153,9 +153,8 @@ github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx2 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.0.20201114000516-e9c7a5ac6401/go.mod h1:Sv4JPQ3/M+teHz9Bo5jBpkNcP0x6r7rdihlNL/7tTAs= +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 v0.22.2 h1:vBZ+lGGd1XubpOWO67ITJpAEsICWhA0YzqkcpkgNBfo= -github.com/btcsuite/btcd v0.22.2/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= github.com/btcsuite/btcd/btcec/v2 v2.1.2/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= @@ -242,8 +241,8 @@ github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= 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 v0.46.8 h1:n3brrFOwTwR9cKpr+k6vf6ryU+4iyzNdKOnQzEP9DwM= -github.com/cosmos/cosmos-sdk v0.46.8/go.mod h1:lg+FqwndbbCYQk1YTUWRDpOsNbQG0nINQqxY7ZnsAP8= +github.com/cosmos/cosmos-sdk v0.46.9 h1:s19zY5vX0kjV2eJOzR0Y3P6EqgtgpwMdPmXM05TQsXM= +github.com/cosmos/cosmos-sdk v0.46.9/go.mod h1:ZFL/yjcIZq67H8FiWoLCnnaChkXnbRRYEEhGrFq8fzE= 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= @@ -251,8 +250,8 @@ github.com/cosmos/gogoproto v1.4.2 h1:UeGRcmFW41l0G0MiefWhkPEVEwvu78SZsHBvI78dAY github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= 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/iavl v0.19.5 h1:rGA3hOrgNxgRM5wYcSCxgQBap7fW82WZgY78V9po/iY= +github.com/cosmos/iavl v0.19.5/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/ibc-go/v5 v5.2.0 h1:LxwttRQqdUJpQ3/Gc3XPg5lkRo3pcbzx65dxFIY6ONE= github.com/cosmos/ibc-go/v5 v5.2.0/go.mod h1:MhDUMDVSboK5JW2pEWHNcw0wJHaHqKV/vwwP7awGhzI= github.com/cosmos/interchain-accounts v0.3.2 h1:7S5rSndahpjkzUvG00kKZrTZsEuVHuVC9a7p0qDVcF8= @@ -612,8 +611,8 @@ github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19y github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= -github.com/informalsystems/tendermint v0.34.25 h1:KlTF1ECfJI2KmM1w1YGai5hoLJ0ZOKjVwGAaElEBPtE= -github.com/informalsystems/tendermint v0.34.25/go.mod h1:TCGT4eRe5OW979YKVTpFOM57B4YkN+7FSDWpsgzAGwY= +github.com/informalsystems/tendermint v0.34.26 h1:89XvVexAy62geGWxmDmdmmJvfindx+Su2oTuwfSWMeU= +github.com/informalsystems/tendermint v0.34.26/go.mod h1:q3uAZ/t5+MblQhFuHSd4flqaLDx7iUtWpwWbwvHAFhs= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= @@ -870,15 +869,16 @@ github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3O 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.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= +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 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 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= @@ -963,8 +963,8 @@ 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.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= -github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +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= @@ -1101,8 +1101,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= -golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= +golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= 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-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1203,8 +1203,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/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.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= 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= @@ -1314,13 +1314,13 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/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-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.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= 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= @@ -1330,8 +1330,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/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.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= +golang.org/x/text v0.6.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= diff --git a/osmosis-types/gamm/errors.go b/osmosis-types/gamm/errors.go index b8fb59203..9e7f1db4c 100644 --- a/osmosis-types/gamm/errors.go +++ b/osmosis-types/gamm/errors.go @@ -1,8 +1,9 @@ package gamm import ( - sdkioerrors "cosmossdk.io/errors" "fmt" + + sdkioerrors "cosmossdk.io/errors" ) type PoolDoesNotExistError struct { diff --git a/osmosis-types/gamm/msgs.go b/osmosis-types/gamm/msgs.go index d1df5a983..26047e2bf 100644 --- a/osmosis-types/gamm/msgs.go +++ b/osmosis-types/gamm/msgs.go @@ -1,11 +1,12 @@ package gamm import ( - sdkioerrors "cosmossdk.io/errors" "fmt" "strings" "time" + sdkioerrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/osmosis-types/gamm/pool-models/balancer/amm.go b/osmosis-types/gamm/pool-models/balancer/amm.go index 3056e4b90..6a3899154 100644 --- a/osmosis-types/gamm/pool-models/balancer/amm.go +++ b/osmosis-types/gamm/pool-models/balancer/amm.go @@ -1,9 +1,10 @@ package balancer import ( - sdkioerrors "cosmossdk.io/errors" "fmt" + sdkioerrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ingenuity-build/quicksilver/osmosis-types/gamm" diff --git a/osmosis-types/gamm/pool-models/balancer/pool.go b/osmosis-types/gamm/pool-models/balancer/pool.go index f906c7a66..b6d208817 100644 --- a/osmosis-types/gamm/pool-models/balancer/pool.go +++ b/osmosis-types/gamm/pool-models/balancer/pool.go @@ -1,13 +1,14 @@ package balancer import ( - sdkioerrors "cosmossdk.io/errors" "errors" "fmt" "sort" "strings" "time" + sdkioerrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ingenuity-build/quicksilver/osmosis-types/gamm" "github.com/ingenuity-build/quicksilver/osmosis-types/gamm/pool-models/internal/cfmm_common" diff --git a/osmosis-types/gamm/pool-models/balancer/pool_asset.go b/osmosis-types/gamm/pool-models/balancer/pool_asset.go index 9360f5636..c1e978b2e 100644 --- a/osmosis-types/gamm/pool-models/balancer/pool_asset.go +++ b/osmosis-types/gamm/pool-models/balancer/pool_asset.go @@ -1,11 +1,12 @@ package balancer import ( - sdkioerrors "cosmossdk.io/errors" "fmt" "sort" "strings" + sdkioerrors "cosmossdk.io/errors" + "gopkg.in/yaml.v2" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/osmosis-types/gamm/pool-models/internal/cfmm_common/lp.go b/osmosis-types/gamm/pool-models/internal/cfmm_common/lp.go index 1c9451be3..fee52ed13 100644 --- a/osmosis-types/gamm/pool-models/internal/cfmm_common/lp.go +++ b/osmosis-types/gamm/pool-models/internal/cfmm_common/lp.go @@ -1,9 +1,10 @@ package cfmm_common import ( - sdkioerrors "cosmossdk.io/errors" "errors" + sdkioerrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ingenuity-build/quicksilver/osmosis-types/gamm" diff --git a/osmosis-types/gamm/pool-models/stableswap/pool.go b/osmosis-types/gamm/pool-models/stableswap/pool.go index 4acf9494a..fdb51d437 100644 --- a/osmosis-types/gamm/pool-models/stableswap/pool.go +++ b/osmosis-types/gamm/pool-models/stableswap/pool.go @@ -1,12 +1,13 @@ package stableswap import ( - sdkioerrors "cosmossdk.io/errors" "encoding/json" "errors" "fmt" "time" + sdkioerrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ingenuity-build/quicksilver/osmosis-types/gamm" diff --git a/osmosis-types/lockup/msgs.go b/osmosis-types/lockup/msgs.go index 9401551f6..cca53eca9 100644 --- a/osmosis-types/lockup/msgs.go +++ b/osmosis-types/lockup/msgs.go @@ -1,11 +1,12 @@ package lockup import ( - sdkioerrors "cosmossdk.io/errors" "errors" "fmt" "time" + sdkioerrors "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) diff --git a/proto/quicksilver/interchainstaking/v1/interchainstaking.proto b/proto/quicksilver/interchainstaking/v1/interchainstaking.proto index d056c1e82..c0efcdf2d 100644 --- a/proto/quicksilver/interchainstaking/v1/interchainstaking.proto +++ b/proto/quicksilver/interchainstaking/v1/interchainstaking.proto @@ -85,6 +85,7 @@ message WithdrawalRecord { int32 status = 8; google.protobuf.Timestamp completion_time = 9 [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; + bool requeued = 10; } message UnbondingRecord { diff --git a/proto/quicksilver/interchainstaking/v1/query.proto b/proto/quicksilver/interchainstaking/v1/query.proto index 9f26ded28..3e707d8ae 100644 --- a/proto/quicksilver/interchainstaking/v1/query.proto +++ b/proto/quicksilver/interchainstaking/v1/query.proto @@ -86,6 +86,7 @@ message Statistics { int64 depositors = 4; int64 delegated = 5; int64 supply = 6; + string distance_to_target = 7; } message QueryZonesInfoRequest { diff --git a/x/claimsmanager/keeper/keeper.go b/x/claimsmanager/keeper/keeper.go index 690e2d643..1d4c36c77 100644 --- a/x/claimsmanager/keeper/keeper.go +++ b/x/claimsmanager/keeper/keeper.go @@ -41,6 +41,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { } func (k Keeper) StoreSelfConsensusState(ctx sdk.Context, key string) error { + var height ibcclienttypes.Height if strings.Contains(ctx.ChainID(), "-") { revisionNum, err := strconv.ParseUint(strings.Split(ctx.ChainID(), "-")[1], 10, 64) if err != nil { @@ -48,35 +49,26 @@ func (k Keeper) StoreSelfConsensusState(ctx sdk.Context, key string) error { return err } - height := ibcclienttypes.Height{ + height = ibcclienttypes.Height{ RevisionNumber: revisionNum, RevisionHeight: uint64(ctx.BlockHeight() - 1), } - - selfConsState, err := k.IBCKeeper.ClientKeeper.GetSelfConsensusState(ctx, height) - if err != nil { - k.Logger(ctx).Error("Error getting self consensus state of previous height") - return err - } - - state := selfConsState.(*ibctmtypes.ConsensusState) - k.SetSelfConsensusState(ctx, key, state) } else { // ONLY FOR TESTING - ibctesting module chains donot follow standard [chainname]-[num] structure - height := ibcclienttypes.Height{ + height = ibcclienttypes.Height{ RevisionNumber: 0, // revision number for testchain1 is 0 (because parseChainId splits on '-') RevisionHeight: uint64(ctx.BlockHeight() - 1), } + } - selfConsState, err := k.IBCKeeper.ClientKeeper.GetSelfConsensusState(ctx, height) - if err != nil { - k.Logger(ctx).Error("Error getting self consensus state of previous height") - return err - } + selfConsState, err := k.IBCKeeper.ClientKeeper.GetSelfConsensusState(ctx, height) + if err != nil { + k.Logger(ctx).Error("Error getting self consensus state of previous height") + return err + } - state := selfConsState.(*ibctmtypes.ConsensusState) - k.SetSelfConsensusState(ctx, key, state) + state := selfConsState.(*ibctmtypes.ConsensusState) + k.SetSelfConsensusState(ctx, key, state) - } return nil } diff --git a/x/epochs/types/hooks.go b/x/epochs/types/hooks.go index fbd29478a..8c2cf9464 100644 --- a/x/epochs/types/hooks.go +++ b/x/epochs/types/hooks.go @@ -34,7 +34,7 @@ func (h MultiEpochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, // BeforeEpochStart is called when epoch is going to be started, epochNumber is the number of epoch that is starting func (h MultiEpochHooks) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { for i := range h { - panicCatchingEpochHook(ctx, h[i].AfterEpochEnd, epochIdentifier, epochNumber) + panicCatchingEpochHook(ctx, h[i].BeforeEpochStart, epochIdentifier, epochNumber) } return nil } diff --git a/x/interchainquery/keeper/abci.go b/x/interchainquery/keeper/abci.go index cd5db5a5f..7010b71bd 100644 --- a/x/interchainquery/keeper/abci.go +++ b/x/interchainquery/keeper/abci.go @@ -27,7 +27,7 @@ func (k Keeper) EndBlocker(ctx sdk.Context) { // return false // } if queryInfo.LastEmission.IsNil() || queryInfo.LastEmission.IsZero() || queryInfo.LastEmission.Add(queryInfo.Period).Equal(sdk.NewInt(ctx.BlockHeight())) { - k.Logger(ctx).Info("Interchainquery event emitted", "id", queryInfo.Id) + k.Logger(ctx).Debug("Interchainquery event emitted", "id", queryInfo.Id) event := sdk.NewEvent( sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), diff --git a/x/interchainquery/keeper/msg_server.go b/x/interchainquery/keeper/msg_server.go index e9e04321a..e0b97120a 100644 --- a/x/interchainquery/keeper/msg_server.go +++ b/x/interchainquery/keeper/msg_server.go @@ -29,7 +29,7 @@ func (k msgServer) SubmitQueryResponse(goCtx context.Context, msg *types.MsgSubm q, found := k.GetQuery(ctx, msg.QueryId) if !found { - k.Logger(ctx).Info("query not found", "QueryID", msg.QueryId) + k.Logger(ctx).Debug("query not found", "QueryID", msg.QueryId) return &types.MsgSubmitQueryResponseResponse{}, nil } @@ -37,7 +37,7 @@ func (k msgServer) SubmitQueryResponse(goCtx context.Context, msg *types.MsgSubm // check if query was previously processed // - indicated by query.LastHeight matching current Block Height; if q.LastHeight.Int64() == ctx.BlockHeader().Height { - k.Logger(ctx).Info("ignoring duplicate query", "id", q.Id, "type", q.QueryType) + k.Logger(ctx).Debug("ignoring duplicate query", "id", q.Id, "type", q.QueryType) // technically this is an error, but will cause the entire tx to fail // if we have one 'bad' message, so we can just no-op here. return &types.MsgSubmitQueryResponseResponse{}, nil diff --git a/x/interchainstaking/keeper/callbacks.go b/x/interchainstaking/keeper/callbacks.go index 4e960bd3a..524bbe1a8 100644 --- a/x/interchainstaking/keeper/callbacks.go +++ b/x/interchainstaking/keeper/callbacks.go @@ -96,7 +96,7 @@ func RewardsCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Quer return fmt.Errorf("no registered zone for chain id: %s", query.GetChainId()) } - k.Logger(ctx).Info("rewards callback", "zone", query.ChainId) + k.Logger(ctx).Debug("rewards callback", "zone", query.ChainId) // unmarshal request payload rewardsQuery := distrtypes.QueryDelegationTotalRewardsRequest{} @@ -112,7 +112,7 @@ func RewardsCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Quer // (initially incremented in AfterEpochEnd) zone.WithdrawalWaitgroup-- - k.Logger(ctx).Info("QueryDelegationRewards callback", "wg", zone.WithdrawalWaitgroup, "delegatorAddress", rewardsQuery.DelegatorAddress, "zone", query.ChainId) + k.Logger(ctx).Debug("QueryDelegationRewards callback", "wg", zone.WithdrawalWaitgroup, "delegatorAddress", rewardsQuery.DelegatorAddress, "zone", query.ChainId) return k.WithdrawDelegationRewardsForResponse(ctx, &zone, rewardsQuery.DelegatorAddress, args) } @@ -132,7 +132,7 @@ func DelegationsCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes. return err } - k.Logger(ctx).Info("Delegations callback triggered", "chain", zone.ChainId) + k.Logger(ctx).Debug("Delegations callback triggered", "chain", zone.ChainId) return k.UpdateDelegationRecordsForAddress(ctx, zone, delegationQuery.DelegatorAddr, args) } @@ -150,7 +150,7 @@ func DelegationCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Q return err } - k.Logger(ctx).Info("Delegation callback", "delegation", delegation, "chain", zone.ChainId) + k.Logger(ctx).Debug("Delegation callback", "delegation", delegation, "chain", zone.ChainId) if delegation.Shares.IsNil() || delegation.Shares.IsZero() { // delegation never gets removed, even with zero shares. @@ -215,7 +215,7 @@ func DepositIntervalCallback(k Keeper, ctx sdk.Context, args []byte, query icqty return fmt.Errorf("chain id %s does not current allow deposits", query.GetChainId()) } - k.Logger(ctx).Info("Deposit interval callback", "zone", zone.ChainId) + k.Logger(ctx).Debug("Deposit interval callback", "zone", zone.ChainId) txs := tx.GetTxsEventResponse{} @@ -233,9 +233,10 @@ func DepositIntervalCallback(k Keeper, ctx sdk.Context, args []byte, query icqty hashBytes := k.cdc.MustMarshal(&req) _, found = k.GetReceipt(ctx, GetReceiptKey(zone.ChainId, txn.TxHash)) if found { - k.Logger(ctx).Info("Found previously handled tx. Ignoring.", "txhash", txn.TxHash) + k.Logger(ctx).Debug("Found previously handled tx. Ignoring.", "txhash", txn.TxHash) continue } + k.Logger(ctx).Info("Found previously unhandled tx. Processing.", "txhash", txn.TxHash) k.ICQKeeper.MakeRequest(ctx, query.ConnectionId, query.ChainId, "tendermint.Tx", hashBytes, sdk.NewInt(-1), types.ModuleName, "deposittx", 0) } return nil @@ -355,7 +356,7 @@ func DepositTx(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) err return fmt.Errorf("chain id %s does not current allow deposits", query.GetChainId()) } - k.Logger(ctx).Info("DepositTx callback", "zone", zone.ChainId) + k.Logger(ctx).Debug("DepositTx callback", "zone", zone.ChainId) res := icqtypes.GetTxWithProofResponse{} if len(args) == 0 { @@ -368,7 +369,7 @@ func DepositTx(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) err _, found = k.GetReceipt(ctx, GetReceiptKey(zone.ChainId, res.GetTxResponse().TxHash)) if found { - k.Logger(ctx).Info("Found previously handled tx. Ignoring.", "txhash", res.GetTxResponse().TxHash) + k.Logger(ctx).Debug("Found previously handled tx. Ignoring.", "txhash", res.GetTxResponse().TxHash) return nil } @@ -400,7 +401,6 @@ func DepositTx(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) err err = checkValidity(tmclientState, tmconsensusState, res.GetHeader(), ctx.BlockHeader().Time) if err != nil { - k.Logger(ctx).Info("unable to validate header", "header", res.Header) return fmt.Errorf("unable to validate header; %w", err) } @@ -475,7 +475,7 @@ func AllBalancesCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes. return fmt.Errorf("no registered zone for chain id: %s", query.GetChainId()) } - k.Logger(ctx).Info("AllBalances callback", "chain", zone.ChainId) + k.Logger(ctx).Debug("AllBalances callback", "chain", zone.ChainId) switch { case zone.DepositAddress != nil && balanceQuery.Address == zone.DepositAddress.Address: diff --git a/x/interchainstaking/keeper/delegation.go b/x/interchainstaking/keeper/delegation.go index 5d80d1be2..b708d5e2c 100644 --- a/x/interchainstaking/keeper/delegation.go +++ b/x/interchainstaking/keeper/delegation.go @@ -224,19 +224,20 @@ func (k *Keeper) PrepareDelegationMessagesForShares(ctx sdk.Context, zone *types } func (k Keeper) DeterminePlanForDelegation(ctx sdk.Context, zone *types.Zone, amount sdk.Coins) map[string]sdkmath.Int { - currentAllocations, currentSum := k.GetDelegationMap(ctx, zone) + currentAllocations, currentSum, _ := k.GetDelegationMap(ctx, zone) targetAllocations := zone.GetAggregateIntentOrDefault() allocations := DetermineAllocationsForDelegation(currentAllocations, currentSum, targetAllocations, amount) return allocations } // CalculateDeltas determines, for the current delegations, in delta between actual allocations and the target intent. +// Positive delta represents current allocation is below target, and vice versa. func CalculateDeltas(currentAllocations map[string]sdkmath.Int, currentSum sdkmath.Int, targetAllocations types.ValidatorIntents) types.ValidatorIntents { deltas := make(types.ValidatorIntents, 0) targetValopers := func(in types.ValidatorIntents) []string { out := make([]string, 0, len(in)) - for _, i := range in.Sort() { + for _, i := range in { out = append(out, i.ValoperAddress) } return out @@ -287,22 +288,24 @@ func minDeltas(deltas types.ValidatorIntents) sdkmath.Int { return minValue } +// maxDeltas returns the greatest value in a slice of Deltas. +func maxDeltas(deltas types.ValidatorIntents) sdkmath.Int { + maxValue := sdk.NewInt(math.MinInt64) + for _, intent := range deltas { + if maxValue.LT(intent.Weight.TruncateInt()) { + maxValue = intent.Weight.TruncateInt() + } + } + + return maxValue +} + func DetermineAllocationsForDelegation(currentAllocations map[string]sdkmath.Int, currentSum sdkmath.Int, targetAllocations types.ValidatorIntents, amount sdk.Coins) map[string]sdkmath.Int { input := amount[0].Amount deltas := CalculateDeltas(currentAllocations, currentSum, targetAllocations) minValue := minDeltas(deltas) sum := sdk.ZeroInt() - // // sort keys by relative value of delta - // sort.SliceStable(deltas, func(i, j int) bool { - // return deltas[i].ValoperAddress > deltas[j].ValoperAddress - // }) - - // // sort keys by relative value of delta - // sort.SliceStable(deltas, func(i, j int) bool { - // return deltas[i].Weight.GT(deltas[j].Weight) - // }) - // raise all deltas such that the minimum value is zero. for idx := range deltas { deltas[idx].Weight = deltas[idx].Weight.Add(sdk.NewDecFromInt(minValue.Abs())) @@ -380,22 +383,25 @@ func (k *Keeper) WithdrawDelegationRewardsForResponse(ctx sdk.Context, zone *typ return k.SubmitTx(ctx, msgs, zone.DelegationAddress, "") } -func (k *Keeper) GetDelegationMap(ctx sdk.Context, zone *types.Zone) (map[string]sdkmath.Int, sdkmath.Int) { +func (k *Keeper) GetDelegationMap(ctx sdk.Context, zone *types.Zone) (map[string]sdkmath.Int, sdkmath.Int, map[string]bool) { out := make(map[string]sdkmath.Int) + locked := make(map[string]bool) sum := sdk.ZeroInt() k.IterateAllDelegations(ctx, zone, func(delegation types.Delegation) bool { existing, found := out[delegation.ValidatorAddress] if !found { out[delegation.ValidatorAddress] = delegation.Amount.Amount + locked[delegation.ValidatorAddress] = delegation.RedelegationEnd != 0 && delegation.RedelegationEnd >= ctx.BlockTime().Unix() } else { out[delegation.ValidatorAddress] = existing.Add(delegation.Amount.Amount) + locked[delegation.ValidatorAddress] = locked[delegation.ValidatorAddress] || (delegation.RedelegationEnd != 0 && delegation.RedelegationEnd >= ctx.BlockTime().Unix()) } sum = sum.Add(delegation.Amount.Amount) return false }) - return out, sum + return out, sum, locked } func (k *Keeper) MakePerformanceDelegation(ctx sdk.Context, zone *types.Zone, validator string) error { diff --git a/x/interchainstaking/keeper/delegation_test.go b/x/interchainstaking/keeper/delegation_test.go index b6f6817ca..93c5cae46 100644 --- a/x/interchainstaking/keeper/delegation_test.go +++ b/x/interchainstaking/keeper/delegation_test.go @@ -11,7 +11,6 @@ import ( "github.com/ingenuity-build/quicksilver/utils" icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" - icstypes "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" "github.com/stretchr/testify/require" ) @@ -55,7 +54,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegationStore() { icsKeeper.SetDelegation( ctx, &zone, - icstypes.NewDelegation( + types.NewDelegation( zone.DelegationAddress.Address, zoneValidatorAddresses[0], sdk.NewCoin(zone.BaseDenom, sdk.NewInt(3000000)), @@ -64,7 +63,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegationStore() { icsKeeper.SetDelegation( ctx, &zone, - icstypes.NewDelegation( + types.NewDelegation( zone.DelegationAddress.Address, zoneValidatorAddresses[1], sdk.NewCoin(zone.BaseDenom, sdk.NewInt(17000000)), @@ -73,7 +72,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegationStore() { icsKeeper.SetDelegation( ctx, &zone, - icstypes.NewDelegation( + types.NewDelegation( zone.DelegationAddress.Address, zoneValidatorAddresses[2], sdk.NewCoin(zone.BaseDenom, sdk.NewInt(20000000)), @@ -109,7 +108,7 @@ func TestDetermineAllocationsForDelegation(t *testing.T) { tc := []struct { current map[string]cosmosmath.Int - target icstypes.ValidatorIntents + target types.ValidatorIntents inAmount sdk.Coins expected map[string]cosmosmath.Int dust cosmosmath.Int @@ -120,7 +119,7 @@ func TestDetermineAllocationsForDelegation(t *testing.T) { val2.String(): sdk.NewInt(650000), val3.String(): sdk.NewInt(75000), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(30, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(63, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(7, 2)}, @@ -139,7 +138,7 @@ func TestDetermineAllocationsForDelegation(t *testing.T) { val3.String(): sdk.NewInt(20), val4.String(): sdk.NewInt(4), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(50, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(25, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(15, 2)}, @@ -160,7 +159,7 @@ func TestDetermineAllocationsForDelegation(t *testing.T) { val3.String(): sdk.NewInt(20), val4.String(): sdk.NewInt(4), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(50, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(25, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(15, 2)}, @@ -194,7 +193,7 @@ func TestDetermineAllocationsForDelegation(t *testing.T) { } type delegationUpdate struct { - delegation icstypes.Delegation + delegation types.Delegation absolute bool } @@ -210,83 +209,83 @@ func (s *KeeperTestSuite) TestUpdateDelegation() { tests := []struct { name string - delegation *icstypes.Delegation + delegation *types.Delegation updates []delegationUpdate - expected icstypes.Delegation + expected types.Delegation }{ { "single update, relative increase +3000", - &icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val1.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + &types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val1.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, []delegationUpdate{ { - delegation: icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val1.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + delegation: types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val1.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, absolute: false, }, }, - icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val1.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(6000))}, + types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val1.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(6000))}, }, { "single update, relative increase +3000", - &icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val2.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + &types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val2.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, []delegationUpdate{ { - delegation: icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val2.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + delegation: types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val2.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, absolute: true, }, }, - icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val2.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val2.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, }, { "multi update, relative increase +3000, +2000", - &icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val3.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + &types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val3.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, []delegationUpdate{ { - delegation: icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val3.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + delegation: types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val3.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, absolute: false, }, { - delegation: icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val3.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(2000))}, + delegation: types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val3.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(2000))}, absolute: false, }, }, - icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val3.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(8000))}, + types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val3.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(8000))}, }, { "multi update, relative +3000, absolute +2000", - &icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val4.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + &types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val4.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, []delegationUpdate{ { - delegation: icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val4.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, + delegation: types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val4.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(3000))}, absolute: false, }, { - delegation: icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val4.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(2000))}, + delegation: types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val4.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(2000))}, absolute: true, }, }, - icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val4.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(2000))}, + types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val4.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(2000))}, }, { "new delegation, relative increase +10000", nil, []delegationUpdate{ { - delegation: icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val5.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(10000))}, + delegation: types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val5.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(10000))}, absolute: false, }, }, - icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val5.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(10000))}, + types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val5.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(10000))}, }, { "new delegation, absolute increase +15000", nil, []delegationUpdate{ { - delegation: icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val6.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(15000))}, + delegation: types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val6.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(15000))}, absolute: true, }, }, - icstypes.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val6.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(15000))}, + types.Delegation{DelegationAddress: del1.String(), ValidatorAddress: val6.String(), Amount: sdk.NewCoin("denom", sdk.NewInt(15000))}, }, } @@ -326,14 +325,14 @@ func TestCalculateDeltas(t *testing.T) { val3 := utils.GenerateValAddressForTest() val4 := utils.GenerateValAddressForTest() - zone := icstypes.Zone{Validators: []*icstypes.Validator{ + zone := types.Zone{Validators: []*types.Validator{ {ValoperAddress: val1.String(), CommissionRate: sdk.NewDecWithPrec(30, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val2.String(), CommissionRate: sdk.NewDecWithPrec(25, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val3.String(), CommissionRate: sdk.NewDecWithPrec(10, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val4.String(), CommissionRate: sdk.NewDecWithPrec(12, 2), Status: stakingtypes.BondStatusBonded}, }} - zone2 := icstypes.Zone{Validators: []*icstypes.Validator{ + zone2 := types.Zone{Validators: []*types.Validator{ {ValoperAddress: val1.String(), CommissionRate: sdk.NewDecWithPrec(30, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val2.String(), CommissionRate: sdk.NewDecWithPrec(25, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val3.String(), CommissionRate: sdk.NewDecWithPrec(10, 2), Status: stakingtypes.BondStatusBonded}, @@ -342,8 +341,8 @@ func TestCalculateDeltas(t *testing.T) { tc := []struct { current map[string]cosmosmath.Int - target icstypes.ValidatorIntents - expected icstypes.ValidatorIntents + target types.ValidatorIntents + expected types.ValidatorIntents }{ { current: map[string]cosmosmath.Int{ @@ -351,12 +350,12 @@ func TestCalculateDeltas(t *testing.T) { val2.String(): sdk.NewInt(650000), val3.String(): sdk.NewInt(75000), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(30, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(63, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(7, 2)}, }, - expected: icstypes.ValidatorIntents{ + expected: types.ValidatorIntents{ {ValoperAddress: val2.String(), Weight: sdk.NewDec(27250)}, {ValoperAddress: val3.String(), Weight: sdk.NewDec(250)}, {ValoperAddress: val1.String(), Weight: sdk.NewDec(-27500)}, @@ -369,13 +368,13 @@ func TestCalculateDeltas(t *testing.T) { val3.String(): sdk.NewInt(14), val4.String(): sdk.NewInt(7), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(50, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(28, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(12, 2)}, {ValoperAddress: val4.String(), Weight: sdk.NewDecWithPrec(10, 2)}, }, - expected: icstypes.ValidatorIntents{ + expected: types.ValidatorIntents{ {ValoperAddress: val4.String(), Weight: sdk.NewDec(3)}, {ValoperAddress: val2.String(), Weight: sdk.NewDec(2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDec(-2)}, @@ -389,13 +388,13 @@ func TestCalculateDeltas(t *testing.T) { val3.String(): sdk.NewInt(60), val4.String(): sdk.NewInt(180), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(50, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(25, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(15, 2)}, {ValoperAddress: val4.String(), Weight: sdk.NewDecWithPrec(10, 2)}, }, - expected: icstypes.ValidatorIntents{ + expected: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDec(120)}, {ValoperAddress: val2.String(), Weight: sdk.NewDec(45)}, {ValoperAddress: val3.String(), Weight: sdk.NewDec(-15)}, @@ -411,7 +410,7 @@ func TestCalculateDeltas(t *testing.T) { val4.String(): sdk.NewInt(60), }, target: zone.GetAggregateIntentOrDefault(), - expected: icstypes.ValidatorIntents{ + expected: types.ValidatorIntents{ {ValoperAddress: val2.String(), Weight: sdk.NewDec(20)}, {ValoperAddress: val1.String(), Weight: sdk.NewDec(10)}, {ValoperAddress: val3.String(), Weight: sdk.NewDec(5)}, @@ -427,7 +426,7 @@ func TestCalculateDeltas(t *testing.T) { val4.String(): sdk.NewInt(60), }, target: zone2.GetAggregateIntentOrDefault(), - expected: icstypes.ValidatorIntents{ + expected: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDec(25)}, {ValoperAddress: val2.String(), Weight: sdk.NewDec(21)}, {ValoperAddress: val3.String(), Weight: sdk.NewDec(13)}, @@ -459,14 +458,14 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { val3 := utils.GenerateValAddressForTest() val4 := utils.GenerateValAddressForTest() - zone := icstypes.Zone{Validators: []*icstypes.Validator{ + zone := types.Zone{Validators: []*types.Validator{ {ValoperAddress: val1.String(), CommissionRate: sdk.NewDecWithPrec(30, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val2.String(), CommissionRate: sdk.NewDecWithPrec(25, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val3.String(), CommissionRate: sdk.NewDecWithPrec(10, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val4.String(), CommissionRate: sdk.NewDecWithPrec(12, 2), Status: stakingtypes.BondStatusBonded}, }} - zone2 := icstypes.Zone{Validators: []*icstypes.Validator{ + zone2 := types.Zone{Validators: []*types.Validator{ {ValoperAddress: val1.String(), CommissionRate: sdk.NewDecWithPrec(30, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val2.String(), CommissionRate: sdk.NewDecWithPrec(25, 2), Status: stakingtypes.BondStatusBonded}, {ValoperAddress: val3.String(), CommissionRate: sdk.NewDecWithPrec(10, 2), Status: stakingtypes.BondStatusBonded}, @@ -476,7 +475,8 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { tc := []struct { name string current map[string]cosmosmath.Int - target icstypes.ValidatorIntents + locked map[string]bool + target types.ValidatorIntents expected []icskeeper.RebalanceTarget dust cosmosmath.Int redelegations []types.RedelegationRecord @@ -488,7 +488,7 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { val2.String(): sdk.NewInt(650000), val3.String(): sdk.NewInt(75000), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(30, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(63, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(7, 2)}, @@ -506,7 +506,7 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { val3.String(): sdk.NewInt(14), val4.String(): sdk.NewInt(5), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(50, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(28, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(12, 2)}, @@ -526,7 +526,7 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { val3.String(): sdk.NewInt(60), val4.String(): sdk.NewInt(180), }, - target: icstypes.ValidatorIntents{ + target: types.ValidatorIntents{ {ValoperAddress: val1.String(), Weight: sdk.NewDecWithPrec(50, 2)}, {ValoperAddress: val2.String(), Weight: sdk.NewDecWithPrec(25, 2)}, {ValoperAddress: val3.String(), Weight: sdk.NewDecWithPrec(15, 2)}, @@ -633,7 +633,7 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { }, }, { - name: "case 8 - includes redelegation, truncated delegation overflow", + name: "case 9 - includes redelegation, truncated delegation overflow", current: map[string]cosmosmath.Int{ val1.String(): sdk.NewInt(2), val2.String(): sdk.NewInt(8), @@ -644,7 +644,7 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { expected: []icskeeper.RebalanceTarget{ {Amount: cosmosmath.NewInt(10), Source: val4.String(), Target: val1.String()}, // below values _would_ applied, if we weren't limited by a max of total/7 - //{Amount: cosmosmath.NewInt(4), Source: val3.String(), Target: val1.String()}, // joe: I would expect this to be included... + //{Amount: cosmosmath.NewInt(4), Source: val3.String(), Target: val1.String()}, // joe: I would expect this to be included... //{Amount: cosmosmath.NewInt(4), Source: val4.String(), Target: val3.String()}, }, redelegations: []types.RedelegationRecord{ @@ -652,7 +652,7 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { }, }, { - name: "case 9 - includes redelegation, zero delegation", + name: "case 10 - includes redelegation, zero delegation", current: map[string]cosmosmath.Int{ val1.String(): sdk.NewInt(8), val2.String(): sdk.NewInt(12), @@ -677,7 +677,7 @@ func TestDetermineAllocationsForRebalance(t *testing.T) { for _, amount := range val.current { sum = sum.Add(amount) } - allocations := icskeeper.DetermineAllocationsForRebalancing(val.current, sum, val.target, val.redelegations, nil) + allocations := icskeeper.DetermineAllocationsForRebalancing(val.current, val.locked, sum, val.target, val.redelegations, nil) require.Equal(t, len(val.expected), len(allocations), fmt.Sprintf("expected %d RebalanceTargets in '%s', got %d", len(val.expected), val.name, len(allocations))) for idx, rebalance := range val.expected { require.Equal(t, rebalance, allocations[idx], fmt.Sprintf("%s, idx %d: Expected %v, got %v", val.name, idx, rebalance, allocations[idx])) @@ -702,7 +702,7 @@ func (s *KeeperTestSuite) TestStoreGetDeleteDelegation() { _, found = app.InterchainstakingKeeper.GetDelegation(ctx, &zone, delegator.String(), validator.String()) s.Require().False(found) - newDelegation := icstypes.NewDelegation(delegator.String(), validator.String(), sdk.NewCoin("uatom", sdk.NewInt(5000))) + newDelegation := types.NewDelegation(delegator.String(), validator.String(), sdk.NewCoin("uatom", sdk.NewInt(5000))) app.InterchainstakingKeeper.SetDelegation(ctx, &zone, newDelegation) fetchedDelegation, found := app.InterchainstakingKeeper.GetDelegation(ctx, &zone, delegator.String(), validator.String()) diff --git a/x/interchainstaking/keeper/grpc_query_test.go b/x/interchainstaking/keeper/grpc_query_test.go index cfc3dffe4..75dfc1602 100644 --- a/x/interchainstaking/keeper/grpc_query_test.go +++ b/x/interchainstaking/keeper/grpc_query_test.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" - icstypes "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) func (suite *KeeperTestSuite) TestKeeper_ZoneInfos() { @@ -18,14 +17,14 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneInfos() { tests := []struct { name string malleate func() - req *icstypes.QueryZonesInfoRequest + req *types.QueryZonesInfoRequest wantErr bool expectLength int }{ { "ZoneInfos_No_State", func() {}, - &icstypes.QueryZonesInfoRequest{}, + &types.QueryZonesInfoRequest{}, false, 0, }, @@ -42,7 +41,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneInfos() { // setup zones suite.setupTestZones() }, - &icstypes.QueryZonesInfoRequest{}, + &types.QueryZonesInfoRequest{}, false, 1, }, @@ -80,13 +79,13 @@ func (suite *KeeperTestSuite) TestKeeper_DepositAccount() { tests := []struct { name string malleate func() - req *icstypes.QueryDepositAccountForChainRequest + req *types.QueryDepositAccountForChainRequest wantErr bool }{ { "DepositAccount_No_State", func() {}, - &icstypes.QueryDepositAccountForChainRequest{}, + &types.QueryDepositAccountForChainRequest{}, true, }, { @@ -101,7 +100,7 @@ func (suite *KeeperTestSuite) TestKeeper_DepositAccount() { // setup zones suite.setupTestZones() }, - &icstypes.QueryDepositAccountForChainRequest{}, + &types.QueryDepositAccountForChainRequest{}, true, }, { @@ -109,7 +108,7 @@ func (suite *KeeperTestSuite) TestKeeper_DepositAccount() { func() { // use state set from previous tests }, - &icstypes.QueryDepositAccountForChainRequest{ + &types.QueryDepositAccountForChainRequest{ ChainId: suite.chainB.ChainID, }, false, @@ -147,7 +146,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegatorIntent() { tests := []struct { name string malleate func() - req *icstypes.QueryDelegatorIntentRequest + req *types.QueryDelegatorIntentRequest wantErr bool expectLength int }{ @@ -164,7 +163,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegatorIntent() { // setup zones suite.setupTestZones() }, - &icstypes.QueryDelegatorIntentRequest{ + &types.QueryDelegatorIntentRequest{ ChainId: "boguschain", DelegatorAddress: testAddress, }, @@ -174,7 +173,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegatorIntent() { { "DelegatorIntent_No_Zone_Intents", func() {}, - &icstypes.QueryDelegatorIntentRequest{ + &types.QueryDelegatorIntentRequest{ ChainId: suite.chainB.ChainID, DelegatorAddress: testAddress, }, @@ -184,7 +183,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegatorIntent() { { "DelegatorIntent_No_Delegator_Intents", func() {}, - &icstypes.QueryDelegatorIntentRequest{ + &types.QueryDelegatorIntentRequest{ ChainId: suite.chainB.ChainID, DelegatorAddress: testAddress, }, @@ -200,11 +199,11 @@ func (suite *KeeperTestSuite) TestKeeper_DelegatorIntent() { suite.giveFunds(ctx, zone.LocalDenom, 5000000, testAddress) // set intents // TODO: set standardized intents for keeper_test package - intents := []icstypes.DelegatorIntent{ + intents := []types.DelegatorIntent{ { Delegator: testAddress, - Intents: icstypes.ValidatorIntents{ - &icstypes.ValidatorIntent{ + Intents: types.ValidatorIntents{ + &types.ValidatorIntent{ ValoperAddress: zone.GetValidatorsAddressesAsSlice()[0], Weight: sdk.OneDec(), }, @@ -215,7 +214,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegatorIntent() { icsKeeper.SetIntent(ctx, zone, intent, false) } }, - &icstypes.QueryDelegatorIntentRequest{ + &types.QueryDelegatorIntentRequest{ ChainId: suite.chainB.ChainID, DelegatorAddress: testAddress, }, @@ -256,7 +255,7 @@ func (suite *KeeperTestSuite) TestKeeper_Delegations() { tests := []struct { name string malleate func() - req *icstypes.QueryDelegationsRequest + req *types.QueryDelegationsRequest wantErr bool expectLength int }{ @@ -273,7 +272,7 @@ func (suite *KeeperTestSuite) TestKeeper_Delegations() { // setup zones suite.setupTestZones() }, - &icstypes.QueryDelegationsRequest{ + &types.QueryDelegationsRequest{ ChainId: "boguschain", }, true, @@ -282,7 +281,7 @@ func (suite *KeeperTestSuite) TestKeeper_Delegations() { { "Delegations_No_Zone_Delegations", func() {}, - &icstypes.QueryDelegationsRequest{ + &types.QueryDelegationsRequest{ ChainId: suite.chainB.ChainID, }, false, @@ -296,14 +295,14 @@ func (suite *KeeperTestSuite) TestKeeper_Delegations() { // set delegation // TODO: set standardized delegatyions for keeper_test package - delegation := icstypes.Delegation{ + delegation := types.Delegation{ DelegationAddress: testAddress, ValidatorAddress: zone.GetValidatorsAddressesAsSlice()[0], Amount: sdk.NewCoin("denom", sdk.NewInt(15000)), } icsKeeper.SetDelegation(ctx, &zone, delegation) }, - &icstypes.QueryDelegationsRequest{ + &types.QueryDelegationsRequest{ ChainId: suite.chainB.ChainID, }, false, @@ -343,7 +342,7 @@ func (suite *KeeperTestSuite) TestKeeper_Receipts() { tests := []struct { name string malleate func() - req *icstypes.QueryReceiptsRequest + req *types.QueryReceiptsRequest wantErr bool expectLength int }{ @@ -360,7 +359,7 @@ func (suite *KeeperTestSuite) TestKeeper_Receipts() { // setup zones suite.setupTestZones() }, - &icstypes.QueryReceiptsRequest{ + &types.QueryReceiptsRequest{ ChainId: "boguschain", }, true, @@ -369,7 +368,7 @@ func (suite *KeeperTestSuite) TestKeeper_Receipts() { { "Receipts_No_Zone_Receipts", func() {}, - &icstypes.QueryReceiptsRequest{ + &types.QueryReceiptsRequest{ ChainId: suite.chainB.ChainID, }, false, @@ -393,7 +392,7 @@ func (suite *KeeperTestSuite) TestKeeper_Receipts() { ) icsKeeper.SetReceipt(ctx, *receipt) }, - &icstypes.QueryReceiptsRequest{ + &types.QueryReceiptsRequest{ ChainId: suite.chainB.ChainID, }, false, @@ -433,7 +432,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneWithdrawalRecords() { tests := []struct { name string malleate func() - req *icstypes.QueryWithdrawalRecordsRequest + req *types.QueryWithdrawalRecordsRequest wantErr bool expectLength int }{ @@ -450,7 +449,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneWithdrawalRecords() { // setup zones suite.setupTestZones() }, - &icstypes.QueryWithdrawalRecordsRequest{ + &types.QueryWithdrawalRecordsRequest{ ChainId: "boguschain", }, true, @@ -459,7 +458,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneWithdrawalRecords() { { "ZoneWithdrawalRecords_No_Zone_Records", func() {}, - &icstypes.QueryWithdrawalRecordsRequest{ + &types.QueryWithdrawalRecordsRequest{ ChainId: suite.chainB.ChainID, DelegatorAddress: "quick16pxh2v4hr28h2gkntgfk8qgh47pfmjfhzgeure", }, @@ -472,7 +471,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneWithdrawalRecords() { zone, found := icsKeeper.GetZone(ctx, suite.chainB.ChainID) suite.Require().True(found) - distribution := []*icstypes.Distribution{ + distribution := []*types.Distribution{ { Valoper: zone.GetValidatorsAddressesAsSlice()[0], Amount: 10000000, @@ -497,7 +496,7 @@ func (suite *KeeperTestSuite) TestKeeper_ZoneWithdrawalRecords() { time.Time{}, ) }, - &icstypes.QueryWithdrawalRecordsRequest{ + &types.QueryWithdrawalRecordsRequest{ ChainId: suite.chainB.ChainID, DelegatorAddress: "quick16pxh2v4hr28h2gkntgfk8qgh47pfmjfhzgeure", }, @@ -538,7 +537,7 @@ func (suite *KeeperTestSuite) TestKeeper_WithdrawalRecords() { tests := []struct { name string malleate func() - req *icstypes.QueryWithdrawalRecordsRequest + req *types.QueryWithdrawalRecordsRequest wantErr bool expectLength int }{ @@ -555,7 +554,7 @@ func (suite *KeeperTestSuite) TestKeeper_WithdrawalRecords() { // setup zones suite.setupTestZones() }, - &icstypes.QueryWithdrawalRecordsRequest{}, + &types.QueryWithdrawalRecordsRequest{}, false, 0, }, @@ -565,7 +564,7 @@ func (suite *KeeperTestSuite) TestKeeper_WithdrawalRecords() { zone, found := icsKeeper.GetZone(ctx, suite.chainB.ChainID) suite.Require().True(found) - distribution := []*icstypes.Distribution{ + distribution := []*types.Distribution{ { Valoper: zone.GetValidatorsAddressesAsSlice()[0], Amount: 10000000, @@ -590,7 +589,7 @@ func (suite *KeeperTestSuite) TestKeeper_WithdrawalRecords() { time.Time{}, ) }, - &icstypes.QueryWithdrawalRecordsRequest{}, + &types.QueryWithdrawalRecordsRequest{}, false, 1, }, @@ -628,7 +627,7 @@ func (suite *KeeperTestSuite) TestKeeper_UnbondingRecords() { tests := []struct { name string malleate func() - req *icstypes.QueryUnbondingRecordsRequest + req *types.QueryUnbondingRecordsRequest wantErr bool expectLength int }{ @@ -645,7 +644,7 @@ func (suite *KeeperTestSuite) TestKeeper_UnbondingRecords() { // setup zones suite.setupTestZones() }, - &icstypes.QueryUnbondingRecordsRequest{}, + &types.QueryUnbondingRecordsRequest{}, false, 0, }, @@ -657,7 +656,7 @@ func (suite *KeeperTestSuite) TestKeeper_UnbondingRecords() { icsKeeper.SetUnbondingRecord( ctx, - icstypes.UnbondingRecord{ + types.UnbondingRecord{ ChainId: zone.ChainId, EpochNumber: 1, Validator: zone.GetValidatorsAddressesAsSlice()[0], @@ -665,7 +664,7 @@ func (suite *KeeperTestSuite) TestKeeper_UnbondingRecords() { }, ) }, - &icstypes.QueryUnbondingRecordsRequest{}, + &types.QueryUnbondingRecordsRequest{}, false, 1, }, @@ -703,7 +702,7 @@ func (suite *KeeperTestSuite) TestKeeper_RedelegationRecords() { tests := []struct { name string malleate func() - req *icstypes.QueryRedelegationRecordsRequest + req *types.QueryRedelegationRecordsRequest wantErr bool expectLength int }{ @@ -720,7 +719,7 @@ func (suite *KeeperTestSuite) TestKeeper_RedelegationRecords() { // setup zones suite.setupTestZones() }, - &icstypes.QueryRedelegationRecordsRequest{}, + &types.QueryRedelegationRecordsRequest{}, false, 0, }, @@ -740,7 +739,7 @@ func (suite *KeeperTestSuite) TestKeeper_RedelegationRecords() { Amount: 10000000, }) }, - &icstypes.QueryRedelegationRecordsRequest{}, + &types.QueryRedelegationRecordsRequest{}, false, 1, }, diff --git a/x/interchainstaking/keeper/ibc_packet_handlers.go b/x/interchainstaking/keeper/ibc_packet_handlers.go index 5aa0a7c8c..bce38f7ec 100644 --- a/x/interchainstaking/keeper/ibc_packet_handlers.go +++ b/x/interchainstaking/keeper/ibc_packet_handlers.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "reflect" - "sort" "strconv" "strings" "time" @@ -13,6 +12,8 @@ import ( "cosmossdk.io/math" "github.com/golang/protobuf/proto" //nolint:staticcheck + "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/bech32" icatypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types" @@ -32,11 +33,44 @@ import ( "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) -const transferPort = "transfer" +const ( + transferPort = "transfer" + withdrawal = "withdrawal" +) + +type TypedMsg struct { + Msg sdk.Msg + Type string +} + +func DeserializeCosmosTxTyped(cdc codec.BinaryCodec, data []byte) ([]TypedMsg, error) { + var cosmosTx icatypes.CosmosTx + if err := cdc.Unmarshal(data, &cosmosTx); err != nil { + return nil, err + } + + msgs := make([]TypedMsg, len(cosmosTx.Messages)) + + for i, any := range cosmosTx.Messages { + var msg sdk.Msg + + err := cdc.UnpackAny(any, &msg) + if err != nil { + return nil, err + } + + msgs[i] = TypedMsg{Msg: msg, Type: any.TypeUrl} + + } + + return msgs, nil +} func (k *Keeper) HandleAcknowledgement(ctx sdk.Context, packet channeltypes.Packet, acknowledgement []byte) error { ack := channeltypes.Acknowledgement_Result{} err := json.Unmarshal(acknowledgement, &ack) + txMsgData := &sdk.TxMsgData{} + var success bool if err != nil { k.Logger(ctx).Error("unable to unmarshal acknowledgement", "error", err, "data", acknowledgement) return err @@ -51,15 +85,16 @@ func (k *Keeper) HandleAcknowledgement(ctx sdk.Context, packet channeltypes.Pack k.Logger(ctx).Error("received an acknowledgement error", "error", err, "remote_err", ackErr, "data", acknowledgement) defer telemetry.IncrCounter(1, types.ModuleName, "ica_acknowledgement_errors") - return nil - // return errors.New("received an acknowledgement error; unable to process") // this just causes the same errAck to be submitted repeatedly. - } - defer telemetry.IncrCounter(1, types.ModuleName, "ica_acknowledgement_success") - txMsgData := &sdk.TxMsgData{} - err = proto.Unmarshal(ack.Result, txMsgData) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal acknowledgement", "error", err, "ack", ack.Result) - return err + success = false + } else { + defer telemetry.IncrCounter(1, types.ModuleName, "ica_acknowledgement_success") + + err = proto.Unmarshal(ack.Result, txMsgData) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal acknowledgement", "error", err, "ack", ack.Result) + return err + } + success = true } var packetData icatypes.InterchainAccountPacketData @@ -72,28 +107,55 @@ func (k *Keeper) HandleAcknowledgement(ctx sdk.Context, packet channeltypes.Pack return errors.New("unable to unmarshal packet data; got empty JSON object") } - msgs, err := icatypes.DeserializeCosmosTx(k.cdc, packetData.Data) + msgs, err := DeserializeCosmosTxTyped(k.cdc, packetData.Data) if err != nil { k.Logger(ctx).Error("unable to decode messages", "err", err) return err } - for msgIndex, msgData := range txMsgData.Data { + for msgIndex, msg := range msgs { + // use msgData for v0.45 and below and msgResponse for v0.46+ + //nolint:staticcheck // SA1019 ignore this! + var msgData *sdk.MsgData + var msgResponse *codectypes.Any + if len(txMsgData.MsgResponses) > 0 { + msgResponse = txMsgData.MsgResponses[msgIndex] + } else if len(txMsgData.Data) > 0 { + msgData = txMsgData.Data[msgIndex] + } + + src := msg.Msg - src := msgs[msgIndex] - switch msgData.MsgType { + switch msg.Type { case "/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward": + // TODO: if this fails, it's okay. log but continue. + if !success { + return nil + } k.Logger(ctx).Info("Rewards withdrawn") if err := k.HandleWithdrawRewards(ctx, src); err != nil { return err } continue case "/cosmos.staking.v1beta1.MsgRedeemTokensforShares": + // TODO: handle this before LSM + if !success { + return nil + } response := lsmstakingtypes.MsgRedeemTokensforSharesResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgRedeemTokensforShares response", "error", err) - return err + + if msgResponse != nil { + err = k.cdc.UnpackAny(msgResponse, response) + if err != nil { + k.Logger(ctx).Error("unable to unpack MsgRedeemTokensforShares response", "error", err) + return err + } + } else { + err := proto.Unmarshal(msgData.Data, &response) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal MsgRedeemTokensforShares response", "error", err) + return err + } } k.Logger(ctx).Info("Tokens redeemed for shares", "response", response) // we should update delegation records here. @@ -102,11 +164,23 @@ func (k *Keeper) HandleAcknowledgement(ctx sdk.Context, packet channeltypes.Pack } continue case "/cosmos.staking.v1beta1.MsgTokenizeShares": + // TODO: handle this before LSM + if !success { + return nil + } response := lsmstakingtypes.MsgTokenizeSharesResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgTokenizeShares response", "error", err) - return err + if msgResponse != nil { + err = k.cdc.UnpackAny(msgResponse, response) + if err != nil { + k.Logger(ctx).Error("unable to unpack MsgTokenizeShares response", "error", err) + return err + } + } else { + err := proto.Unmarshal(msgData.Data, &response) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal MsgTokenizeShares response", "error", err) + return err + } } k.Logger(ctx).Info("Shares tokenized", "response", response) if err := k.HandleTokenizedShares(ctx, src, response.Amount, packetData.Memo); err != nil { @@ -114,11 +188,23 @@ func (k *Keeper) HandleAcknowledgement(ctx sdk.Context, packet channeltypes.Pack } continue case "/cosmos.staking.v1beta1.MsgDelegate": + // TODO: can we safely ignore this? + if !success { + return nil + } response := stakingtypes.MsgDelegateResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgDelegate response", "error", err) - return err + if msgResponse != nil { + err = k.cdc.UnpackAny(msgResponse, response) + if err != nil { + k.Logger(ctx).Error("unable to unpack MsgDelegate response", "error", err) + return err + } + } else { + err := proto.Unmarshal(msgData.Data, &response) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal MsgDelegate response", "error", err) + return err + } } k.Logger(ctx).Info("Delegated", "response", response) // we should update delegation records here. @@ -127,80 +213,130 @@ func (k *Keeper) HandleAcknowledgement(ctx sdk.Context, packet channeltypes.Pack } continue case "/cosmos.staking.v1beta1.MsgBeginRedelegate": - response := stakingtypes.MsgBeginRedelegateResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgBeginRedelegate response", "error", err) - return err - } - k.Logger(ctx).Info("Redelegation initiated", "response", response) - if err := k.HandleBeginRedelegate(ctx, src, response.CompletionTime, packetData.Memo); err != nil { - return err + if success { + response := stakingtypes.MsgBeginRedelegateResponse{} + if msgResponse != nil { + err = k.cdc.UnpackAny(msgResponse, response) + if err != nil { + k.Logger(ctx).Error("unable to unpack MsgBeginRedelegate response", "error", err) + return err + } + } else { + err := proto.Unmarshal(msgData.Data, &response) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal MsgBeginRedelegate response", "error", err) + return err + } + } + k.Logger(ctx).Info("Redelegation initiated", "response", response) + if err := k.HandleBeginRedelegate(ctx, src, response.CompletionTime, packetData.Memo); err != nil { + return err + } + } else { + if err := k.HandleFailedBeginRedelegate(ctx, src, packetData.Memo); err != nil { + return err + } } continue case "/cosmos.staking.v1beta1.MsgUndelegate": - response := stakingtypes.MsgUndelegateResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgDelegate response", "error", err) - return err - } - k.Logger(ctx).Info("Undelegation started", "response", response) - if err := k.HandleUndelegate(ctx, src, response.CompletionTime, packetData.Memo); err != nil { - return err + if success { + response := stakingtypes.MsgUndelegateResponse{} + if msgResponse != nil { + err = k.cdc.UnpackAny(msgResponse, response) + if err != nil { + k.Logger(ctx).Error("unable to unpack MsgUndelegate response", "error", err) + return err + } + } else { + err := proto.Unmarshal(msgData.Data, &response) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal MsgUndelegate response", "error", err) + return err + } + } + k.Logger(ctx).Info("Undelegation started", "response", response) + if err := k.HandleUndelegate(ctx, src, response.CompletionTime, packetData.Memo); err != nil { + return err + } + } else { + if err := k.HandleFailedUndelegate(ctx, src, packetData.Memo); err != nil { + return err + } } continue + case "/cosmos.bank.v1beta1.MsgSend": + if !success { + // TODO: handle this. + return nil + } response := banktypes.MsgSendResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgSend response", "error", err) - return err + if msgResponse != nil { + err = k.cdc.UnpackAny(msgResponse, response) + if err != nil { + k.Logger(ctx).Error("unable to unpack MsgSend response", "error", err) + return err + } + } else { + err := proto.Unmarshal(msgData.Data, &response) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal MsgSend response", "error", err) + return err + } } k.Logger(ctx).Info("Funds Transferred", "response", response) // check tokenTransfers - if end user unescrow and burn txs if err := k.HandleCompleteSend(ctx, src, packetData.Memo); err != nil { return err } - continue - case "/cosmos.bank.v1beta1.MsgMultiSend": - response := banktypes.MsgMultiSendResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgMultiSend response", "error", err) - return err - } - k.Logger(ctx).Info("Funds Transferred (Multi)", "response", response) - if err := k.HandleCompleteMultiSend(ctx, src, packetData.Memo); err != nil { - return err - } - continue case "/cosmos.distribution.v1beta1.MsgSetWithdrawAddress": + if !success { + // safely ignore this, as we'll try again anyway. + return nil + } response := distrtypes.MsgSetWithdrawAddressResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgMultiSend response", "error", err) - return err + if msgResponse != nil { + err = k.cdc.UnpackAny(msgResponse, response) + if err != nil { + k.Logger(ctx).Error("unable to unpack MsgSetWithdrawAddress response", "error", err) + return err + } + } else { + err := proto.Unmarshal(msgData.Data, &response) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal MsgSetWithdrawAddress response", "error", err) + return err + } } k.Logger(ctx).Info("Withdraw Address Updated", "response", response) if err := k.HandleUpdatedWithdrawAddress(ctx, src); err != nil { return err } - continue case "/ibc.applications.transfer.v1.MsgTransfer": + // this should be okay to fail; we'll pick it up next time around. + if !success { + return nil + } response := ibctransfertypes.MsgTransferResponse{} - err := proto.Unmarshal(msgData.Data, &response) - if err != nil { - k.Logger(ctx).Error("unable to unmarshal MsgTransfer response", "error", err) - return err + if msgResponse != nil { + err = k.cdc.UnpackAny(msgResponse, response) + if err != nil { + k.Logger(ctx).Error("unable to unpack MsgTransfer response", "error", err) + return err + } + } else { + err := proto.Unmarshal(msgData.Data, &response) + if err != nil { + k.Logger(ctx).Error("unable to unmarshal MsgTransfer response", "error", err) + return err + } } k.Logger(ctx).Info("MsgTranfer acknowledgement received") if err := k.HandleMsgTransfer(ctx, src); err != nil { return err } - continue default: - k.Logger(ctx).Error("unhandled acknowledgement packet", "type", msgData.MsgType) + k.Logger(ctx).Error("unhandled acknowledgement packet", "type", reflect.TypeOf(src).Name()) } } @@ -238,39 +374,6 @@ func (k *Keeper) HandleDistributeFeesFromModuleAccount(ctx sdk.Context) error { return k.BankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, authtypes.FeeCollectorName, balance) // Fee collector name needs to be passed in to keeper constructor. } -func (k *Keeper) HandleCompleteMultiSend(ctx sdk.Context, msg sdk.Msg, memo string) error { - k.Logger(ctx).Info("Received MsgMultiSend acknowledgement") - // first, type assertion. we should have banktypes.MsgMultiSend - sMsg, ok := msg.(*banktypes.MsgMultiSend) - if !ok { - k.Logger(ctx).Error("unable to cast source message to MsgMultiSend") - return errors.New("unable to cast source message to MsgMultiSend") - } - - // check for sending of tokens from deposit -> delegate. - zone, err := k.GetZoneFromContext(ctx) - if err != nil { - err = fmt.Errorf("1: %w", err) - k.Logger(ctx).Error(err.Error()) - return err - } - - for _, out := range sMsg.Outputs { - // coerce banktype.Output to banktype.MsgSend - // to use in handleSendToDelegate - msg := banktypes.MsgSend{ - FromAddress: "", - ToAddress: out.Address, - Amount: out.Coins, - } - if err := k.handleSendToDelegate(ctx, zone, &msg, memo); err != nil { - return err - } - } - - return nil -} - func (k *Keeper) HandleCompleteSend(ctx sdk.Context, msg sdk.Msg, memo string) error { k.Logger(ctx).Info("Received MsgSend acknowledgement") // first, type assertion. we should have banktypes.MsgSend @@ -393,123 +496,6 @@ func (k *Keeper) HandleWithdrawForUser(ctx sdk.Context, zone *types.Zone, msg *b return k.EmitValsetRequery(ctx, zone.ConnectionId, zone.ChainId) } -// GetUnlockedTokensForZone will iterate over all delegation records for a zone, and then remove the -// locked tokens (those actively being redelegated), returning a slice of int64 staking tokens that -// are unlocked and free to redelegate or unbond. -func (k *Keeper) GetUnlockedTokensForZone(ctx sdk.Context, zone *types.Zone) map[string]int64 { - availablePerValidator := map[string]int64{} - for _, delegation := range k.GetAllDelegations(ctx, zone) { - thisAvailable, found := availablePerValidator[delegation.ValidatorAddress] - if !found { - thisAvailable = 0 - } - availablePerValidator[delegation.ValidatorAddress] = thisAvailable + delegation.Amount.Amount.Int64() - } - for _, redelegation := range k.ZoneRedelegationRecords(ctx, zone.ChainId) { - thisAvailable, found := availablePerValidator[redelegation.Destination] - if found { - availablePerValidator[redelegation.Destination] = thisAvailable - redelegation.Amount - } - } - return availablePerValidator -} - -// handle queued unbondings is called once per epoch to aggregate all queued unbondings into -// a single unbond transaction per delegation. -func (k *Keeper) HandleQueuedUnbondings(ctx sdk.Context, zone *types.Zone, epoch int64) error { - // out here will only ever be in native bond denom - out := make(map[string]sdk.Coin, 0) - txhashes := make(map[string][]string, 0) - - availablePerValidator := k.GetUnlockedTokensForZone(ctx, zone) - - var err error - k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusQueued, func(idx int64, withdrawal types.WithdrawalRecord) bool { - // copy this so we can rollback on fail - thisAvail := availablePerValidator - thisOut := make(map[string]sdk.Coin, 0) - k.Logger(ctx).Info("unbonding funds", "from", withdrawal.Delegator, "to", withdrawal.Recipient, "amount", withdrawal.Amount) - for _, dist := range withdrawal.Distribution { - if thisAvail[dist.Valoper] < int64(dist.Amount) { - // we cannot satisfy this unbond this epoch. - k.Logger(ctx).Error("unable to satisfy unbonding for this epoch, due to locked tokens.", "txhash", withdrawal.Txhash, "user", withdrawal.Delegator, "chain", zone.ChainId, "validator", dist.Valoper, "avail", thisAvail[dist.Valoper], "wanted", int64(dist.Amount)) - return false - } - thisOut[dist.Valoper] = sdk.NewCoin(zone.BaseDenom, math.NewIntFromUint64(dist.Amount)) - thisAvail[dist.Valoper] -= int64(dist.Amount) - - // if the validator has been historically slashed, and delegatorShares does not match tokens, then we end up with 'clipping'. - // clipping is the truncation of the expected unbonding amount because of the need to have whole integer tokens. - // the amount unbonded is emitted as an event, but not in the response, so we never _know_ this has happened. - // as such, if we know the validator has hisotrical slashing, we remove 1 utoken from the distribution for this validator, with - // the expectation that clipping will occur. We do not reduce the amount requested to unbond. - val, found := zone.GetValidatorByValoper(dist.Valoper) - if !found { - // something kooky is going on... - err = fmt.Errorf("unable to find a validator we expected to exist [%s]", dist.Valoper) - return true - } - if !val.DelegatorShares.Equal(sdk.NewDecFromInt(val.VotingPower)) && dist.Amount > 0 { - dist.Amount-- - } - } - - // update record of available balances. - availablePerValidator = thisAvail - - for valoper, amount := range thisOut { - existing, found := out[valoper] - if !found { - out[valoper] = amount - txhashes[valoper] = []string{withdrawal.Txhash} - - } else { - out[valoper] = existing.Add(amount) - txhashes[valoper] = append(txhashes[valoper], withdrawal.Txhash) - - } - } - - k.UpdateWithdrawalRecordStatus(ctx, &withdrawal, WithdrawStatusUnbond) - return false - }) - if err != nil { - return err - } - - if len(txhashes) == 0 { - // no records to handle. - return nil - } - - var msgs []sdk.Msg - for _, valoper := range utils.Keys(out) { - if !out[valoper].Amount.IsZero() { - sort.Strings(txhashes[valoper]) - k.SetUnbondingRecord(ctx, types.UnbondingRecord{ChainId: zone.ChainId, EpochNumber: epoch, Validator: valoper, RelatedTxhash: txhashes[valoper]}) - msgs = append(msgs, &stakingtypes.MsgUndelegate{DelegatorAddress: zone.DelegationAddress.Address, ValidatorAddress: valoper, Amount: out[valoper]}) - } - } - - k.Logger(ctx).Info("unbonding messages to send", "msg", msgs) - - return k.SubmitTx(ctx, msgs, zone.DelegationAddress, fmt.Sprintf("withdrawal/%d", epoch)) -} - -func (k *Keeper) GCCompletedUnbondings(ctx sdk.Context, zone *types.Zone) error { - var err error - - k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusCompleted, func(idx int64, withdrawal types.WithdrawalRecord) bool { - if ctx.BlockTime().After(withdrawal.CompletionTime.Add(24 * time.Hour)) { - k.Logger(ctx).Info("garbage collecting completed unbondings") - k.DeleteWithdrawalRecord(ctx, zone.ChainId, withdrawal.Txhash, WithdrawStatusCompleted) - } - return false - }) - - return err -} - func (k *Keeper) GCCompletedRedelegations(ctx sdk.Context) error { var err error @@ -589,7 +575,7 @@ func (k *Keeper) HandleTokenizedShares(ctx sdk.Context, msg sdk.Msg, sharesAmoun func (k *Keeper) HandleBeginRedelegate(ctx sdk.Context, msg sdk.Msg, completion time.Time, memo string) error { parts := strings.Split(memo, "/") - if len(parts) != 2 { + if len(parts) != 2 || parts[0] != "rebalance" { return errors.New("unexpected epoch rebalance memo format") } @@ -613,6 +599,37 @@ func (k *Keeper) HandleBeginRedelegate(ctx sdk.Context, msg sdk.Msg, completion k.Logger(ctx).Info("updating redelegation record with completion time", "completion", completion) record.CompletionTime = completion k.SetRedelegationRecord(ctx, record) + + delegation, found := k.GetDelegation(ctx, zone, redelegateMsg.DelegatorAddress, redelegateMsg.ValidatorDstAddress) + if !found { + k.Logger(ctx).Error("unable to find delegation record", "chain", zone.ChainId, "source", redelegateMsg.ValidatorSrcAddress, "dst", redelegateMsg.ValidatorDstAddress, "epoch", epochNumber) + return fmt.Errorf("unable to find delegation record for chain %s, src: %s, dst: %s, at epoch %d", zone.ChainId, redelegateMsg.ValidatorSrcAddress, redelegateMsg.ValidatorDstAddress, epochNumber) + } + delegation.RedelegationEnd = completion.Unix() // this field should be a timestamp, but lets avoid unnecessary state changes. + k.SetDelegation(ctx, zone, delegation) + return nil +} + +func (k *Keeper) HandleFailedBeginRedelegate(ctx sdk.Context, msg sdk.Msg, memo string) error { + parts := strings.Split(memo, "/") + if len(parts) != 2 || parts[0] != "rebalance" { + return errors.New("unexpected epoch rebalance memo format") + } + + epochNumber, err := strconv.ParseInt(parts[1], 10, 64) + if err != nil { + return errors.New("unexpected epoch rebalance memo format (2)") + } + + k.Logger(ctx).Error("Received MsgBeginRedelegate acknowledgement error") + // first, type assertion. we should have stakingtypes.MsgBeginRedelegate + redelegateMsg, ok := msg.(*stakingtypes.MsgBeginRedelegate) + if !ok { + return errors.New("unable to unmarshal MsgBeginRedelegate") + } + zone := k.GetZoneForDelegateAccount(ctx, redelegateMsg.DelegatorAddress) + k.DeleteRedelegationRecord(ctx, zone.ChainId, redelegateMsg.ValidatorSrcAddress, redelegateMsg.ValidatorDstAddress, epochNumber) + k.Logger(ctx).Error("Cleaning up redelegation record") return nil } @@ -625,7 +642,7 @@ func (k *Keeper) HandleUndelegate(ctx sdk.Context, msg sdk.Msg, completion time. return errors.New("unable to cast source message to MsgUndelegate") } memoParts := strings.Split(memo, "/") - if len(memoParts) != 2 { + if len(memoParts) != 2 || memoParts[0] != withdrawal { return errors.New("unexpected memo form") } @@ -681,6 +698,82 @@ func (k *Keeper) HandleUndelegate(ctx sdk.Context, msg sdk.Msg, completion time. return nil } +func (k *Keeper) HandleFailedUndelegate(ctx sdk.Context, msg sdk.Msg, memo string) error { + parts := strings.Split(memo, "/") + if len(parts) != 2 || parts[0] != withdrawal { + return errors.New("unexpected epoch undelegate memo format") + } + + epochNumber, err := strconv.ParseInt(parts[1], 10, 64) + if err != nil { + return errors.New("unexpected epoch undelegate memo format (2)") + } + + k.Logger(ctx).Error("Received MsgUndelegate acknowledgement error") + // first, type assertion. we should have stakingtypes.MsgBeginRedelegate + undelegateMsg, ok := msg.(*stakingtypes.MsgUndelegate) + if !ok { + return errors.New("unable to unmarshal MsgUndelegate") + } + + zone := k.GetZoneForDelegateAccount(ctx, undelegateMsg.DelegatorAddress) + ubr, found := k.GetUnbondingRecord(ctx, zone.ChainId, undelegateMsg.ValidatorAddress, epochNumber) + if !found { + return fmt.Errorf("cannot find unbonding record for %s/%s/%d", zone.ChainId, undelegateMsg.ValidatorAddress, epochNumber) + } + + for _, hash := range ubr.RelatedTxhash { + wdr, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, WithdrawStatusUnbond) + if !found { + return fmt.Errorf("cannot find withdrawal record for %s/%s", zone.ChainId, hash) + } + if len(wdr.Distribution) == 1 { + // sanity check + if wdr.Distribution[0].Valoper != ubr.Validator { + return fmt.Errorf("unable to requeue withdrawal record for failed unbonding; expected %s, got %s", ubr.Validator, wdr.Distribution[0].Valoper) + } + wdr.Distribution = nil + wdr.Requeued = true + k.UpdateWithdrawalRecordStatus(ctx, &wdr, WithdrawStatusQueued) + } else { + // remove this validator from distribution; amend amounts; requeue. + newDistribution := make([]*types.Distribution, 0) + relatedAmount := uint64(0) + for _, dist := range wdr.Distribution { + if dist.Valoper != ubr.Validator { + newDistribution = append(newDistribution, dist) + } else { + relatedAmount = dist.Amount + } + } + wdr.Distribution = newDistribution + amount := wdr.Amount.AmountOf(zone.BaseDenom) + wdr.Amount = wdr.Amount.Sub(sdk.NewCoin(zone.BaseDenom, sdk.NewIntFromUint64(relatedAmount))) + rr := sdk.NewDecFromInt(wdr.BurnAmount.Amount).Quo(sdk.NewDecFromInt(amount)) + relatedQAsset := sdk.NewDec(int64(relatedAmount)).Mul(rr).TruncateInt() + wdr.BurnAmount = wdr.BurnAmount.SubAmount(relatedQAsset) + k.SetWithdrawalRecord(ctx, wdr) + // create a new record with the failed amount + newWdr := types.WithdrawalRecord{ + ChainId: zone.ChainId, + Delegator: wdr.Delegator, + Recipient: wdr.Recipient, + Distribution: nil, + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewIntFromUint64(relatedAmount))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, relatedQAsset), + Txhash: fmt.Sprintf("%064d", k.GetNextWithdrawalRecordSequence(ctx)), + Status: WithdrawStatusQueued, + Requeued: true, + } + k.SetWithdrawalRecord(ctx, newWdr) + } + } + + k.DeleteUnbondingRecord(ctx, zone.ChainId, undelegateMsg.ValidatorAddress, epochNumber) + k.Logger(ctx).Error("Cleaning up redelegation record") + return nil +} + func (k *Keeper) HandleRedeemTokens(ctx sdk.Context, msg sdk.Msg, amount sdk.Coin) error { k.Logger(ctx).Info("Received MsgRedeemTokensforShares acknowledgement") // first, type assertion. we should have stakingtypes.MsgRedeemTokensforShares diff --git a/x/interchainstaking/keeper/ibc_packet_handlers_test.go b/x/interchainstaking/keeper/ibc_packet_handlers_test.go index c5f6348de..aafcb73a9 100644 --- a/x/interchainstaking/keeper/ibc_packet_handlers_test.go +++ b/x/interchainstaking/keeper/ibc_packet_handlers_test.go @@ -1,6 +1,10 @@ package keeper_test import ( + sdkmath "cosmossdk.io/math" + "crypto/sha256" + "fmt" + "math/rand" "testing" "time" @@ -8,7 +12,10 @@ import ( "github.com/cosmos/cosmos-sdk/types/bech32" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + icatypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types" ibctransfertypes "github.com/cosmos/ibc-go/v5/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" "github.com/ingenuity-build/quicksilver/app" "github.com/ingenuity-build/quicksilver/utils" icskeeper "github.com/ingenuity-build/quicksilver/x/interchainstaking/keeper" @@ -114,32 +121,28 @@ func mustGetTestBech32Address(hrp string) string { } func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { - val1 := utils.GenerateValAddressForTest().String() - val2 := utils.GenerateValAddressForTest().String() - val3 := utils.GenerateValAddressForTest().String() - val4 := utils.GenerateValAddressForTest().String() - tests := []struct { name string - records func(chainID string, hrp string) []icstypes.WithdrawalRecord - delegations func(chainID string, delegateAddress string, hrp string) []icstypes.Delegation - redelegations func(chainID string, delegateAddress string, hrp string) []icstypes.RedelegationRecord + records func(zone *icstypes.Zone) []icstypes.WithdrawalRecord + delegations func(zone *icstypes.Zone) []icstypes.Delegation + redelegations func(zone *icstypes.Zone) []icstypes.RedelegationRecord expectTransition []bool + expectError bool }{ { name: "valid", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ - {Valoper: val1, Amount: 1000000}, - {Valoper: val2, Amount: 1000000}, - {Valoper: val3, Amount: 1000000}, - {Valoper: val4, Amount: 1000000}, + {Valoper: zone.Validators[0].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[1].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[2].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[3].ValoperAddress, Amount: 1000000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", @@ -147,64 +150,65 @@ func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { }, } }, - delegations: func(chainID string, delegateAddress string, hrp string) []icstypes.Delegation { + delegations: func(zone *icstypes.Zone) []icstypes.Delegation { return []icstypes.Delegation{ { - DelegationAddress: delegateAddress, - ValidatorAddress: val1, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[0].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(1000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val2, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[1].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(1000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val3, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[2].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(1000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val4, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[3].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(1000000)), }, } }, - redelegations: func(chainID string, delegateAddress string, hrp string) []icstypes.RedelegationRecord { + redelegations: func(zone *icstypes.Zone) []icstypes.RedelegationRecord { return []icstypes.RedelegationRecord{} }, expectTransition: []bool{true}, + expectError: false, }, { name: "valid - two", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ - {Valoper: val1, Amount: 1000000}, - {Valoper: val2, Amount: 1000000}, - {Valoper: val3, Amount: 1000000}, - {Valoper: val4, Amount: 1000000}, + {Valoper: zone.Validators[0].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[1].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[2].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[3].ValoperAddress, Amount: 1000000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", Status: icskeeper.WithdrawStatusQueued, }, { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ - {Valoper: val1, Amount: 5000000}, - {Valoper: val2, Amount: 2500000}, - {Valoper: val3, Amount: 5000000}, - {Valoper: val4, Amount: 2500000}, + {Valoper: zone.Validators[0].ValoperAddress, Amount: 5000000}, + {Valoper: zone.Validators[1].ValoperAddress, Amount: 2500000}, + {Valoper: zone.Validators[2].ValoperAddress, Amount: 5000000}, + {Valoper: zone.Validators[3].ValoperAddress, Amount: 2500000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(15000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(15000000)), Txhash: "d786f7d4c94247625c2882e921a790790eb77a00d0534d5c3154d0a9c5ab68f5", @@ -212,49 +216,50 @@ func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { }, } }, - delegations: func(chainID string, delegateAddress string, hrp string) []icstypes.Delegation { + delegations: func(zone *icstypes.Zone) []icstypes.Delegation { return []icstypes.Delegation{ { - DelegationAddress: delegateAddress, - ValidatorAddress: val1, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[0].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(10000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val2, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[1].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(10000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val3, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[2].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(10000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val4, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[3].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(10000000)), }, } }, - redelegations: func(chainID string, delegateAddress string, hrp string) []icstypes.RedelegationRecord { + redelegations: func(zone *icstypes.Zone) []icstypes.RedelegationRecord { return []icstypes.RedelegationRecord{} }, expectTransition: []bool{true, true}, + expectError: false, }, { name: "invalid - locked tokens", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ - {Valoper: val1, Amount: 1000000}, - {Valoper: val2, Amount: 1000000}, - {Valoper: val3, Amount: 1000000}, - {Valoper: val4, Amount: 1000000}, + {Valoper: zone.Validators[0].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[1].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[2].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[3].ValoperAddress, Amount: 1000000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", @@ -262,73 +267,74 @@ func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { }, } }, - delegations: func(chainID string, delegateAddress string, hrp string) []icstypes.Delegation { + delegations: func(zone *icstypes.Zone) []icstypes.Delegation { return []icstypes.Delegation{ { - DelegationAddress: delegateAddress, - ValidatorAddress: val1, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[0].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(1000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val2, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[1].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(1000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val3, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[2].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(1000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val4, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[3].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(1000000)), }, } }, - redelegations: func(chainID string, delegateAddress string, hrp string) []icstypes.RedelegationRecord { + redelegations: func(zone *icstypes.Zone) []icstypes.RedelegationRecord { return []icstypes.RedelegationRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, EpochNumber: 1, - Source: val4, - Destination: val1, + Source: zone.Validators[3].ValoperAddress, + Destination: zone.Validators[0].ValoperAddress, Amount: 50000, CompletionTime: time.Now().Add(time.Hour), }, } }, expectTransition: []bool{false}, + expectError: true, }, { - name: "mixed - locked tokens prohibit first unbond, but second permitted", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + name: "mixed - locked tokens but both succeed (previously failed)", + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ - {Valoper: val1, Amount: 5000000}, - {Valoper: val2, Amount: 2500000}, - {Valoper: val3, Amount: 5000000}, - {Valoper: val4, Amount: 2500000}, + {Valoper: zone.Validators[0].ValoperAddress, Amount: 5000000}, + {Valoper: zone.Validators[1].ValoperAddress, Amount: 2500000}, + {Valoper: zone.Validators[2].ValoperAddress, Amount: 5000000}, + {Valoper: zone.Validators[3].ValoperAddress, Amount: 2500000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(15000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(15000000)), Txhash: "d786f7d4c94247625c2882e921a790790eb77a00d0534d5c3154d0a9c5ab68f5", Status: icskeeper.WithdrawStatusQueued, }, { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ - {Valoper: val1, Amount: 1000000}, - {Valoper: val2, Amount: 1000000}, - {Valoper: val3, Amount: 1000000}, - {Valoper: val4, Amount: 1000000}, + {Valoper: zone.Validators[0].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[1].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[2].ValoperAddress, Amount: 1000000}, + {Valoper: zone.Validators[3].ValoperAddress, Amount: 1000000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", @@ -336,43 +342,44 @@ func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { }, } }, - delegations: func(chainID string, delegateAddress string, hrp string) []icstypes.Delegation { + delegations: func(zone *icstypes.Zone) []icstypes.Delegation { return []icstypes.Delegation{ { - DelegationAddress: delegateAddress, - ValidatorAddress: val1, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[0].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(6000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val2, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[1].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(6000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val3, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[2].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(6000000)), }, { - DelegationAddress: delegateAddress, - ValidatorAddress: val4, + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[3].ValoperAddress, Amount: sdk.NewCoin("uatom", sdk.NewInt(6000000)), }, } }, - redelegations: func(chainID string, delegateAddress string, hrp string) []icstypes.RedelegationRecord { + redelegations: func(zone *icstypes.Zone) []icstypes.RedelegationRecord { return []icstypes.RedelegationRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, EpochNumber: 1, - Source: val4, - Destination: val1, + Source: zone.Validators[3].ValoperAddress, + Destination: zone.Validators[0].ValoperAddress, Amount: 1000001, CompletionTime: time.Now().Add(time.Hour), }, } }, - expectTransition: []bool{false, true}, + expectTransition: []bool{true, true}, + expectError: false, }, } @@ -388,14 +395,9 @@ func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { if !found { s.Fail("unable to retrieve zone for test") } - zone.Validators = append(zone.Validators, &icstypes.Validator{ValoperAddress: val1, VotingPower: sdk.ZeroInt(), DelegatorShares: sdk.ZeroDec()}) - zone.Validators = append(zone.Validators, &icstypes.Validator{ValoperAddress: val2, VotingPower: sdk.ZeroInt(), DelegatorShares: sdk.ZeroDec()}) - zone.Validators = append(zone.Validators, &icstypes.Validator{ValoperAddress: val3, VotingPower: sdk.ZeroInt(), DelegatorShares: sdk.ZeroDec()}) - zone.Validators = append(zone.Validators, &icstypes.Validator{ValoperAddress: val4, VotingPower: sdk.ZeroInt(), DelegatorShares: sdk.ZeroDec()}) - - records := test.records(s.chainB.ChainID, zone.AccountPrefix) - delegations := test.delegations(s.chainB.ChainID, zone.DelegationAddress.Address, zone.AccountPrefix) - redelegations := test.redelegations(s.chainB.ChainID, zone.DelegationAddress.Address, zone.AccountPrefix) + records := test.records(&zone) + delegations := test.delegations(&zone) + redelegations := test.redelegations(&zone) // set up zones for _, record := range records { @@ -417,7 +419,11 @@ func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { // trigger handler err := app.InterchainstakingKeeper.HandleQueuedUnbondings(ctx, &zone, 1) - s.Require().NoError(err) + if test.expectError { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } for idx, record := range records { // check record with old status is opposite to expectedTransition (if false, this record should exist in status 3) @@ -428,8 +434,11 @@ func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { s.Require().Equal(test.expectTransition[idx], found) if test.expectTransition[idx] { - for _, unbonding := range record.Distribution { + actualRecord, found := app.InterchainstakingKeeper.GetWithdrawalRecord(ctx, zone.ChainId, record.Txhash, icskeeper.WithdrawStatusUnbond) + s.Require().True(found) + for _, unbonding := range actualRecord.Distribution { r, found := app.InterchainstakingKeeper.GetUnbondingRecord(ctx, zone.ChainId, unbonding.Valoper, 1) + fmt.Println(r) s.Require().True(found) s.Require().Contains(r.RelatedTxhash, record.Txhash) } @@ -442,17 +451,17 @@ func (s *KeeperTestSuite) TestHandleQueuedUnbondings() { func (s *KeeperTestSuite) TestHandleWithdrawForUser() { tests := []struct { name string - records func(chainID string, hrp string) []icstypes.WithdrawalRecord + records func(zone *icstypes.Zone) []icstypes.WithdrawalRecord message banktypes.MsgSend memo string err bool }{ { name: "invalid - no matching record", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, @@ -460,7 +469,7 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUser() { {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", @@ -474,10 +483,10 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUser() { }, { name: "valid", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, @@ -485,7 +494,7 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUser() { {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", @@ -501,10 +510,10 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUser() { }, { name: "valid - two", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, @@ -512,14 +521,14 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUser() { {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1000000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(4000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(4000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", Status: icskeeper.WithdrawStatusSend, }, { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ {Valoper: utils.GenerateValAddressForTest().String(), Amount: 5000000}, @@ -527,7 +536,7 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUser() { {Valoper: utils.GenerateValAddressForTest().String(), Amount: 5000000}, {Valoper: utils.GenerateValAddressForTest().String(), Amount: 1250000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(15000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(15000000)), Txhash: "d786f7d4c94247625c2882e921a790790eb77a00d0534d5c3154d0a9c5ab68f5", @@ -556,7 +565,7 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUser() { s.Fail("unable to retrieve zone for test") } - records := test.records(s.chainB.ChainID, zone.AccountPrefix) + records := test.records(&zone) // set up zones for _, record := range records { @@ -597,23 +606,23 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUserLSM() { v2 := utils.GenerateValAddressForTest().String() tests := []struct { name string - records func(chainID string, hrp string) []icstypes.WithdrawalRecord + records func(zone *icstypes.Zone) []icstypes.WithdrawalRecord message []banktypes.MsgSend memo string err bool }{ { name: "valid", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ {Valoper: v1, Amount: 1000000}, {Valoper: v2, Amount: 1000000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(2000000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(2000000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", @@ -630,16 +639,16 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUserLSM() { }, { name: "valid - unequal", - records: func(chainID string, hrp string) []icstypes.WithdrawalRecord { + records: func(zone *icstypes.Zone) []icstypes.WithdrawalRecord { return []icstypes.WithdrawalRecord{ { - ChainId: chainID, + ChainId: zone.ChainId, Delegator: utils.GenerateAccAddressForTest().String(), Distribution: []*icstypes.Distribution{ {Valoper: v1, Amount: 1000000}, {Valoper: v2, Amount: 1500000}, }, - Recipient: mustGetTestBech32Address(hrp), + Recipient: mustGetTestBech32Address(zone.AccountPrefix), Amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(2500000))), BurnAmount: sdk.NewCoin("uqatom", sdk.NewInt(2500000)), Txhash: "7C8B95EEE82CB63771E02EBEB05E6A80076D70B2E0A1C457F1FD1A0EF2EA961D", @@ -669,7 +678,7 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUserLSM() { s.Fail("unable to retrieve zone for test") } - records := test.records(s.chainB.ChainID, zone.AccountPrefix) + records := test.records(&zone) startBalance := app.BankKeeper.GetAllBalances(ctx, app.AccountKeeper.GetModuleAddress(icstypes.ModuleName)) // set up zones @@ -710,3 +719,760 @@ func (s *KeeperTestSuite) TestHandleWithdrawForUserLSM() { }) } } + +func (s *KeeperTestSuite) TestReceiveAckErrForBeginRedelegate() { + s.SetupTest() + s.setupTestZones() + + app := s.GetQuicksilverApp(s.chainA) + ctx := s.chainA.GetContext() + + zone, found := app.InterchainstakingKeeper.GetZone(ctx, s.chainB.ChainID) + if !found { + s.Fail("unable to retrieve zone for test") + } + + // create redelegation record + record := icstypes.RedelegationRecord{ + ChainId: s.chainB.ChainID, + EpochNumber: 1, + Source: zone.Validators[0].ValoperAddress, + Destination: zone.Validators[1].ValoperAddress, + Amount: 1000, + } + + app.InterchainstakingKeeper.SetRedelegationRecord(ctx, record) + + redelegate := &stakingtypes.MsgBeginRedelegate{DelegatorAddress: zone.DelegationAddress.Address, ValidatorSrcAddress: zone.Validators[0].ValoperAddress, ValidatorDstAddress: zone.Validators[1].ValoperAddress, Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))} + data, err := icatypes.SerializeCosmosTx(app.InterchainstakingKeeper.GetCodec(), []sdk.Msg{redelegate}) + s.Require().NoError(err) + + // validate memo < 256 bytes + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + Memo: fmt.Sprintf("rebalance/%d", 1), + } + + packet := channeltypes.Packet{Data: app.InterchainstakingKeeper.GetCodec().MustMarshalJSON(&packetData)} + + ackBytes := []byte("{\"error\":\"ABCI code: 32: error handling packet on host chain: see events for details\"}") + // call handler + + _, found = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, zone.Validators[0].ValoperAddress, zone.Validators[1].ValoperAddress, 1) + s.Require().True(found) + + err = app.InterchainstakingKeeper.HandleAcknowledgement(ctx, packet, ackBytes) + s.Require().NoError(err) + + _, found = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, zone.Validators[0].ValoperAddress, zone.Validators[1].ValoperAddress, 1) + s.Require().False(found) +} + +func (s *KeeperTestSuite) TestReceiveAckErrForBeginUndelegate() { + hash1 := fmt.Sprintf("%x", sha256.Sum256([]byte{0x01})) + hash2 := fmt.Sprintf("%x", sha256.Sum256([]byte{0x02})) + hash3 := fmt.Sprintf("%x", sha256.Sum256([]byte{0x03})) + delegator1 := utils.GenerateAccAddressForTest().String() + delegator2 := utils.GenerateAccAddressForTest().String() + randRr := rand.Float64() + 1.0 + tests := []struct { + name string + epoch int64 + withdrawalRecords func(zone icstypes.Zone) []icstypes.WithdrawalRecord + unbondingRecords func(zone icstypes.Zone) []icstypes.UnbondingRecord + msgs func(zone icstypes.Zone) []sdk.Msg + expectedWithdrawalRecords func(zone icstypes.Zone) []icstypes.WithdrawalRecord + }{ + { + name: "1 wdr, 2 vals, 1k+1k, 1800 qasset", + epoch: 1, + withdrawalRecords: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { + return []icstypes.WithdrawalRecord{ + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 1000, + }, + { + Valoper: zone.Validators[1].ValoperAddress, + Amount: 1000, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(2000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1800)), + Txhash: hash1, + Status: icskeeper.WithdrawStatusUnbond, + }, + } + }, + unbondingRecords: func(zone icstypes.Zone) []icstypes.UnbondingRecord { + return []icstypes.UnbondingRecord{ + { + ChainId: s.chainB.ChainID, + EpochNumber: 1, + Validator: zone.Validators[0].ValoperAddress, + RelatedTxhash: []string{hash1}, + }, + } + }, + msgs: func(zone icstypes.Zone) []sdk.Msg { + return []sdk.Msg{ + &stakingtypes.MsgUndelegate{ + DelegatorAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[0].ValoperAddress, + Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000)), + }, + } + }, + expectedWithdrawalRecords: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { + return []icstypes.WithdrawalRecord{ + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[1].ValoperAddress, + Amount: 1000, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), + Txhash: hash1, + Status: icskeeper.WithdrawStatusUnbond, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: nil, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), + Txhash: fmt.Sprintf("%064d", 1), + Status: icskeeper.WithdrawStatusQueued, + }, + } + }, + }, + { + name: "1 wdr, 1 vals, 1k, 900 qasset", + epoch: 1, + withdrawalRecords: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { + return []icstypes.WithdrawalRecord{ + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 1000, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), + Txhash: hash1, + Status: icskeeper.WithdrawStatusUnbond, + }, + } + }, + unbondingRecords: func(zone icstypes.Zone) []icstypes.UnbondingRecord { + return []icstypes.UnbondingRecord{ + { + ChainId: s.chainB.ChainID, + EpochNumber: 1, + Validator: zone.Validators[0].ValoperAddress, + RelatedTxhash: []string{hash1}, + }, + } + }, + msgs: func(zone icstypes.Zone) []sdk.Msg { + return []sdk.Msg{ + &stakingtypes.MsgUndelegate{ + DelegatorAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[0].ValoperAddress, + Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000)), + }, + } + }, + expectedWithdrawalRecords: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { + return []icstypes.WithdrawalRecord{ + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: nil, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), + Txhash: hash1, + Status: icskeeper.WithdrawStatusQueued, + }, + } + }, + }, + { + name: "3 wdr, 2 vals, 1k+0.5k, 1350 qasset; 1k+2k, 2700 qasset; 600+400, 900qasset", + epoch: 2, + withdrawalRecords: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { + return []icstypes.WithdrawalRecord{ + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 1000, + }, + { + Valoper: zone.Validators[1].ValoperAddress, + Amount: 500, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1500))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1350)), + Txhash: hash1, + Status: icskeeper.WithdrawStatusUnbond, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator2, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 1000, + }, + { + Valoper: zone.Validators[1].ValoperAddress, + Amount: 2000, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(3000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(2700)), + Txhash: hash2, + Status: icskeeper.WithdrawStatusUnbond, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 600, + }, + { + Valoper: zone.Validators[1].ValoperAddress, + Amount: 400, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), + Txhash: hash3, + Status: icskeeper.WithdrawStatusUnbond, + }, + } + }, + unbondingRecords: func(zone icstypes.Zone) []icstypes.UnbondingRecord { + return []icstypes.UnbondingRecord{ + { + ChainId: s.chainB.ChainID, + EpochNumber: 2, + Validator: zone.Validators[1].ValoperAddress, + RelatedTxhash: []string{hash1, hash2, hash3}, + }, + } + }, + msgs: func(zone icstypes.Zone) []sdk.Msg { + return []sdk.Msg{ + &stakingtypes.MsgUndelegate{ + DelegatorAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[1].ValoperAddress, + Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewInt(2900)), + }, + } + }, + expectedWithdrawalRecords: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { + return []icstypes.WithdrawalRecord{ + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 1000, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), + Txhash: hash1, + Status: icskeeper.WithdrawStatusUnbond, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator2, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 1000, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(900)), + Txhash: hash2, + Status: icskeeper.WithdrawStatusUnbond, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 600, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(600))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(540)), + Txhash: hash3, + Status: icskeeper.WithdrawStatusUnbond, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: nil, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(500))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(450)), + Txhash: fmt.Sprintf("%064d", 1), + Status: icskeeper.WithdrawStatusQueued, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator2, + Distribution: nil, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(2000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(1800)), + Txhash: fmt.Sprintf("%064d", 2), + Status: icskeeper.WithdrawStatusQueued, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: nil, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(400))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewInt(360)), + Txhash: fmt.Sprintf("%064d", 3), + Status: icskeeper.WithdrawStatusQueued, + }, + } + }, + }, + { + name: "2 wdr, random_rr, 1 vals, 1k; 2 vals; 123 + 456 ", + epoch: 1, + withdrawalRecords: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { + return []icstypes.WithdrawalRecord{ + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[0].ValoperAddress, + Amount: 1000, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewDec(1000).Quo(sdk.MustNewDecFromStr(fmt.Sprintf("%f", randRr))).TruncateInt()), + Txhash: hash1, + Status: icskeeper.WithdrawStatusUnbond, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator2, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[1].ValoperAddress, + Amount: 123, + }, + { + Valoper: zone.Validators[2].ValoperAddress, + Amount: 456, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(579))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewDec(579).Quo(sdk.MustNewDecFromStr(fmt.Sprintf("%f", randRr))).TruncateInt()), + Txhash: hash2, + Status: icskeeper.WithdrawStatusUnbond, + }, + } + }, + unbondingRecords: func(zone icstypes.Zone) []icstypes.UnbondingRecord { + return []icstypes.UnbondingRecord{ + { + ChainId: s.chainB.ChainID, + EpochNumber: 1, + Validator: zone.Validators[0].ValoperAddress, + RelatedTxhash: []string{hash1}, + }, + { + ChainId: s.chainB.ChainID, + EpochNumber: 1, + Validator: zone.Validators[1].ValoperAddress, + RelatedTxhash: []string{hash2}, + }, + // { + // ChainId: s.chainB.ChainID, + // EpochNumber: 1, + // Validator: zone.Validators[2].ValoperAddress, + // RelatedTxhash: []string{hash2}, + // }, + } + }, + msgs: func(zone icstypes.Zone) []sdk.Msg { + return []sdk.Msg{ + &stakingtypes.MsgUndelegate{ + DelegatorAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[0].ValoperAddress, + Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000)), + }, + &stakingtypes.MsgUndelegate{ + DelegatorAddress: zone.DelegationAddress.Address, + ValidatorAddress: zone.Validators[1].ValoperAddress, + Amount: sdk.NewCoin(zone.BaseDenom, sdk.NewInt(123)), + }, + } + }, + expectedWithdrawalRecords: func(zone icstypes.Zone) []icstypes.WithdrawalRecord { + return []icstypes.WithdrawalRecord{ + { + ChainId: s.chainB.ChainID, + Delegator: delegator1, + Distribution: nil, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(1000))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewDec(1000).Quo(sdk.MustNewDecFromStr(fmt.Sprintf("%f", randRr))).TruncateInt()), + Txhash: hash1, + Status: icskeeper.WithdrawStatusQueued, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator2, + Distribution: nil, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(123))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewDec(123).Quo(sdk.MustNewDecFromStr(fmt.Sprintf("%f", randRr))).TruncateInt()), + Txhash: fmt.Sprintf("%064d", 1), + Status: icskeeper.WithdrawStatusQueued, + }, + { + ChainId: s.chainB.ChainID, + Delegator: delegator2, + Distribution: []*icstypes.Distribution{ + { + Valoper: zone.Validators[2].ValoperAddress, + Amount: 456, + }, + }, + Recipient: mustGetTestBech32Address(zone.GetAccountPrefix()), + Amount: sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, sdk.NewInt(456))), + BurnAmount: sdk.NewCoin(zone.LocalDenom, sdk.NewDec(456).Quo(sdk.MustNewDecFromStr(fmt.Sprintf("%f", randRr))).TruncateInt()), + Txhash: hash2, + Status: icskeeper.WithdrawStatusUnbond, + }, + } + }, + }, + } + + for _, test := range tests { + s.Run(test.name, func() { + s.SetupTest() + s.setupTestZones() + + app := s.GetQuicksilverApp(s.chainA) + ctx := s.chainA.GetContext() + + zone, found := app.InterchainstakingKeeper.GetZone(ctx, s.chainB.ChainID) + if !found { + s.Fail("unable to retrieve zone for test") + } + + for _, wdr := range test.withdrawalRecords(zone) { + app.InterchainstakingKeeper.SetWithdrawalRecord(ctx, wdr) + } + + for _, ubr := range test.unbondingRecords(zone) { + app.InterchainstakingKeeper.SetUnbondingRecord(ctx, ubr) + } + + data, err := icatypes.SerializeCosmosTx(app.InterchainstakingKeeper.GetCodec(), test.msgs(zone)) + s.Require().NoError(err) + + // validate memo < 256 bytes + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: data, + Memo: fmt.Sprintf("withdrawal/%d", test.epoch), + } + + packet := channeltypes.Packet{Data: app.InterchainstakingKeeper.GetCodec().MustMarshalJSON(&packetData)} + + ackBytes := []byte("{\"error\":\"ABCI code: 32: error handling packet on host chain: see events for details\"}") + // call handler + + for _, ubr := range test.unbondingRecords(zone) { + _, found = app.InterchainstakingKeeper.GetUnbondingRecord(ctx, zone.ChainId, ubr.Validator, test.epoch) + s.Require().True(found) + } + + err = app.InterchainstakingKeeper.HandleAcknowledgement(ctx, packet, ackBytes) + s.Require().NoError(err) + + for _, ubr := range test.unbondingRecords(zone) { + _, found = app.InterchainstakingKeeper.GetUnbondingRecord(ctx, zone.ChainId, ubr.Validator, test.epoch) + s.Require().False(found) + } + + for idx, ewdr := range test.expectedWithdrawalRecords(zone) { + wdr, found := app.InterchainstakingKeeper.GetWithdrawalRecord(ctx, zone.ChainId, ewdr.Txhash, ewdr.Status) + s.Require().True(found) + s.Require().Equal(ewdr.Amount, wdr.Amount) + s.Require().Equal(ewdr.BurnAmount, wdr.BurnAmount) + s.Require().Equal(ewdr.Delegator, wdr.Delegator) + s.Require().Equal(ewdr.Distribution, wdr.Distribution, idx) + s.Require().Equal(ewdr.Status, wdr.Status) + } + }) + } +} +func (s *KeeperTestSuite) TestRebalanceDueToIntentChange() { + + s.SetupTest() + s.setupTestZones() + + app := s.GetQuicksilverApp(s.chainA) + ctx := s.chainA.GetContext() + + zone, found := app.InterchainstakingKeeper.GetZone(ctx, s.chainB.ChainID) + if !found { + s.Fail("unable to retrieve zone for test") + } + vals := zone.Validators + + delegations := []icstypes.Delegation{ + { + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: vals[0].ValoperAddress, + Amount: sdk.NewCoin("uatom", sdk.NewInt(1000)), + RedelegationEnd: 0, + }, + { + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: vals[1].ValoperAddress, + Amount: sdk.NewCoin("uatom", sdk.NewInt(1000)), + RedelegationEnd: 0, + }, + { + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: vals[2].ValoperAddress, + Amount: sdk.NewCoin("uatom", sdk.NewInt(1000)), + RedelegationEnd: 0, + }, { + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: vals[3].ValoperAddress, + Amount: sdk.NewCoin("uatom", sdk.NewInt(1000)), + RedelegationEnd: 0, + }, + } + for _, delegation := range delegations { + app.InterchainstakingKeeper.SetDelegation(ctx, &zone, delegation) + val, _ := zone.GetValidatorByValoper(delegation.ValidatorAddress) + val.VotingPower = val.VotingPower.Add(delegation.Amount.Amount) + val.DelegatorShares = val.DelegatorShares.Add(sdk.NewDecFromInt(delegation.Amount.Amount)) + } + + app.InterchainstakingKeeper.SetZone(ctx, &zone) + + // trigger rebalance + err := app.InterchainstakingKeeper.Rebalance(ctx, zone, 1) + s.Require().NoError(err) + + //change intents to trigger redelegations from val[3] + intents := icstypes.ValidatorIntents{ + {ValoperAddress: vals[0].ValoperAddress, Weight: sdk.NewDecWithPrec(3, 1)}, + {ValoperAddress: vals[1].ValoperAddress, Weight: sdk.NewDecWithPrec(3, 1)}, + {ValoperAddress: vals[2].ValoperAddress, Weight: sdk.NewDecWithPrec(3, 1)}, + {ValoperAddress: vals[3].ValoperAddress, Weight: sdk.NewDecWithPrec(1, 1)}, + } + zone.AggregateIntent = intents + + // trigger rebalance + err = app.InterchainstakingKeeper.Rebalance(ctx, zone, 2) + + // mock ack for redelegations + app.InterchainstakingKeeper.IteratePrefixedRedelegationRecords(ctx, []byte(zone.ChainId), func(idx int64, _ []byte, record icstypes.RedelegationRecord) (stop bool) { + if record.EpochNumber == 2 { + msg := stakingtypes.MsgBeginRedelegate{zone.DelegationAddress.Address, + record.Source, + record.Destination, + sdk.NewCoin("uatom", sdkmath.NewInt(record.Amount))} + err := app.InterchainstakingKeeper.HandleBeginRedelegate(ctx, &msg, time.Now().Add(time.Hour*24*7), fmt.Sprintf("rebalance/%d", 2)) + if err != nil { + return false + } + } + return false + }) + + // check for redelegations + _, present := app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[3].ValoperAddress, vals[0].ValoperAddress, 2) + s.Require().True(present) + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[3].ValoperAddress, vals[1].ValoperAddress, 2) + s.Require().True(present) + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[3].ValoperAddress, vals[2].ValoperAddress, 2) + s.Require().True(present) + + // change intents to trigger transitive redelegations which should fail rebalance + zone, _ = app.InterchainstakingKeeper.GetZone(ctx, s.chainB.ChainID) + intents = icstypes.ValidatorIntents{ + {ValoperAddress: vals[0].ValoperAddress, Weight: sdk.NewDecWithPrec(1, 1)}, + {ValoperAddress: vals[1].ValoperAddress, Weight: sdk.NewDecWithPrec(3, 1)}, + {ValoperAddress: vals[2].ValoperAddress, Weight: sdk.NewDecWithPrec(3, 1)}, + {ValoperAddress: vals[3].ValoperAddress, Weight: sdk.NewDecWithPrec(3, 1)}, + } + zone.AggregateIntent = intents + + // trigger rebalance + err = app.InterchainstakingKeeper.Rebalance(ctx, zone, 3) + + //check for redelegations originating from val[0], they should not be present + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[0].ValoperAddress, vals[1].ValoperAddress, 3) + s.Require().False(present) + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[0].ValoperAddress, vals[2].ValoperAddress, 3) + s.Require().False(present) + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[0].ValoperAddress, vals[3].ValoperAddress, 3) + s.Require().False(present) +} + +func (s *KeeperTestSuite) TestRebalanceDueToDelegationChange() { + + s.SetupTest() + s.setupTestZones() + + app := s.GetQuicksilverApp(s.chainA) + ctx := s.chainA.GetContext() + + zone, found := app.InterchainstakingKeeper.GetZone(ctx, s.chainB.ChainID) + if !found { + s.Fail("unable to retrieve zone for test") + } + vals := zone.Validators + + delegations := []icstypes.Delegation{ + { + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: vals[0].ValoperAddress, + Amount: sdk.NewCoin("uatom", sdk.NewInt(1000)), + RedelegationEnd: 0, + }, + { + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: vals[1].ValoperAddress, + Amount: sdk.NewCoin("uatom", sdk.NewInt(1000)), + RedelegationEnd: 0, + }, + { + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: vals[2].ValoperAddress, + Amount: sdk.NewCoin("uatom", sdk.NewInt(1000)), + RedelegationEnd: 0, + }, { + DelegationAddress: zone.DelegationAddress.Address, + ValidatorAddress: vals[3].ValoperAddress, + Amount: sdk.NewCoin("uatom", sdk.NewInt(1000)), + RedelegationEnd: 0, + }, + } + for _, delegation := range delegations { + app.InterchainstakingKeeper.SetDelegation(ctx, &zone, delegation) + val, _ := zone.GetValidatorByValoper(delegation.ValidatorAddress) + val.VotingPower = val.VotingPower.Add(delegation.Amount.Amount) + val.DelegatorShares = val.DelegatorShares.Add(sdk.NewDecFromInt(delegation.Amount.Amount)) + } + + app.InterchainstakingKeeper.SetZone(ctx, &zone) + + // trigger rebalance + err := app.InterchainstakingKeeper.Rebalance(ctx, zone, 1) + s.Require().NoError(err) + + app.InterchainstakingKeeper.IterateAllDelegations(ctx, &zone, func(delegation icstypes.Delegation) bool { + if delegation.ValidatorAddress == vals[0].ValoperAddress { + delegation.Amount = delegation.Amount.Add(sdk.NewInt64Coin("uatom", 4000)) + app.InterchainstakingKeeper.SetDelegation(ctx, &zone, delegation) + } + return false + }) + + // trigger rebalance + err = app.InterchainstakingKeeper.Rebalance(ctx, zone, 2) + + // mock ack for redelegations + app.InterchainstakingKeeper.IteratePrefixedRedelegationRecords(ctx, []byte(zone.ChainId), func(idx int64, _ []byte, record icstypes.RedelegationRecord) (stop bool) { + if record.EpochNumber == 2 { + msg := stakingtypes.MsgBeginRedelegate{zone.DelegationAddress.Address, + record.Source, + record.Destination, + sdk.NewCoin("uatom", sdkmath.NewInt(record.Amount))} + err := app.InterchainstakingKeeper.HandleBeginRedelegate(ctx, &msg, time.Now().Add(time.Hour*24*7), fmt.Sprintf("rebalance/%d", 2)) + if err != nil { + return false + } + } + return false + }) + + // check for redelegations + _, present := app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[0].ValoperAddress, vals[2].ValoperAddress, 2) + s.Require().True(present) + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[0].ValoperAddress, vals[3].ValoperAddress, 2) + s.Require().True(present) + + // change validator delegation to trigger transitive redelegations which should fail rebalance + app.InterchainstakingKeeper.IterateAllDelegations(ctx, &zone, func(delegation icstypes.Delegation) bool { + if delegation.ValidatorAddress == vals[0].ValoperAddress { + delegation.Amount = delegation.Amount.Sub(sdk.NewInt64Coin("uatom", 4000)) + app.InterchainstakingKeeper.SetDelegation(ctx, &zone, delegation) + } + if delegation.ValidatorAddress == vals[2].ValoperAddress { + delegation.Amount = delegation.Amount.Add(sdk.NewInt64Coin("uatom", 4000)) + app.InterchainstakingKeeper.SetDelegation(ctx, &zone, delegation) + } + + return false + }) + + // trigger rebalance + err = app.InterchainstakingKeeper.Rebalance(ctx, zone, 3) + + //check for redelegations originating from val[1], they should not be present + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[2].ValoperAddress, vals[0].ValoperAddress, 3) + s.Require().False(present) + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[2].ValoperAddress, vals[1].ValoperAddress, 3) + s.Require().False(present) + _, present = app.InterchainstakingKeeper.GetRedelegationRecord(ctx, zone.ChainId, vals[2].ValoperAddress, vals[3].ValoperAddress, 3) + s.Require().False(present) +} diff --git a/x/interchainstaking/keeper/keeper.go b/x/interchainstaking/keeper/keeper.go index 2e109673d..73116b834 100644 --- a/x/interchainstaking/keeper/keeper.go +++ b/x/interchainstaking/keeper/keeper.go @@ -171,7 +171,6 @@ func SetValidatorsForZone(k *Keeper, ctx sdk.Context, zoneInfo types.Zone, data return err } if validatorsReq.Pagination == nil { - k.Logger(ctx).Info("unmarshalled a QueryValidatorsRequest with a nil Pagination", "zone", zoneInfo.ChainId) validatorsReq.Pagination = new(query.PageRequest) } validatorsReq.Pagination.Key = validatorsRes.Pagination.NextKey @@ -179,7 +178,7 @@ func SetValidatorsForZone(k *Keeper, ctx sdk.Context, zoneInfo types.Zone, data if err != nil { return errors.New("failed to marshal valset pagination request") } - k.Logger(ctx).Info("Found pagination nextKey in valset; resubmitting...") + k.Logger(ctx).Debug("Found pagination nextKey in valset; resubmitting...") k.ICQKeeper.MakeRequest( ctx, @@ -199,16 +198,16 @@ func SetValidatorsForZone(k *Keeper, ctx sdk.Context, zoneInfo types.Zone, data toQuery := false switch { case !found: - k.Logger(ctx).Info("Unable to find validator - fetching proof...", "valoper", validator.OperatorAddress) + k.Logger(ctx).Debug("Unable to find validator - fetching proof...", "valoper", validator.OperatorAddress) toQuery = true case !val.CommissionRate.Equal(validator.GetCommission()): - k.Logger(ctx).Info("Validator commission change; fetching proof", "valoper", validator.OperatorAddress, "from", val.CommissionRate, "to", validator.GetCommission()) + k.Logger(ctx).Debug("Validator commission change; fetching proof", "valoper", validator.OperatorAddress, "from", val.CommissionRate, "to", validator.GetCommission()) toQuery = true case !val.VotingPower.Equal(validator.Tokens): - k.Logger(ctx).Info("Validator voting power change; fetching proof", "valoper", validator.OperatorAddress, "from", val.VotingPower, "to", validator.Tokens) + k.Logger(ctx).Debug("Validator voting power change; fetching proof", "valoper", validator.OperatorAddress, "from", val.VotingPower, "to", validator.Tokens) toQuery = true case !val.DelegatorShares.Equal(validator.DelegatorShares): - k.Logger(ctx).Info("Validator shares amount change; fetching proof", "valoper", validator.OperatorAddress, "from", val.DelegatorShares, "to", validator.DelegatorShares) + k.Logger(ctx).Debug("Validator shares amount change; fetching proof", "valoper", validator.OperatorAddress, "from", val.DelegatorShares, "to", validator.DelegatorShares) toQuery = true } @@ -298,22 +297,22 @@ func SetValidatorForZone(k *Keeper, ctx sdk.Context, zone types.Zone, data []byt } if !val.CommissionRate.Equal(validator.GetCommission()) { - k.Logger(ctx).Info("Validator commission rate change; updating...", "valoper", validator.OperatorAddress, "oldRate", val.CommissionRate, "newRate", validator.GetCommission()) + k.Logger(ctx).Debug("Validator commission rate change; updating...", "valoper", validator.OperatorAddress, "oldRate", val.CommissionRate, "newRate", validator.GetCommission()) val.CommissionRate = validator.GetCommission() } if !val.VotingPower.Equal(validator.Tokens) { - k.Logger(ctx).Info("Validator voting power change; updating", "valoper", validator.OperatorAddress, "oldPower", val.VotingPower, "newPower", validator.Tokens) + k.Logger(ctx).Debug("Validator voting power change; updating", "valoper", validator.OperatorAddress, "oldPower", val.VotingPower, "newPower", validator.Tokens) val.VotingPower = validator.Tokens } if !val.DelegatorShares.Equal(validator.DelegatorShares) { - k.Logger(ctx).Info("Validator delegator shares change; updating", "valoper", validator.OperatorAddress, "oldShares", val.DelegatorShares, "newShares", validator.DelegatorShares) + k.Logger(ctx).Debug("Validator delegator shares change; updating", "valoper", validator.OperatorAddress, "oldShares", val.DelegatorShares, "newShares", validator.DelegatorShares) val.DelegatorShares = validator.DelegatorShares } if val.Status != validator.Status.String() { - k.Logger(ctx).Info("Transitioning validator status", "valoper", validator.OperatorAddress, "previous", val.Status, "current", validator.Status.String()) + k.Logger(ctx).Debug("Transitioning validator status", "valoper", validator.OperatorAddress, "previous", val.Status, "current", validator.Status.String()) val.Status = validator.Status.String() } @@ -340,7 +339,6 @@ func (k Keeper) UpdateWithdrawalRecordsForSlash(ctx sdk.Context, zone types.Zone thisSubAmount := math.NewInt(int64(d.Amount)).Sub(newAmount) recordSubAmount = recordSubAmount.Add(thisSubAmount) d.Amount = newAmount.Uint64() - fmt.Println("Updated withdrawal record due to slashing", "valoper", valoper, "old_amount", d.Amount, "new_amount", newAmount.Int64(), "sub_amount", thisSubAmount.Int64()) k.Logger(ctx).Info("Updated withdrawal record due to slashing", "valoper", valoper, "old_amount", d.Amount, "new_amount", newAmount.Int64(), "sub_amount", thisSubAmount.Int64()) } } @@ -356,7 +354,7 @@ func (k Keeper) depositInterval(ctx sdk.Context) zoneItrFn { return func(index int64, zoneInfo types.Zone) (stop bool) { if zoneInfo.DepositAddress != nil { if !zoneInfo.DepositAddress.Balance.Empty() { - k.Logger(ctx).Info("balance is non zero", "balance", zoneInfo.DepositAddress.Balance) + k.Logger(ctx).Debug("balance is non zero", "balance", zoneInfo.DepositAddress.Balance) req := tx.GetTxsEventRequest{Events: []string{"transfer.recipient='" + zoneInfo.DepositAddress.GetAddress() + "'"}, OrderBy: tx.OrderBy_ORDER_BY_DESC, Pagination: &query.PageRequest{Limit: types.TxRetrieveCount}} k.ICQKeeper.MakeRequest(ctx, zoneInfo.ConnectionId, zoneInfo.ChainId, "cosmos.tx.v1beta1.Service/GetTxsEvent", k.cdc.MustMarshal(&req), sdk.NewInt(-1), types.ModuleName, "depositinterval", 0) @@ -519,9 +517,9 @@ func (k *Keeper) GetRatio(ctx sdk.Context, zone types.Zone, epochRewards math.In } func (k *Keeper) Rebalance(ctx sdk.Context, zone types.Zone, epochNumber int64) error { - currentAllocations, currentSum := k.GetDelegationMap(ctx, &zone) + currentAllocations, currentSum, currentLocked := k.GetDelegationMap(ctx, &zone) targetAllocations := zone.GetAggregateIntentOrDefault() - rebalances := DetermineAllocationsForRebalancing(currentAllocations, currentSum, targetAllocations, k.ZoneRedelegationRecords(ctx, zone.ChainId), k.Logger(ctx)) + rebalances := DetermineAllocationsForRebalancing(currentAllocations, currentLocked, currentSum, targetAllocations, k.ZoneRedelegationRecords(ctx, zone.ChainId), k.Logger(ctx)) msgs := make([]sdk.Msg, 0) for _, rebalance := range rebalances { msgs = append(msgs, &stakingTypes.MsgBeginRedelegate{DelegatorAddress: zone.DelegationAddress.Address, ValidatorSrcAddress: rebalance.Source, ValidatorDstAddress: rebalance.Target, Amount: sdk.NewCoin(zone.BaseDenom, rebalance.Amount)}) @@ -537,7 +535,7 @@ func (k *Keeper) Rebalance(ctx sdk.Context, zone types.Zone, epochNumber int64) k.Logger(ctx).Info("No rebalancing required") return nil } - k.Logger(ctx).Info("Send rebalancing messages", "msgs", msgs) + k.Logger(ctx).Debug("Send rebalancing messages", "msgs", msgs) return k.SubmitTx(ctx, msgs, zone.DelegationAddress, fmt.Sprintf("rebalance/%d", epochNumber)) } @@ -547,7 +545,7 @@ type RebalanceTarget struct { Target string } -func DetermineAllocationsForRebalancing(currentAllocations map[string]math.Int, currentSum math.Int, targetAllocations types.ValidatorIntents, existingRedelegations []types.RedelegationRecord, log log.Logger) []RebalanceTarget { +func DetermineAllocationsForRebalancing(currentAllocations map[string]math.Int, currentLocked map[string]bool, currentSum math.Int, targetAllocations types.ValidatorIntents, existingRedelegations []types.RedelegationRecord, log log.Logger) []RebalanceTarget { out := make([]RebalanceTarget, 0) deltas := CalculateDeltas(currentAllocations, currentSum, targetAllocations) @@ -564,6 +562,18 @@ func DetermineAllocationsForRebalancing(currentAllocations map[string]math.Int, } lockedPerValidator[redelegation.Destination] = thisLocked + redelegation.Amount } + for _, valoper := range utils.Keys(currentAllocations) { + // if validator already has a redelegation _to_ it, we can no longer redelegate _from_ it (transitive redelegations) + // remove _locked_ amount from lpv and total locked for purposes of rebalancing. + if currentLocked[valoper] { + thisLocked, found := lockedPerValidator[valoper] + if !found { + thisLocked = 0 + } + totalLocked = totalLocked - thisLocked + currentAllocations[valoper].Int64() + lockedPerValidator[valoper] = currentAllocations[valoper].Int64() + } + } // TODO: make these params maxCanRebalanceTotal := currentSum.Sub(math.NewInt(totalLocked)).Quo(sdk.NewInt(2)) @@ -572,16 +582,7 @@ func DetermineAllocationsForRebalancing(currentAllocations map[string]math.Int, log.Debug("Rebalancing", "totalLocked", totalLocked, "lockedPerValidator", lockedPerValidator, "canRebalanceTotal", maxCanRebalanceTotal, "canRebalanceEpoch", maxCanRebalance) } - // sort keys by relative value of delta - sort.SliceStable(deltas, func(i, j int) bool { - return deltas[i].ValoperAddress < deltas[j].ValoperAddress - }) - - // sort keys by relative value of delta - sort.SliceStable(deltas, func(i, j int) bool { - return deltas[i].Weight.GT(deltas[j].Weight) - }) - + // deltas are sorted in CalculateDeltas; don't re-sort. for _, delta := range deltas { switch { case delta.Weight.IsZero(): diff --git a/x/interchainstaking/keeper/proposal_handler.go b/x/interchainstaking/keeper/proposal_handler.go index 9b7f07db8..cd17de260 100644 --- a/x/interchainstaking/keeper/proposal_handler.go +++ b/x/interchainstaking/keeper/proposal_handler.go @@ -238,7 +238,7 @@ func HandleUpdateZoneProposal(ctx sdk.Context, k Keeper, p *types.UpdateZoneProp } default: - return errors.New("unexpected key") + return fmt.Errorf("unexpected key '%s'", change.Key) } } k.SetZone(ctx, &zone) diff --git a/x/interchainstaking/keeper/redemptions.go b/x/interchainstaking/keeper/redemptions.go index 67c866277..c0827595a 100644 --- a/x/interchainstaking/keeper/redemptions.go +++ b/x/interchainstaking/keeper/redemptions.go @@ -2,10 +2,13 @@ package keeper import ( "errors" + "fmt" + "sort" "time" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/ingenuity-build/quicksilver/utils" "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" lsmstakingtypes "github.com/iqlusioninc/liquidity-staking-module/x/staking/types" @@ -25,11 +28,11 @@ func (k *Keeper) processRedemptionForLsm(ctx sdk.Context, zone types.Zone, sende outstanding := nativeTokens distribution := make(map[string]uint64, 0) - availablePerValidator := k.GetUnlockedTokensForZone(ctx, &zone) + availablePerValidator, _ := k.GetUnlockedTokensForZone(ctx, &zone) for _, intent := range intents.Sort() { thisAmount := intent.Weight.MulInt(nativeTokens).TruncateInt() - if thisAmount.Int64() > availablePerValidator[intent.ValoperAddress] { + if thisAmount.GT(availablePerValidator[intent.ValoperAddress]) { return errors.New("unable to satisfy unbond request; delegations may be locked") } distribution[intent.ValoperAddress] = thisAmount.Uint64() @@ -68,21 +71,6 @@ func (k *Keeper) queueRedemption( hash string, ) error { //nolint:unparam // we know that the error is always nil distribution := make([]*types.Distribution, 0) - outstanding := nativeTokens - - aggregateIntent := zone.GetAggregateIntentOrDefault() - for _, intent := range aggregateIntent { - thisAmount := intent.Weight.MulInt(nativeTokens).TruncateInt() - outstanding = outstanding.Sub(thisAmount) - dist := types.Distribution{ - Valoper: intent.ValoperAddress, - Amount: thisAmount.Uint64(), - } - - distribution = append(distribution, &dist) - } - // handle dust ? ok to do uint64 calc here or do we use math.Int (just more verbose) ? - distribution[0].Amount += outstanding.Uint64() amount := sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, nativeTokens)) k.AddWithdrawalRecord( @@ -100,3 +88,285 @@ func (k *Keeper) queueRedemption( return nil } + +// GetUnlockedTokensForZone will iterate over all delegation records for a zone, and then remove the +// locked tokens (those actively being redelegated), returning a slice of int64 staking tokens that +// are unlocked and free to redelegate or unbond. +func (k *Keeper) GetUnlockedTokensForZone(ctx sdk.Context, zone *types.Zone) (map[string]math.Int, math.Int) { + availablePerValidator := make(map[string]math.Int, len(zone.Validators)) + total := sdk.ZeroInt() + for _, delegation := range k.GetAllDelegations(ctx, zone) { + thisAvailable, found := availablePerValidator[delegation.ValidatorAddress] + if !found { + thisAvailable = sdk.ZeroInt() + } + availablePerValidator[delegation.ValidatorAddress] = thisAvailable.Add(delegation.Amount.Amount) + total = total.Add(delegation.Amount.Amount) + } + for _, redelegation := range k.ZoneRedelegationRecords(ctx, zone.ChainId) { + thisAvailable, found := availablePerValidator[redelegation.Destination] + if found { + availablePerValidator[redelegation.Destination] = thisAvailable.Sub(sdk.NewInt(redelegation.Amount)) + } + total.Sub(sdk.NewInt(redelegation.Amount)) + } + return availablePerValidator, total +} + +// handle queued unbondings is called once per epoch to aggregate all queued unbondings into +// a single unbond transaction per delegation. +func (k *Keeper) HandleQueuedUnbondings(ctx sdk.Context, zone *types.Zone, epoch int64) error { + // out here will only ever be in native bond denom + out := make(map[string]sdk.Coin, 0) + txhashes := make(map[string][]string, 0) + + totalToWithdraw := sdk.NewCoin(zone.BaseDenom, sdk.ZeroInt()) + distributions := make(map[string][]*types.Distribution, 0) + amounts := make(map[string]sdk.Coin, 0) + _, totalAvailable := k.GetUnlockedTokensForZone(ctx, zone) + + k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusQueued, func(idx int64, withdrawal types.WithdrawalRecord) bool { + k.Logger(ctx).Info("handling queued withdrawal request", "from", withdrawal.Delegator, "to", withdrawal.Recipient, "amount", withdrawal.Amount) + if len(withdrawal.Amount) == 0 { + k.Logger(ctx).Error("withdrawal %s has no amount set; cannot process...", withdrawal.Txhash) + return false + } + if totalAvailable.LT(totalToWithdraw.Amount.Add(withdrawal.Amount[0].Amount)) { + k.Logger(ctx).Error("unable to satisfy further unbondings this epoch") + // do not process this or subsequent withdrawals this epoch. + return true + } + totalToWithdraw = totalToWithdraw.Add(withdrawal.Amount[0]) + + amounts[withdrawal.Txhash] = withdrawal.Amount[0] + distributions[withdrawal.Txhash] = make([]*types.Distribution, 0) + return false + }) + + // no undelegations to attempt + if totalToWithdraw.IsZero() { + return nil + } + + allocations := k.DeterminePlanForUndelegation(ctx, zone, sdk.NewCoins(totalToWithdraw)) + valopers := utils.Keys(allocations) + vidx := 0 + v := valopers[vidx] +WITHDRAWAL: + for _, hash := range utils.Keys(amounts) { + for { + fmt.Println(amounts[hash].Amount) + if amounts[hash].Amount.IsZero() { + continue WITHDRAWAL + } + if allocations[v].GT(amounts[hash].Amount) { + allocations[v] = allocations[v].Sub(amounts[hash].Amount) + distributions[hash] = append(distributions[hash], &types.Distribution{Valoper: v, Amount: amounts[hash].Amount.Uint64()}) + existing, found := out[v] + if !found { + out[v] = amounts[hash] + txhashes[v] = []string{hash} + + } else { + out[v] = existing.Add(amounts[hash]) + txhashes[v] = append(txhashes[v], hash) + } + amounts[hash] = sdk.NewCoin(amounts[hash].Denom, sdk.ZeroInt()) + continue WITHDRAWAL + } else { + distributions[hash] = append(distributions[hash], &types.Distribution{Valoper: v, Amount: allocations[v].Uint64()}) + amounts[hash] = sdk.NewCoin(amounts[hash].Denom, amounts[hash].Amount.Sub(allocations[v])) + existing, found := out[v] + if !found { + out[v] = sdk.NewCoin(zone.BaseDenom, allocations[v]) + txhashes[v] = []string{hash} + + } else { + out[v] = existing.Add(sdk.NewCoin(zone.BaseDenom, allocations[v])) + txhashes[v] = append(txhashes[v], hash) + } + allocations[v] = sdk.ZeroInt() + } + if allocations[v].IsZero() { + fmt.Println("valopers len", len(valopers)) + fmt.Println("vidx+1", vidx+1) + if len(valopers) > vidx+1 { + vidx++ + v = valopers[vidx] + } else { + if !amounts[hash].Amount.IsZero() { + return fmt.Errorf("unable to satisfy unbonding") + } + continue WITHDRAWAL + } + } + } + } + + for _, hash := range utils.Keys(distributions) { + record, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, WithdrawStatusQueued) + if !found { + return errors.New("unable to find withdrawal record") + } + record.Distribution = distributions[hash] + k.UpdateWithdrawalRecordStatus(ctx, &record, WithdrawStatusUnbond) + } + + if len(txhashes) == 0 { + // no records to handle. + return nil + } + + var msgs []sdk.Msg + for _, valoper := range utils.Keys(out) { + if !out[valoper].Amount.IsZero() { + sort.Strings(txhashes[valoper]) + k.SetUnbondingRecord(ctx, types.UnbondingRecord{ChainId: zone.ChainId, EpochNumber: epoch, Validator: valoper, RelatedTxhash: txhashes[valoper]}) + msgs = append(msgs, &stakingtypes.MsgUndelegate{DelegatorAddress: zone.DelegationAddress.Address, ValidatorAddress: valoper, Amount: out[valoper]}) + } + } + + k.Logger(ctx).Info("unbonding messages to send", "msg", msgs) + + return k.SubmitTx(ctx, msgs, zone.DelegationAddress, fmt.Sprintf("withdrawal/%d", epoch)) +} + +func (k *Keeper) GCCompletedUnbondings(ctx sdk.Context, zone *types.Zone) error { + var err error + + k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusCompleted, func(idx int64, withdrawal types.WithdrawalRecord) bool { + if ctx.BlockTime().After(withdrawal.CompletionTime.Add(24 * time.Hour)) { + k.Logger(ctx).Info("garbage collecting completed unbondings") + k.DeleteWithdrawalRecord(ctx, zone.ChainId, withdrawal.Txhash, WithdrawStatusCompleted) + } + return false + }) + + return err +} + +func (k Keeper) DeterminePlanForUndelegation(ctx sdk.Context, zone *types.Zone, amount sdk.Coins) map[string]math.Int { + currentAllocations, currentSum, _ := k.GetDelegationMap(ctx, zone) + availablePerValidator, _ := k.GetUnlockedTokensForZone(ctx, zone) + targetAllocations := zone.GetAggregateIntentOrDefault() + allocations := DetermineAllocationsForUndelegation(currentAllocations, currentSum, targetAllocations, availablePerValidator, amount) + return allocations +} + +func DetermineAllocationsForUndelegation(currentAllocations map[string]math.Int, currentSum math.Int, targetAllocations types.ValidatorIntents, availablePerValidator map[string]math.Int, amount sdk.Coins) map[string]math.Int { + input := amount[0].Amount + deltas := CalculateDeltas(currentAllocations, currentSum.Sub(input), targetAllocations) + sum := sdk.ZeroInt() + outSum := sdk.ZeroInt() + outWeights := make(map[string]math.Int) + + // deltas: +ve is below target; -ve is above target. + + // q1: can we satisfy this unbonding using _just_ above target allocations. + // example: + // we have v1: 5000, v2: 1800; v3: 1200; v4: 1000 and targets of 50%, 20%, 15% and 5% respectively. + // deltas == 500, 0, -150, 550 + // an unbonding of 300 should come from v1, v4 (as they has an excess of > unbond amount) _before_ touching anything else. + + for idx := range deltas { + if deltas[idx].Weight.IsNegative() { + sum = sum.Add(deltas[idx].Weight.TruncateInt().Abs()) + } + } + + overAllocationSplit := sdk.MinInt(sum, input) + if !overAllocationSplit.IsZero() { + for idx := range deltas { + if deltas[idx].Weight.IsNegative() { + fmt.Println("trying to remove from overallocated", deltas[idx].ValoperAddress) + outWeights[deltas[idx].ValoperAddress] = deltas[idx].Weight.Quo(sdk.NewDecFromInt(sum)).Mul(sdk.NewDecFromInt(overAllocationSplit)).TruncateInt().Abs() + if outWeights[deltas[idx].ValoperAddress].GT(availablePerValidator[deltas[idx].ValoperAddress]) { + outWeights[deltas[idx].ValoperAddress] = availablePerValidator[deltas[idx].ValoperAddress] + availablePerValidator[deltas[idx].ValoperAddress] = sdk.ZeroInt() + } else { + availablePerValidator[deltas[idx].ValoperAddress] = availablePerValidator[deltas[idx].ValoperAddress].Sub(outWeights[deltas[idx].ValoperAddress]) + } + fmt.Println("removed from overallocated", outWeights[deltas[idx].ValoperAddress]) + deltas[idx].Weight = deltas[idx].Weight.Add(sdk.NewDecFromInt(outWeights[deltas[idx].ValoperAddress])) + outSum = outSum.Add(outWeights[deltas[idx].ValoperAddress]) + } + } + } + input = input.Sub(outSum) + if input.IsZero() { + return outWeights + } + + maxValue := maxDeltas(deltas) + sum = sdk.ZeroInt() + + // drop all deltas such that the maximum value is zero, and invert. + for idx := range deltas { + deltas[idx].Weight = deltas[idx].Weight.Sub(sdk.NewDecFromInt(maxValue)).Abs() + sum = sum.Add(deltas[idx].Weight.TruncateInt().Abs()) + } + + // unequalSplit is the portion of input that should be distributed in attempt to make targets == 0 + unequalSplit := sdk.MinInt(sum, input) + + if !unequalSplit.IsZero() { + for idx := range deltas { + allocation := deltas[idx].Weight.Quo(sdk.NewDecFromInt(sum)).Mul(sdk.NewDecFromInt(unequalSplit)) + _, ok := availablePerValidator[deltas[idx].ValoperAddress] + if !ok { + availablePerValidator[deltas[idx].ValoperAddress] = sdk.ZeroInt() + } + if allocation.TruncateInt().GT(availablePerValidator[deltas[idx].ValoperAddress]) { + allocation = sdk.NewDecFromInt(availablePerValidator[deltas[idx].ValoperAddress]) + availablePerValidator[deltas[idx].ValoperAddress] = sdk.ZeroInt() + } else { + availablePerValidator[deltas[idx].ValoperAddress] = availablePerValidator[deltas[idx].ValoperAddress].Sub(allocation.TruncateInt()) + } + + deltas[idx].Weight = deltas[idx].Weight.Sub(allocation) + value, ok := outWeights[deltas[idx].ValoperAddress] + if !ok { + value = sdk.ZeroInt() + } + + outWeights[deltas[idx].ValoperAddress] = value.Add(allocation.TruncateInt()) + outSum = outSum.Add(allocation.TruncateInt()) + input = input.Sub(allocation.TruncateInt()) + } + } + + // equalSplit is the portion of input that should be distributed equally across all validators, once targets are met. + + if !outSum.Equal(amount[0].Amount) { + each := sdk.NewDecFromInt(input).Quo(sdk.NewDec(int64(len(deltas)))) + for idx := range deltas { + value, ok := outWeights[deltas[idx].ValoperAddress] + if !ok { + value = sdk.ZeroInt() + } + if each.TruncateInt().GT(availablePerValidator[deltas[idx].ValoperAddress]) { + each = sdk.NewDecFromInt(availablePerValidator[deltas[idx].ValoperAddress]) + availablePerValidator[deltas[idx].ValoperAddress] = sdk.ZeroInt() + } else { + availablePerValidator[deltas[idx].ValoperAddress] = availablePerValidator[deltas[idx].ValoperAddress].Sub(each.TruncateInt()) + } + outWeights[deltas[idx].ValoperAddress] = value.Add(each.TruncateInt()) + outSum = outSum.Add(each.TruncateInt()) + input = input.Sub(each.TruncateInt()) + } + } + + // dust is the portion of the input that was truncated in previous calculations; add this to the last validator in the list, + // which should be the biggest source. This will always be a small amount, and will count toward the delta calculations on the next run. + dust := amount[0].Amount.Sub(outSum) + for idx := len(deltas) - 1; idx >= 0; idx-- { + if dust.GT(availablePerValidator[deltas[idx].ValoperAddress]) { + continue + } else { + outWeights[deltas[idx].ValoperAddress] = outWeights[deltas[idx].ValoperAddress].Add(dust) + break + } + } + + return outWeights +} diff --git a/x/interchainstaking/keeper/redemptions_test.go b/x/interchainstaking/keeper/redemptions_test.go new file mode 100644 index 000000000..01055dac1 --- /dev/null +++ b/x/interchainstaking/keeper/redemptions_test.go @@ -0,0 +1,240 @@ +package keeper + +import ( + "fmt" + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" + "github.com/stretchr/testify/require" +) + +func TestDetermineAllocationsForUndelegation(t *testing.T) { + v1 := "cosmosvaloper1f9xf8pl9ev5e6amuec9680scqhpyd85ee25q5y90uqpxdcdfmufsal5nd0" + v2 := "cosmosvaloper1345w0hf2x4c5vdcm4wmj38pn26z0pmgvvjj8s0tplj87cxegw34qu8f6l1" + v3 := "cosmosvaloper1fslnzgde7z8mexm9y3evcy9a8t9km0lshtr92a2jsq3mhtku789qy62jg2" + v4 := "cosmosvaloper1vx4el3dyqzucc3jhc6leaxt8gg9sar78elrce7wvyqsk9uu2d99slwapz3" + tests := []struct { + name string + currentAllocations map[string]math.Int + unlocked map[string]math.Int + targetAllocations types.ValidatorIntents + amount sdk.Coins + expected map[string]math.Int + }{ + { + name: "equal delegations, equal intents; no locked", + currentAllocations: map[string]math.Int{ + v1: sdk.NewInt(1000), + v2: sdk.NewInt(1000), + v3: sdk.NewInt(1000), + v4: sdk.NewInt(1000), + }, + unlocked: map[string]math.Int{ + v1: sdk.NewInt(1000), + v2: sdk.NewInt(1000), + v3: sdk.NewInt(1000), + v4: sdk.NewInt(1000), + }, + targetAllocations: types.ValidatorIntents{ + &types.ValidatorIntent{ValoperAddress: v1, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v2, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v3, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v4, Weight: sdk.NewDecWithPrec(25, 2)}, + }, + amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(1000))), + expected: map[string]math.Int{ + v1: sdk.NewInt(250), + v2: sdk.NewInt(250), + v3: sdk.NewInt(250), + v4: sdk.NewInt(250), + }, + }, + { + name: "unequal delegations, equal intents; no locked", + currentAllocations: map[string]math.Int{ + v1: sdk.NewInt(1000), // + 25 + v2: sdk.NewInt(950), // -25 + v3: sdk.NewInt(1200), // + 225 + v4: sdk.NewInt(750), // -225 + // 250; 0, -25, 0, -225; 225, 200, 225, 0; 650 (275, 225, 475, 25) + }, + unlocked: map[string]math.Int{ + v1: sdk.NewInt(1000), + v2: sdk.NewInt(950), + v3: sdk.NewInt(1200), + v4: sdk.NewInt(750), + }, + targetAllocations: types.ValidatorIntents{ + &types.ValidatorIntent{ValoperAddress: v1, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v2, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v3, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v4, Weight: sdk.NewDecWithPrec(25, 2)}, + }, + amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(1000))), + expected: map[string]math.Int{ + v1: sdk.NewInt(275), + v2: sdk.NewInt(225), + v3: sdk.NewInt(475), + v4: sdk.NewInt(25), + }, + }, + { + name: "unequal delegations, unequal intents; no locked", + currentAllocations: map[string]math.Int{ + v1: sdk.NewInt(5000), + v2: sdk.NewInt(1800), + v3: sdk.NewInt(1200), + v4: sdk.NewInt(1000), + }, + unlocked: map[string]math.Int{ + v1: sdk.NewInt(5000), + v2: sdk.NewInt(1800), + v3: sdk.NewInt(1200), + v4: sdk.NewInt(1000), + }, + targetAllocations: types.ValidatorIntents{ + &types.ValidatorIntent{ValoperAddress: v1, Weight: sdk.NewDecWithPrec(50, 2)}, + &types.ValidatorIntent{ValoperAddress: v2, Weight: sdk.NewDecWithPrec(20, 2)}, + &types.ValidatorIntent{ValoperAddress: v3, Weight: sdk.NewDecWithPrec(15, 2)}, + &types.ValidatorIntent{ValoperAddress: v4, Weight: sdk.NewDecWithPrec(5, 2)}, + }, + amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(300))), + expected: map[string]math.Int{ + v1: sdk.NewInt(154), + v2: sdk.NewInt(14), + v3: sdk.NewInt(0), + v4: sdk.NewInt(132), + }, + }, + { + name: "unequal delegations, unequal intents, big discrepancy in intent (should not take from underallocated); no locked", + currentAllocations: map[string]math.Int{ + v1: sdk.NewInt(1234), + v2: sdk.NewInt(675), + v3: sdk.NewInt(210), + v4: sdk.NewInt(401), + }, + unlocked: map[string]math.Int{ + v1: sdk.NewInt(1234), + v2: sdk.NewInt(675), + v3: sdk.NewInt(210), + v4: sdk.NewInt(401), + }, + targetAllocations: types.ValidatorIntents{ + &types.ValidatorIntent{ValoperAddress: v1, Weight: sdk.NewDecWithPrec(10, 2)}, + &types.ValidatorIntent{ValoperAddress: v2, Weight: sdk.NewDecWithPrec(20, 2)}, + &types.ValidatorIntent{ValoperAddress: v3, Weight: sdk.NewDecWithPrec(30, 2)}, + &types.ValidatorIntent{ValoperAddress: v4, Weight: sdk.NewDecWithPrec(40, 2)}, + }, + amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(100))), + expected: map[string]math.Int{ + v1: sdk.NewInt(84), + v2: sdk.NewInt(16), + v3: sdk.NewInt(0), + v4: sdk.NewInt(0), + }, + }, + { + name: "equal delegations, equal intents; v1 partially locked", + currentAllocations: map[string]math.Int{ + v1: sdk.NewInt(1000), + v2: sdk.NewInt(1000), + v3: sdk.NewInt(1000), + v4: sdk.NewInt(1000), + }, + unlocked: map[string]math.Int{ + v1: sdk.NewInt(500), + v2: sdk.NewInt(1000), + v3: sdk.NewInt(1000), + v4: sdk.NewInt(1000), + }, + targetAllocations: types.ValidatorIntents{ + &types.ValidatorIntent{ValoperAddress: v1, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v2, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v3, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v4, Weight: sdk.NewDecWithPrec(25, 2)}, + }, + amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(1000))), + expected: map[string]math.Int{ + v1: sdk.NewInt(250), + v2: sdk.NewInt(250), + v3: sdk.NewInt(250), + v4: sdk.NewInt(250), + }, + }, + { + name: "equal delegations, equal intents; v1 partially locked #2", + currentAllocations: map[string]math.Int{ + v1: sdk.NewInt(1000), + v2: sdk.NewInt(1000), + v3: sdk.NewInt(1000), + v4: sdk.NewInt(1000), + }, + unlocked: map[string]math.Int{ + v1: sdk.NewInt(200), + v2: sdk.NewInt(1000), + v3: sdk.NewInt(1000), + v4: sdk.NewInt(1000), + }, + targetAllocations: types.ValidatorIntents{ + &types.ValidatorIntent{ValoperAddress: v1, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v2, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v3, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v4, Weight: sdk.NewDecWithPrec(25, 2)}, + }, + amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(1000))), + expected: map[string]math.Int{ + v1: sdk.NewInt(200), + v2: sdk.NewInt(276), + v3: sdk.NewInt(262), + v4: sdk.NewInt(262), + }, + }, + { + name: "equal delegations, equal intents; v1 completely locked", + currentAllocations: map[string]math.Int{ + v1: sdk.NewInt(1000), + v2: sdk.NewInt(1000), + v3: sdk.NewInt(1000), + v4: sdk.NewInt(1000), + }, + unlocked: map[string]math.Int{ + v1: sdk.NewInt(0), + v2: sdk.NewInt(1000), + v3: sdk.NewInt(1000), + v4: sdk.NewInt(1000), + }, + targetAllocations: types.ValidatorIntents{ + &types.ValidatorIntent{ValoperAddress: v1, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v2, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v3, Weight: sdk.NewDecWithPrec(25, 2)}, + &types.ValidatorIntent{ValoperAddress: v4, Weight: sdk.NewDecWithPrec(25, 2)}, + }, + amount: sdk.NewCoins(sdk.NewCoin("uatom", sdk.NewInt(1000))), + expected: map[string]math.Int{ + v1: sdk.NewInt(0), + v2: sdk.NewInt(376), + v3: sdk.NewInt(312), + v4: sdk.NewInt(312), + }, + }, + } + for testidx, tt := range tests { + sum := func(in map[string]math.Int) math.Int { + out := sdk.ZeroInt() + for _, i := range in { + out = out.Add(i) + } + return out + } + fmt.Printf("=============== case %d ===============\n", testidx) + allocations := DetermineAllocationsForUndelegation(tt.currentAllocations, sum(tt.currentAllocations), tt.targetAllocations, tt.unlocked, tt.amount) + for valoper := range allocations { + require.Equal(t, tt.expected[valoper].Int64(), allocations[valoper].Int64(), fmt.Sprintf("%s (%d) / %s", tt.name, testidx, valoper)) + } + // validate that the amount withdrawn always matches total amount. + require.Equal(t, tt.amount[0].Amount, sum(allocations)) + } +} diff --git a/x/interchainstaking/keeper/withdrawal_record.go b/x/interchainstaking/keeper/withdrawal_record.go index 3a812db61..eac2a9215 100644 --- a/x/interchainstaking/keeper/withdrawal_record.go +++ b/x/interchainstaking/keeper/withdrawal_record.go @@ -20,6 +20,21 @@ const ( WithdrawStatusCompleted int32 = iota + 1 ) +func (k Keeper) GetNextWithdrawalRecordSequence(ctx sdk.Context) (sequence uint64) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), nil) + bz := store.Get(types.KeyPrefixRequeuedWithdrawalRecordSeq) + if bz == nil { + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, uint64(2)) + store.Set(types.KeyPrefixRequeuedWithdrawalRecordSeq, bz) + return 1 + } + sequence = binary.BigEndian.Uint64(bz) + binary.BigEndian.PutUint64(bz, sequence+1) + store.Set(types.KeyPrefixRequeuedWithdrawalRecordSeq, bz) + return sequence +} + func (k Keeper) AddWithdrawalRecord(ctx sdk.Context, chainID string, delegator string, distribution []*types.Distribution, recipient string, amount sdk.Coins, burnAmount sdk.Coin, hash string, status int32, completionTime time.Time) { record := types.WithdrawalRecord{ChainId: chainID, Delegator: delegator, Distribution: distribution, Recipient: recipient, Amount: amount, Status: status, BurnAmount: burnAmount, Txhash: hash, CompletionTime: completionTime} k.Logger(ctx).Error("addWithdrawalRecord", "record", record) diff --git a/x/interchainstaking/keeper/zones.go b/x/interchainstaking/keeper/zones.go index 97b824237..1444af63f 100644 --- a/x/interchainstaking/keeper/zones.go +++ b/x/interchainstaking/keeper/zones.go @@ -3,6 +3,7 @@ package keeper import ( "errors" "fmt" + "math" "strings" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -12,9 +13,9 @@ import ( distrTypes "github.com/cosmos/cosmos-sdk/x/distribution/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" - icatypes "github.com/cosmos/ibc-go/v5/modules/apps/27-interchain-accounts/types" + icqtypes "github.com/ingenuity-build/quicksilver/x/interchainquery/types" + "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) // GetZone returns zone info by chainID @@ -408,5 +409,95 @@ func (k *Keeper) CollectStatsForZone(ctx sdk.Context, zone *types.Zone) *types.S return false }) out.Supply = k.BankKeeper.GetSupply(ctx, zone.LocalDenom).Amount.Int64() + out.DistanceToTarget = fmt.Sprintf("%f", k.DistanceToTarget(ctx, zone)) return out } + +func (k *Keeper) RemoveZoneAndAssociatedRecords(ctx sdk.Context, chainID string) { + // clear unbondings + k.IteratePrefixedUnbondingRecords(ctx, []byte(chainID), func(_ int64, record types.UnbondingRecord) (stop bool) { + k.DeleteUnbondingRecord(ctx, record.ChainId, record.Validator, record.EpochNumber) + return false + }) + + // clear redelegations + k.IteratePrefixedRedelegationRecords(ctx, []byte(chainID), func(_ int64, _ []byte, record types.RedelegationRecord) (stop bool) { + k.DeleteRedelegationRecord(ctx, record.ChainId, record.Source, record.Destination, record.EpochNumber) + return false + }) + + // remove zone and related records + k.IterateZones(ctx, func(index int64, zone types.Zone) (stop bool) { + if zone.ChainId == chainID { + // remove uni-5 delegation records + k.IterateAllDelegations(ctx, &zone, func(delegation types.Delegation) (stop bool) { + err := k.RemoveDelegation(ctx, &zone, delegation) + if err != nil { + panic(err) + } + return false + }) + + // remove performance delegation records + k.IterateAllPerformanceDelegations(ctx, &zone, func(delegation types.Delegation) (stop bool) { + err := k.RemoveDelegation(ctx, &zone, delegation) + if err != nil { + panic(err) + } + return false + }) + // remove receipts + k.IterateZoneReceipts(ctx, &zone, func(index int64, receiptInfo types.Receipt) (stop bool) { + k.DeleteReceipt(ctx, GetReceiptKey(receiptInfo.ChainId, receiptInfo.Txhash)) + return false + }) + + // remove withdrawal records + k.IterateZoneWithdrawalRecords(ctx, zone.ChainId, func(index int64, record types.WithdrawalRecord) (stop bool) { + k.DeleteWithdrawalRecord(ctx, zone.ChainId, record.Txhash, record.Status) + return false + }) + + k.DeleteZone(ctx, zone.ChainId) + + } + return false + }) + + // remove queries in state + k.ICQKeeper.IterateQueries(ctx, func(_ int64, queryInfo icqtypes.Query) (stop bool) { + if queryInfo.ChainId == chainID { + k.ICQKeeper.DeleteQuery(ctx, queryInfo.Id) + } + return false + }) +} + +func (k *Keeper) CurrentDelegationsAsIntent(ctx sdk.Context, zone *types.Zone) types.ValidatorIntents { + currentDelegations := k.GetAllDelegations(ctx, zone) + intents := make(types.ValidatorIntents, 0) + for _, d := range currentDelegations { + intents = append(intents, &types.ValidatorIntent{ValoperAddress: d.ValidatorAddress, Weight: sdk.NewDecFromInt(d.Amount.Amount)}) + } + + return intents.Normalize() +} + +func (k *Keeper) DistanceToTarget(ctx sdk.Context, zone *types.Zone) float64 { + current := k.CurrentDelegationsAsIntent(ctx, zone) + target := zone.GetAggregateIntentOrDefault() + preSqRt := sdk.ZeroDec() + + for _, valoper := range zone.Validators { + c := current.MustGetForValoper(valoper.ValoperAddress) + t := target.MustGetForValoper(valoper.ValoperAddress) + v := c.Weight.SubMut(t.Weight) + preSqRt = preSqRt.AddMut(v.Mul(v)) + } + + psqrtf, err := preSqRt.Float64() + if err != nil { + panic("this value should never be greater than 64-bit dec!") + } + return math.Sqrt(psqrtf) +} diff --git a/x/interchainstaking/spec/README.md b/x/interchainstaking/spec/README.md index e2f61dfb5..d450aa53b 100644 --- a/x/interchainstaking/spec/README.md +++ b/x/interchainstaking/spec/README.md @@ -104,37 +104,37 @@ type Zone struct { } ``` -* **ConnectionId** - remote zone connection identifier; -* **ChainId** - remote zone identifier; -* **DepositAddress** - remote zone deposit address; -* **WithdrawalAddress** - remote zone withdrawal address; -* **PerformanceAddress** - remote zone performance address (each validator gets +- **ConnectionId** - remote zone connection identifier; +- **ChainId** - remote zone identifier; +- **DepositAddress** - remote zone deposit address; +- **WithdrawalAddress** - remote zone withdrawal address; +- **PerformanceAddress** - remote zone performance address (each validator gets an exact equal delegation from this account to measure performance); -* **DelegationAddresses** - remote zone delegation addresses to represent +- **DelegationAddresses** - remote zone delegation addresses to represent granular voting power; -* **AccountPrefix** - remote zone account address prefix; -* **LocalDenom** - protocol denomination (qAsset), e.g. uqatom; -* **BaseDenom** - remote zone denomination (uStake), e.g. uatom; -* **RedemptionRate** - redemption rate between protocol qAsset and native +- **AccountPrefix** - remote zone account address prefix; +- **LocalDenom** - protocol denomination (qAsset), e.g. uqatom; +- **BaseDenom** - remote zone denomination (uStake), e.g. uatom; +- **RedemptionRate** - redemption rate between protocol qAsset and native remote asset; -* **LastRedemptionRate** - redemption rate as at previous epoch boundary +- **LastRedemptionRate** - redemption rate as at previous epoch boundary (used to prevent epoch boundary gaming); -* **Validators** - list of validators on the remote zone; -* **AggregateIntent** - the aggregated delegation intent of the protocol for +- **Validators** - list of validators on the remote zone; +- **AggregateIntent** - the aggregated delegation intent of the protocol for this remote zone. The map key is the corresponding validator address contained in the `ValidatorIntent`; -* **MultiSend** - multisend support on remote zone; -* **LiquidityModule** - liquidity module enabled on remote zone; -* **WithdrawalWaitgroup** - tally of pending withdrawal transactions; -* **IbcNextValidatorHash** - -* **ValidatorSelectionAllocation** - proportional zone rewards allocation for +- **MultiSend** - multisend support on remote zone; deprecated; +- **LiquidityModule** - liquidity module enabled on remote zone; +- **WithdrawalWaitgroup** - tally of pending withdrawal transactions; +- **IbcNextValidatorHash** - +- **ValidatorSelectionAllocation** - proportional zone rewards allocation for validator selection; -* **HoldingsAllocation** - proportional zone rewards allocation for asset +- **HoldingsAllocation** - proportional zone rewards allocation for asset holdings; -* **LastEpochHeight** - the height of this chain at the last Quicksilver epoch +- **LastEpochHeight** - the height of this chain at the last Quicksilver epoch boundary; -* **Tvl** - the Total Value Locked for this zone (in terms of Atom value); -* **UnbondingPeriod** - this zone's unbonding period; +- **Tvl** - the Total Value Locked for this zone (in terms of Atom value); +- **UnbondingPeriod** - this zone's unbonding period; ### ICAAccount @@ -152,11 +152,11 @@ type ICAAccount struct { } ``` -* **Address** - the account address on the remote zone; -* **Balance** - the account balance on the remote zone; -* **PortName** - the port name to access the remote zone; -* **WithdrawalAddress** - the address withdrawals are sent to for this account; -* **BalanceWaitgroup** - the tally of pending balance query transactions sent +- **Address** - the account address on the remote zone; +- **Balance** - the account balance on the remote zone; +- **PortName** - the port name to access the remote zone; +- **WithdrawalAddress** - the address withdrawals are sent to for this account; +- **BalanceWaitgroup** - the tally of pending balance query transactions sent to the remote zone; ### Distribution @@ -236,15 +236,15 @@ type Validator struct { } ``` -* **ValoperAddress** - the validator address; -* **CommissionRate** - the validator commission rate; -* **DelegatorShares** - -* **VotingPower** - the validator voting power on the remote zone; -* **Score** - the validator Quicksilver protocol overall score; -* **Status** - -* **Jailed** - is this validator currently jailed; -* **Tombstoned** - is this validator tombstoned; -* **JailedSince** - blocktime timestamp when this validator was jailed; +- **ValoperAddress** - the validator address; +- **CommissionRate** - the validator commission rate; +- **DelegatorShares** - +- **VotingPower** - the validator voting power on the remote zone; +- **Score** - the validator Quicksilver protocol overall score; +- **Status** - +- **Jailed** - is this validator currently jailed; +- **Tombstoned** - is this validator tombstoned; +- **JailedSince** - blocktime timestamp when this validator was jailed; ### ValidatorIntent @@ -258,8 +258,8 @@ type ValidatorIntent struct { } ``` -* **ValoperAddress** - the remote zone validator address; -* **Weight** - the weight of intended delegation to this validator; +- **ValoperAddress** - the remote zone validator address; +- **Weight** - the weight of intended delegation to this validator; ### DelegatorIntent @@ -273,8 +273,8 @@ type DelegatorIntent struct { } ``` -* **Delegator** - the delegation account address on the remote zone; -* **Intents** - the delegation intents to individual validators on the remote +- **Delegator** - the delegation account address on the remote zone; +- **Intents** - the delegation intents to individual validators on the remote zone; ### Delegation @@ -292,11 +292,11 @@ type Delegation struct { } ``` -* **DelegationAddress** - the delegator address on the remote zone; -* **ValidatorAddress** - the validator address on the remote zone; -* **Amount** - the amount delegated; -* **Height** - the block height at which the delegation occured; -* **RedelegationEnd** - ; +- **DelegationAddress** - the delegator address on the remote zone; +- **ValidatorAddress** - the validator address on the remote zone; +- **Amount** - the amount delegated; +- **Height** - the block height at which the delegation occured; +- **RedelegationEnd** - ; ### PortConnectionTuple @@ -358,9 +358,9 @@ type MsgRequestRedemption struct { } ``` -* **Value** - qAsset as standard cosmos sdk cli coin string, {amount}{denomination}; -* **DestinationAddress** - standard cosmos sdk bech32 address string; -* **FromAddress** - standard cosmos sdk bech32 address string; +- **Value** - qAsset as standard cosmos sdk cli coin string, {amount}{denomination}; +- **DestinationAddress** - standard cosmos sdk bech32 address string; +- **FromAddress** - standard cosmos sdk bech32 address string; **Transaction**: [`redeem`](#redeem) @@ -378,9 +378,9 @@ type MsgSignalIntent struct { } ``` -* **ChainId** - zone identifier string; -* **Intents** - list of validator intents according to weight; -* **FromAddress** - standard cosmos sdk bech32 address string; +- **ChainId** - zone identifier string; +- **Intents** - list of validator intents according to weight; +- **FromAddress** - standard cosmos sdk bech32 address string; **Transaction**: [`signal-intent`](#signal-intent) @@ -446,10 +446,12 @@ file, e.g. "title": "Enable liquidity module for cosmoshub-4", "description": "Update cosmoshub-4 to enable liquidity module", "chain_id": "cosmoshub-4", - "changes": [{ + "changes": [ + { "key": "liquidity_module", - "value": "true", - }], + "value": "true" + } + ], "deposit": "512000000uqck" } ``` @@ -461,7 +463,7 @@ Events emitted by module for tracking messages and index transactions; ### RegisterZone | Type | Attribute Key | Attribute Value | -|:--------------|:--------------|:------------------| +| :------------ | :------------ | :---------------- | | message | module | interchainstaking | | register_zone | connection_id | {connection_id} | | register_zone | chain_id | {chain_id} | @@ -469,7 +471,7 @@ Events emitted by module for tracking messages and index transactions; ### MsgClaim | Type | Attribute Key | Attribute Value | -|:-------------------|:--------------|:------------------| +| :----------------- | :------------ | :---------------- | | message | module | interchainstaking | | request_redemption | burn_amount | {burn_amount} | | request_redemption | redeem_amount | {redeem_amount} | @@ -515,7 +517,7 @@ service Query { option (google.api.http).get = "/quicksilver/interchainstaking/v1/zones/{chain_id}/receipts"; } - + // WithdrawalRecords provides data on the active withdrawals. rpc ZoneWithdrawalRecords(QueryWithdrawalRecordsRequest) returns (QueryWithdrawalRecordsResponse) { @@ -677,20 +679,19 @@ https://pkg.go.dev/github.com/ingenuity-build/quicksilver/x/interchainstaking/ke Module parameters: -| Key | Type | Default | -|:-------------------------|:--------|:--------| -| deposit_interval | uint64 | 20 | -| validatorset_interval | uint64 | 200 | -| commission_rate | sdk.Dec | "0.025" | -| unbonding_enabled | bool | false | - +| Key | Type | Default | +| :-------------------- | :------ | :------ | +| deposit_interval | uint64 | 20 | +| validatorset_interval | uint64 | 200 | +| commission_rate | sdk.Dec | "0.025" | +| unbonding_enabled | bool | false | Description of parameters: -* `deposit_interval` - monitoring and handling interval of registered zones' deposit accounts; -* `validatorset_interval` - monitoring and updating interval of registered zones' validator sets; -* `commission_rate` - default commission rate for Quicksilver validators; -* `unbonding_enabled` - flag to indicate if unbondings are enabled for the Quicksilver protocol; +- `deposit_interval` - monitoring and handling interval of registered zones' deposit accounts; +- `validatorset_interval` - monitoring and updating interval of registered zones' validator sets; +- `commission_rate` - default commission rate for Quicksilver validators; +- `unbonding_enabled` - flag to indicate if unbondings are enabled for the Quicksilver protocol; ## Begin Block @@ -701,20 +702,21 @@ status has changed, requery the validator set and update zone state. The following is performed at the end of every epoch for each registered zone: -* Aggregate Intents: +- Aggregate Intents: 1. Iterate through all stored instances of `DelegatorIntent` for each zone and obtain the **delegator account balance**; 2. Compute the **base balance** using the account balance and `RedpemtionRate`; 3. Ordinalize the delegator's validator intents by `Weight`; 4. Set the zone `AggregateIntent` and update zone state; -* Query delegator delegations for each zone and update delegation records: +- Query delegator delegations for each zone and update delegation records: 1. Query delegator delegations `cosmos.staking.v1beta1.Query/DelegatorDelegations`; 2. For each response (per delegator `DelegationsCallback`), verify every delegation record (via IBC `DelegationCallback`) and update delegation record accordingly (add, update or remove); 3. Update validator set; 4. Update zone; -* Withdraw delegation rewards for each zone and distribute: +- Withdraw delegation rewards for each zone and distribute: + 1. Query delegator rewards `cosmos.distribution.v1beta1.Query/DelegationTotalRewards`; 2. For each response (per delegator `RewardsCallback`), send withdrawal messages for each of its validator delegations and add tally to @@ -737,8 +739,8 @@ Triggered at the end of every epoch if delegator accounts have accrued rewards. Collects rewards to zone withdrawal account `WithdrawalAddress` and distributes rewards once all delegator rewards withdrawals have been acknowledged. -* **Endpoint:** `/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward` -* **Handler:** `HandleWithdrawRewards` +- **Endpoint:** `/cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward` +- **Handler:** `HandleWithdrawRewards` #### MsgRedeemTokensforShares @@ -746,8 +748,8 @@ Triggered during execution of `Delegate` for delegation allocations that are not in the zone `BaseDenom`. During callback the relevant delegation record is updated. -* **Endpoint:** `/cosmos.staking.v1beta1.MsgRedeemTokensforShares` -* **Handler:** `HandleRedeemTokens` +- **Endpoint:** `/cosmos.staking.v1beta1.MsgRedeemTokensforShares` +- **Handler:** `HandleRedeemTokens` #### MsgTokenizeShares @@ -755,8 +757,8 @@ Triggered by `RequestRedemption` when a user redeems qAssets. Withdrawal records are set or updated accordingly. See [MsgRequestRedemption](#MsgRequestRedemption). -* **Endpoint:** `/cosmos.staking.v1beta1.MsgTokenizeShares` -* **Handler:** `HandleTokenizedShares` +- **Endpoint:** `/cosmos.staking.v1beta1.MsgTokenizeShares` +- **Handler:** `HandleTokenizedShares` #### MsgDelegate @@ -764,23 +766,23 @@ Triggered by `Delegate` whenever delagtions are made by the protocol to zone validators. `HandleDelegate` distinguishes `DelegationAddresses` and updates delegation records for these delegation accounts. -* **Endpoint:** `/cosmos.staking.v1beta1.MsgDelegate` -* **Handler:** `HandleDelegate` +- **Endpoint:** `/cosmos.staking.v1beta1.MsgDelegate` +- **Handler:** `HandleDelegate` #### MsgBeginRedelegate Triggered at the end of every epoch during `Rebalance`. -* **Endpoint:** `/cosmos.staking.v1beta1.MsgBeginRedelegate` -* **Handler:** `HandleBeginRedelegate` +- **Endpoint:** `/cosmos.staking.v1beta1.MsgBeginRedelegate` +- **Handler:** `HandleBeginRedelegate` #### MsgSend Triggered by `TransferToDelegate` during `HandleReceiptTransaction`. See [Deposit Interval](#Deposit-Interval). -* **Endpoint:** `/cosmos.bank.v1beta1.MsgSend` -* **Handler:** `HandleCompleteSend` +- **Endpoint:** `/cosmos.bank.v1beta1.MsgSend` +- **Handler:** `HandleCompleteSend` `HandleCompleteSend` executes one of the following options based on the `FromAddress` and `ToAddress` of the msg: @@ -792,13 +794,6 @@ See [Deposit Interval](#Deposit-Interval). 3. **Delegate amount according to delegation plan.** (If `FromAddress` is `DepositAddress` and `ToAddress` is one of zone's `DelegationAddresses`); -#### MsgMultiSend - -Not sent? - -* **Endpoint:** `/cosmos.bank.v1beta1.MsgMultiSend` -* **Handler:** `HandleCompleteMultiSend` - #### MsgSetWithdrawAddress Triggered during zone initialization for every `DelegationAddresses` and @@ -808,8 +803,8 @@ be impossible as the rewards amount will only be known at the time the msg is triggered, and not at the time it was executed by the remote zone (due to network latency and different zone block times, etc). -* **Endpoint:** `/cosmos.distribution.v1beta1.MsgSetWithdrawAddress` -* **Handler:** `HandleUpdatedWithdrawAddress` +- **Endpoint:** `/cosmos.distribution.v1beta1.MsgSetWithdrawAddress` +- **Handler:** `HandleUpdatedWithdrawAddress` #### MsgTransfer @@ -818,8 +813,8 @@ across the zone delegation accounts and collect fees to the module fee account. The `RedemptionRate` is updated accordingly. See [WithdrawalAddress Balances](#WithdrawalAddress-Balances). -* **Endpoint:** `/ibc.applications.transfer.v1.MsgTransfer` -* **Handler:** `HandleMsgTransfer` +- **Endpoint:** `/ibc.applications.transfer.v1.MsgTransfer` +- **Handler:** `HandleMsgTransfer` ### Queries, Requests & Callbacks @@ -832,32 +827,32 @@ For every registered zone a periodic `AllBalances` query is run against the update the individual account balances `AccountBalanceCallback`, trigger the `depositInterval` and finally update the zone state. -* **Query:** `cosmos.bank.v1beta1.Query/AllBalances` -* **Callback:** `AllBalancesCallback` +- **Query:** `cosmos.bank.v1beta1.Query/AllBalances` +- **Callback:** `AllBalancesCallback` #### Delegator Delegations Query delegator delegations for each zone and update delegation records. See [After Epoch End](#After-Epoch-End). -* **Query:** `cosmos.staking.v1beta1.Query/DelegatorDelegations` -* **Callback:** `DelegationsCallback` +- **Query:** `cosmos.staking.v1beta1.Query/DelegatorDelegations` +- **Callback:** `DelegationsCallback` #### Delegate Total Rewards Withdraw delegation rewards for each zone and distribute. See [After Epoch End](#After-Epoch-End). -* **Query:** `cosmos.distribution.v1beta1.Query/DelegationTotalRewards` -* **Callback:** `RewardsCallback` +- **Query:** `cosmos.distribution.v1beta1.Query/DelegationTotalRewards` +- **Callback:** `RewardsCallback` #### WithdrawalAddress Balances Triggered by `HandleWithdrawRewards`. See [MsgWithdrawDelegatorReward](#MsgWithdrawDelegatorReward). -* **Query:** `cosmos.bank.v1beta1.Query/AllBalances` -* **Callback:** `DistributeRewardsFromWithdrawAccount` +- **Query:** `cosmos.bank.v1beta1.Query/AllBalances` +- **Callback:** `DistributeRewardsFromWithdrawAccount` #### Deposit Interval @@ -868,8 +863,8 @@ qAssets minted and transferred to the sender (`MintQAsset`). A delegation plan is computed (`DeterminePlanForDelegation`) and then executed (`TransferToDelegate`). Successfully executed receipts are recorded to state. -* **Query:** `cosmos.tx.v1beta1.Service/GetTxsEvent` -* **Callback:** `DepositIntervalCallback` +- **Query:** `cosmos.tx.v1beta1.Service/GetTxsEvent` +- **Callback:** `DepositIntervalCallback` #### Performance Balance Query @@ -878,8 +873,8 @@ Triggered at zone registration when the zone performance account until sufficient funds are available to execute the performance delegations. See [x/participationrewards/spec](../../participationrewards/spec/README.md). -* **Query:** `cosmos.bank.v1beta1.Query/AllBalances` -* **Callback:** `PerfBalanceCallback` +- **Query:** `cosmos.bank.v1beta1.Query/AllBalances` +- **Callback:** `PerfBalanceCallback` #### Validator Set Query @@ -887,5 +882,5 @@ An essential query to ensure that the registred zone state accurately reflects the validator set of the remote zone for bonded, unbonded and unbonding validators. -* **Query:** `cosmos.staking.v1beta1.Query/Validators` -* **Callback:** `ValsetCallback` +- **Query:** `cosmos.staking.v1beta1.Query/Validators` +- **Callback:** `ValsetCallback` diff --git a/x/interchainstaking/types/delegation.go b/x/interchainstaking/types/delegation.go index 933511471..41bb12ad4 100644 --- a/x/interchainstaking/types/delegation.go +++ b/x/interchainstaking/types/delegation.go @@ -2,7 +2,6 @@ package types import ( "errors" - "fmt" "sort" "github.com/cosmos/cosmos-sdk/codec" @@ -75,7 +74,7 @@ func (vi ValidatorIntents) Sort() ValidatorIntents { } func (vi ValidatorIntents) GetForValoper(valoper string) (*ValidatorIntent, bool) { - for _, i := range vi.Sort() { + for _, i := range vi { if i.ValoperAddress == valoper { return i, true } @@ -84,14 +83,10 @@ func (vi ValidatorIntents) GetForValoper(valoper string) (*ValidatorIntent, bool } func (vi ValidatorIntents) SetForValoper(valoper string, intent *ValidatorIntent) ValidatorIntents { - fmt.Println("Replacing valoper" + valoper) - for idx, i := range vi.Sort() { + for idx, i := range vi { if i.ValoperAddress == valoper { - fmt.Println("Found valoper at " + fmt.Sprint(idx)) - fmt.Println("before", vi) vi[idx] = vi[len(vi)-1] vi = vi[:len(vi)-1] - fmt.Println("after", vi) break } } @@ -102,8 +97,21 @@ func (vi ValidatorIntents) SetForValoper(valoper string, intent *ValidatorIntent func (vi ValidatorIntents) MustGetForValoper(valoper string) *ValidatorIntent { intent, found := vi.GetForValoper(valoper) - if !found { - panic("could not find intent for valoper") + if !found || intent == nil { + return &ValidatorIntent{ValoperAddress: valoper, Weight: sdk.ZeroDec()} } return intent } + +func (vi ValidatorIntents) Normalize() ValidatorIntents { + total := sdk.ZeroDec() + for _, i := range vi { + total = total.AddMut(i.Weight) + } + + out := make(ValidatorIntents, 0) + for _, i := range vi { + out = append(out, &ValidatorIntent{ValoperAddress: i.ValoperAddress, Weight: i.Weight.Quo(total)}) + } + return out.Sort() +} diff --git a/x/interchainstaking/types/interchainstaking.pb.go b/x/interchainstaking/types/interchainstaking.pb.go index fa7cbb084..8c1c29b3e 100644 --- a/x/interchainstaking/types/interchainstaking.pb.go +++ b/x/interchainstaking/types/interchainstaking.pb.go @@ -392,6 +392,7 @@ type WithdrawalRecord struct { Txhash string `protobuf:"bytes,7,opt,name=txhash,proto3" json:"txhash,omitempty"` Status int32 `protobuf:"varint,8,opt,name=status,proto3" json:"status,omitempty"` CompletionTime time.Time `protobuf:"bytes,9,opt,name=completion_time,json=completionTime,proto3,stdtime" json:"completion_time"` + Requeued bool `protobuf:"varint,10,opt,name=requeued,proto3" json:"requeued,omitempty"` } func (m *WithdrawalRecord) Reset() { *m = WithdrawalRecord{} } @@ -483,6 +484,13 @@ func (m *WithdrawalRecord) GetCompletionTime() time.Time { return time.Time{} } +func (m *WithdrawalRecord) GetRequeued() bool { + if m != nil { + return m.Requeued + } + return false +} + type UnbondingRecord struct { ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` EpochNumber int64 `protobuf:"varint,2,opt,name=epoch_number,json=epochNumber,proto3" json:"epoch_number,omitempty"` @@ -1091,116 +1099,116 @@ func init() { } var fileDescriptor_0d755cfd37ef9fee = []byte{ - // 1729 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x5f, 0x6f, 0x5b, 0x49, - 0x15, 0xef, 0xb5, 0x1d, 0x3b, 0x3e, 0x76, 0xe2, 0x64, 0x92, 0xed, 0xde, 0x06, 0x70, 0x8c, 0x11, - 0x60, 0x58, 0x62, 0x6f, 0x8a, 0x04, 0x68, 0x85, 0xd0, 0x26, 0x4d, 0xb5, 0x1b, 0xa1, 0x56, 0xd5, - 0x4d, 0x96, 0x95, 0x8a, 0xd0, 0xd5, 0xf8, 0xde, 0x89, 0x3d, 0xf4, 0xde, 0x19, 0x77, 0x66, 0x9c, - 0xa4, 0x7c, 0x8a, 0xfd, 0x08, 0xbc, 0xad, 0xb4, 0x42, 0x3c, 0xf5, 0x91, 0x0f, 0xb0, 0x8f, 0x4b, - 0x9f, 0x10, 0x42, 0x2d, 0x6a, 0x5f, 0xe1, 0x85, 0x4f, 0x80, 0xe6, 0xcf, 0xbd, 0xbe, 0xc9, 0x86, - 0x3a, 0x69, 0xb3, 0x3c, 0xd9, 0x73, 0xfe, 0xfc, 0xe6, 0xcf, 0x39, 0x73, 0x7e, 0x67, 0x2e, 0xfc, - 0xe2, 0xf1, 0x94, 0x46, 0x8f, 0x24, 0x4d, 0x8e, 0x89, 0x18, 0x50, 0xa6, 0x88, 0x88, 0xc6, 0x98, - 0x32, 0xa9, 0xf0, 0x23, 0xca, 0x46, 0x83, 0xe3, 0xed, 0xaf, 0x0b, 0xfb, 0x13, 0xc1, 0x15, 0x47, - 0x9d, 0x82, 0x67, 0xff, 0xeb, 0x46, 0xc7, 0xdb, 0x1b, 0xeb, 0x23, 0x3e, 0xe2, 0xc6, 0x78, 0xa0, - 0xff, 0x59, 0xbf, 0x8d, 0x5b, 0x11, 0x97, 0x29, 0x97, 0xa1, 0x55, 0xd8, 0x81, 0x53, 0xb5, 0xed, - 0x68, 0x30, 0xc4, 0x92, 0x0c, 0x8e, 0xb7, 0x87, 0x44, 0xe1, 0xed, 0x41, 0xc4, 0x29, 0x73, 0xfa, - 0xcd, 0x11, 0xe7, 0xa3, 0x84, 0x0c, 0xcc, 0x68, 0x38, 0x3d, 0x1a, 0x28, 0x9a, 0x12, 0xa9, 0x70, - 0x3a, 0xb1, 0x06, 0xdd, 0xcf, 0x9b, 0x50, 0x79, 0xc8, 0x19, 0x41, 0xdf, 0x83, 0xa5, 0x88, 0x33, - 0x46, 0x22, 0x45, 0x39, 0x0b, 0x69, 0xec, 0x7b, 0x1d, 0xaf, 0x57, 0x0f, 0x9a, 0x33, 0xe1, 0x7e, - 0x8c, 0x6e, 0xc1, 0xa2, 0x59, 0xb2, 0xd6, 0x97, 0x8c, 0xbe, 0x66, 0xc6, 0xfb, 0x31, 0xfa, 0x04, - 0x5a, 0x31, 0x99, 0x70, 0x49, 0x55, 0x88, 0xe3, 0x58, 0x10, 0x29, 0xfd, 0x72, 0xc7, 0xeb, 0x35, - 0x6e, 0xff, 0xa4, 0x3f, 0x6f, 0xdb, 0xfd, 0xfd, 0x3b, 0x3b, 0x3b, 0x51, 0xc4, 0xa7, 0x4c, 0x05, - 0xcb, 0x0e, 0x64, 0xc7, 0x62, 0xa0, 0xdf, 0x02, 0x3a, 0xa1, 0x6a, 0x1c, 0x0b, 0x7c, 0x82, 0x93, - 0x1c, 0xb9, 0xf2, 0x06, 0xc8, 0xab, 0x33, 0x9c, 0x0c, 0xfc, 0x77, 0xb0, 0x36, 0x21, 0xe2, 0x88, - 0x8b, 0x14, 0xb3, 0x88, 0xe4, 0xe8, 0x0b, 0x6f, 0x80, 0x8e, 0x0a, 0x40, 0x85, 0xb5, 0xc7, 0x24, - 0x21, 0x23, 0x6c, 0x8e, 0x34, 0x43, 0xaf, 0xbe, 0xc9, 0xda, 0x67, 0x38, 0x19, 0xf8, 0xf7, 0x61, - 0x19, 0x5b, 0x6d, 0x38, 0x11, 0xe4, 0x88, 0x9e, 0xfa, 0x35, 0x13, 0x90, 0x25, 0x27, 0x7d, 0x60, - 0x84, 0x68, 0x13, 0x1a, 0x09, 0x8f, 0x70, 0x12, 0xc6, 0x84, 0xf1, 0xd4, 0x5f, 0x34, 0x36, 0x60, - 0x44, 0x7b, 0x5a, 0x82, 0xbe, 0x03, 0xa0, 0x93, 0xc7, 0xe9, 0xeb, 0x46, 0x5f, 0xd7, 0x12, 0xab, - 0x26, 0xd0, 0x12, 0x24, 0x26, 0xe9, 0xc4, 0xec, 0x41, 0x60, 0x45, 0x7c, 0xd0, 0x36, 0xbb, 0xbf, - 0xfc, 0xf2, 0xf9, 0xe6, 0x8d, 0xbf, 0x3f, 0xdf, 0xfc, 0xc1, 0x88, 0xaa, 0xf1, 0x74, 0xd8, 0x8f, - 0x78, 0xea, 0x52, 0xd3, 0xfd, 0x6c, 0xc9, 0xf8, 0xd1, 0x40, 0x3d, 0x99, 0x10, 0xd9, 0xdf, 0x23, - 0xd1, 0xb3, 0xa7, 0x5b, 0xe0, 0x32, 0x77, 0x8f, 0x44, 0xc1, 0xf2, 0x0c, 0x34, 0xc0, 0x8a, 0x20, - 0x06, 0xeb, 0x09, 0x96, 0x2a, 0x3c, 0x3f, 0x57, 0xe3, 0x1a, 0xe6, 0x42, 0x1a, 0x39, 0x38, 0x3b, - 0xdf, 0xaf, 0x01, 0x8e, 0x71, 0x42, 0x63, 0xac, 0xb8, 0x90, 0x7e, 0xb3, 0x53, 0xee, 0x35, 0x6e, - 0xbf, 0x37, 0x3f, 0x24, 0xbf, 0xc9, 0x7c, 0x82, 0x82, 0x3b, 0x12, 0xb0, 0x82, 0x47, 0x23, 0xa1, - 0x03, 0x44, 0x42, 0xed, 0xc7, 0x94, 0xbf, 0x64, 0x20, 0xb7, 0xaf, 0x00, 0xb9, 0x6f, 0x1c, 0x77, - 0xd7, 0xbf, 0x78, 0xb1, 0xb9, 0x72, 0x4e, 0x28, 0x83, 0x56, 0x3e, 0x81, 0x95, 0xe8, 0xb0, 0xa5, - 0xd3, 0x44, 0xd1, 0x50, 0x12, 0x16, 0xfb, 0xcb, 0x1d, 0xaf, 0xb7, 0x18, 0xd4, 0x8d, 0xe4, 0x80, - 0xb0, 0x18, 0xfd, 0x08, 0x56, 0x12, 0xfa, 0x78, 0x4a, 0x63, 0xaa, 0x9e, 0x84, 0x29, 0x8f, 0xa7, - 0x09, 0xf1, 0x5b, 0xc6, 0xa8, 0x95, 0xcb, 0xef, 0x19, 0x31, 0xda, 0x86, 0xf5, 0xc2, 0x0d, 0x3b, - 0xc1, 0x54, 0x8d, 0x04, 0x9f, 0x4e, 0xfc, 0x95, 0x8e, 0xd7, 0x5b, 0x0a, 0xd6, 0x66, 0xba, 0x4f, - 0x33, 0x15, 0xfa, 0x39, 0xf8, 0x74, 0x18, 0x85, 0x8c, 0x9c, 0xaa, 0x70, 0x76, 0x0e, 0xe1, 0x18, - 0xcb, 0xb1, 0xbf, 0xda, 0xf1, 0x7a, 0xcd, 0xe0, 0x1d, 0x3a, 0x8c, 0xee, 0x93, 0x53, 0x95, 0x6f, - 0x44, 0x7e, 0x8c, 0xe5, 0x18, 0xed, 0x41, 0x3b, 0xb7, 0x0f, 0x25, 0x49, 0x5c, 0xb5, 0xc1, 0x89, - 0x4e, 0x48, 0xfd, 0xd7, 0x47, 0x1d, 0xaf, 0x57, 0x09, 0xbe, 0x9d, 0x5b, 0x1d, 0x64, 0x46, 0x3b, - 0xb9, 0x0d, 0x1a, 0xc0, 0xda, 0x98, 0x27, 0x31, 0x65, 0x23, 0x59, 0x74, 0x5d, 0x33, 0xae, 0x28, - 0x53, 0x15, 0x1c, 0x7e, 0x0c, 0xab, 0x26, 0xbb, 0xc8, 0x84, 0x47, 0xe3, 0x70, 0x4c, 0xe8, 0x68, - 0xac, 0xfc, 0xf5, 0x8e, 0xd7, 0x2b, 0x07, 0x2d, 0xad, 0xb8, 0xab, 0xe5, 0x1f, 0x1b, 0x31, 0xba, - 0x0f, 0x65, 0x75, 0x9c, 0xf8, 0xef, 0x5c, 0x43, 0xe2, 0x69, 0x20, 0x1d, 0x89, 0x29, 0x1b, 0x72, - 0xa6, 0xd7, 0x14, 0x4e, 0x88, 0xa0, 0x3c, 0xf6, 0x6f, 0xda, 0xa9, 0x73, 0xf9, 0x03, 0x23, 0x46, - 0x1b, 0xb0, 0x18, 0x93, 0x88, 0xa6, 0x38, 0x91, 0xfe, 0xbb, 0xc6, 0x24, 0x1f, 0xa3, 0xf7, 0x60, - 0x75, 0x06, 0x43, 0x18, 0x1e, 0x26, 0x24, 0xf6, 0x7d, 0x13, 0xd1, 0x19, 0xfe, 0x5d, 0x2b, 0xd7, - 0x73, 0xba, 0x32, 0x2a, 0x73, 0xdb, 0x5b, 0x36, 0xfa, 0x99, 0x3c, 0x33, 0xed, 0xc1, 0x8a, 0x20, - 0x6a, 0x2a, 0x58, 0xa8, 0xb8, 0xc9, 0x25, 0x22, 0xfc, 0x0d, 0x63, 0xba, 0x6c, 0xe5, 0x87, 0xfc, - 0xc0, 0x48, 0xbb, 0x7f, 0x2c, 0x01, 0xcc, 0x4a, 0x12, 0xba, 0x0d, 0xb5, 0xac, 0xa2, 0x19, 0xa6, - 0xd8, 0xf5, 0x9f, 0x3d, 0xdd, 0x5a, 0x77, 0xbb, 0x77, 0x45, 0xea, 0x40, 0x09, 0xca, 0x46, 0x41, - 0x66, 0x88, 0x08, 0xd4, 0x86, 0x38, 0xd1, 0x25, 0xd2, 0x2f, 0x99, 0xfb, 0x71, 0xab, 0xef, 0x1c, - 0x74, 0xc1, 0xe9, 0x3b, 0xfe, 0xea, 0xdf, 0xe1, 0x94, 0xed, 0xbe, 0xaf, 0x8f, 0xfe, 0x8b, 0x17, - 0x9b, 0xbd, 0x4b, 0x1c, 0xbd, 0x76, 0x90, 0x41, 0x86, 0x8d, 0xbe, 0x05, 0xf5, 0x09, 0x17, 0x2a, - 0x64, 0x38, 0x25, 0x86, 0x84, 0xea, 0xc1, 0xa2, 0x16, 0xdc, 0xc7, 0x29, 0x41, 0x5b, 0xff, 0x93, - 0x50, 0xea, 0x17, 0x51, 0xc4, 0x7b, 0xb0, 0xea, 0x60, 0x0b, 0x57, 0x63, 0xc1, 0x5c, 0x8d, 0x15, - 0xa7, 0xc8, 0xef, 0x45, 0xf7, 0x43, 0x68, 0xee, 0x51, 0xa9, 0x04, 0x1d, 0x4e, 0x4d, 0xde, 0xf9, - 0x50, 0x3b, 0xc6, 0x09, 0x9f, 0x10, 0xe1, 0xd8, 0x34, 0x1b, 0xa2, 0x9b, 0x50, 0xc5, 0xa9, 0x3e, - 0x47, 0x43, 0xa3, 0x95, 0xc0, 0x8d, 0xba, 0x7f, 0xad, 0xc0, 0xca, 0xa7, 0xf9, 0x22, 0x02, 0x12, - 0x71, 0x71, 0x96, 0x75, 0xbd, 0xb3, 0xac, 0xfb, 0x33, 0xa8, 0x3b, 0x6a, 0xe0, 0xc2, 0x32, 0xf2, - 0x6b, 0xe2, 0x30, 0x33, 0x45, 0x01, 0x34, 0xe3, 0xc2, 0x4a, 0xfd, 0xb2, 0x09, 0x47, 0x7f, 0x7e, - 0xb9, 0x2a, 0xee, 0x2f, 0x38, 0x83, 0xa1, 0xd7, 0x22, 0x48, 0x44, 0x27, 0x54, 0xd7, 0xbf, 0xca, - 0xbc, 0xb5, 0xe4, 0xa6, 0x28, 0xca, 0xcf, 0x62, 0xe1, 0xfa, 0x93, 0xc2, 0x41, 0xa3, 0x3f, 0x40, - 0x63, 0xa8, 0xb3, 0xdc, 0xcd, 0x64, 0x49, 0xf8, 0x35, 0x33, 0xfd, 0xca, 0xdd, 0xfc, 0x1f, 0x5e, - 0x72, 0xa6, 0x67, 0x4f, 0xb7, 0x1a, 0x0e, 0x4c, 0x0f, 0x03, 0xd0, 0xb3, 0xed, 0xd8, 0xb9, 0x6f, - 0x42, 0x55, 0x9d, 0x9a, 0xe2, 0x68, 0x29, 0xda, 0x8d, 0xb4, 0x5c, 0x2a, 0xac, 0xa6, 0xd2, 0xd0, - 0xf2, 0x42, 0xe0, 0x46, 0xe8, 0x1e, 0xb4, 0x22, 0x9e, 0x4e, 0x12, 0x62, 0x8a, 0xa3, 0xee, 0xd8, - 0x0c, 0x2f, 0x37, 0x6e, 0x6f, 0xf4, 0x6d, 0x3b, 0xd7, 0xcf, 0xda, 0xb9, 0xfe, 0x61, 0xd6, 0xce, - 0xed, 0x2e, 0xea, 0x05, 0x7f, 0xf6, 0x62, 0xd3, 0x0b, 0x96, 0x67, 0xce, 0x5a, 0xdd, 0xfd, 0xb3, - 0x07, 0xad, 0x4f, 0xb2, 0x12, 0x31, 0x3f, 0xa5, 0xbe, 0x0b, 0x4d, 0x5b, 0x27, 0xd9, 0x34, 0x1d, - 0x12, 0x9b, 0x55, 0xe5, 0xa0, 0x61, 0x64, 0xf7, 0x8d, 0x48, 0x47, 0x3a, 0x2f, 0xd0, 0xf6, 0x82, - 0xbd, 0x2e, 0xd2, 0xb9, 0xa9, 0xee, 0x59, 0x04, 0x49, 0xb0, 0x22, 0x71, 0xe8, 0x0e, 0xa4, 0xd2, - 0x29, 0xeb, 0x9e, 0xc5, 0x49, 0x0f, 0x8d, 0xb0, 0xfb, 0x79, 0x09, 0x90, 0xe6, 0xeb, 0xac, 0xe5, - 0xb9, 0x96, 0x35, 0xbf, 0x0f, 0x55, 0xc9, 0xa7, 0x22, 0x22, 0x73, 0x17, 0xec, 0xec, 0xd0, 0x07, - 0xd0, 0x88, 0x89, 0x54, 0x94, 0x59, 0x7a, 0x99, 0x97, 0xd1, 0x45, 0xe3, 0xc2, 0xfd, 0x5e, 0x30, - 0x4b, 0xc9, 0xd2, 0xf0, 0x82, 0xd0, 0x56, 0xdf, 0x22, 0xb4, 0xff, 0xf6, 0x60, 0xf9, 0x50, 0x60, - 0x26, 0x8f, 0x88, 0x70, 0xa7, 0xa4, 0xf7, 0x69, 0xcb, 0xb8, 0x37, 0x77, 0x9f, 0xc6, 0xee, 0xec, - 0xbd, 0x2d, 0x5d, 0xfe, 0xde, 0x3e, 0xce, 0xf7, 0x58, 0xfe, 0xa6, 0x6f, 0x53, 0x56, 0x1e, 0xff, - 0x55, 0x81, 0x7a, 0xde, 0x52, 0xa0, 0x1d, 0x68, 0xb9, 0x7a, 0x1a, 0x5e, 0x96, 0x8a, 0x96, 0x9d, - 0xc3, 0x4e, 0xce, 0x48, 0x3a, 0x1e, 0x29, 0x95, 0x32, 0x6f, 0x39, 0x4b, 0xd7, 0xd1, 0xde, 0xce, - 0x40, 0x4d, 0xbb, 0x39, 0xd2, 0x84, 0xec, 0x6a, 0x6f, 0x28, 0xc7, 0x58, 0x10, 0xe9, 0xd2, 0xf0, - 0xed, 0xe6, 0x69, 0xe5, 0xa8, 0x07, 0x06, 0x14, 0x85, 0xd0, 0x3c, 0xe6, 0xca, 0xb4, 0x1a, 0xfc, - 0x84, 0x08, 0x97, 0xb4, 0x57, 0x99, 0x64, 0x9f, 0xa9, 0xc2, 0x24, 0xfb, 0x4c, 0x05, 0x0d, 0x8b, - 0xf8, 0x40, 0x03, 0xa2, 0x00, 0x16, 0x64, 0xc4, 0x05, 0x31, 0x79, 0xfd, 0xb6, 0xcb, 0xb7, 0x50, - 0x85, 0x3a, 0x58, 0xb5, 0xf5, 0xd1, 0xd5, 0xc1, 0x9b, 0x50, 0xfd, 0x3d, 0xa6, 0xba, 0x79, 0xa9, - 0x99, 0x8e, 0xc4, 0x8d, 0x50, 0x1b, 0x40, 0xf1, 0x74, 0x28, 0x15, 0x67, 0x24, 0x36, 0xb5, 0x73, - 0x31, 0x28, 0x48, 0xd0, 0x47, 0xd0, 0xb4, 0x96, 0xa1, 0xa4, 0xba, 0xd7, 0xb8, 0x4a, 0xf1, 0x6c, - 0x58, 0xcf, 0x03, 0xed, 0xd8, 0xfd, 0x93, 0x07, 0xad, 0xbd, 0xec, 0x84, 0x5d, 0xe3, 0x7d, 0x86, - 0x71, 0xbd, 0xcb, 0x33, 0x2e, 0x86, 0x9a, 0x7d, 0x1a, 0x48, 0xd7, 0xfb, 0x5c, 0xdb, 0xdb, 0x20, - 0xc3, 0xed, 0xfe, 0xc5, 0x83, 0xd6, 0x39, 0x2d, 0xda, 0xbd, 0xfa, 0x1d, 0x39, 0xef, 0x80, 0x08, - 0x54, 0x4f, 0x6c, 0xcf, 0x6c, 0xef, 0xc6, 0xbd, 0xab, 0x05, 0xfd, 0x3f, 0xcf, 0x37, 0x97, 0x9e, - 0xe0, 0x34, 0xf9, 0xa0, 0x6b, 0x51, 0xba, 0xe7, 0xb2, 0xa0, 0x9a, 0x89, 0x4b, 0x00, 0x7b, 0x79, - 0xd1, 0x47, 0x1f, 0x5d, 0xf8, 0x7a, 0x9e, 0xb7, 0xf8, 0x0b, 0x5e, 0xca, 0x77, 0x61, 0x75, 0xf6, - 0xe8, 0xc8, 0x70, 0xe6, 0xd5, 0xb9, 0x95, 0xdc, 0x25, 0x83, 0xf9, 0xff, 0x97, 0x3b, 0x7d, 0x01, - 0xdc, 0x63, 0xa5, 0x62, 0x59, 0xc4, 0x8e, 0x74, 0x7f, 0x2f, 0x0a, 0xfc, 0x18, 0xea, 0x27, 0xa0, - 0xe5, 0x99, 0x56, 0x51, 0x7e, 0x97, 0xc5, 0xdd, 0x03, 0x58, 0x7b, 0xc0, 0x85, 0xba, 0x93, 0x7f, - 0xc5, 0x39, 0x9c, 0x4e, 0x92, 0x4b, 0x7e, 0xed, 0x79, 0x17, 0x6a, 0xa6, 0x8f, 0xce, 0x3f, 0xf6, - 0x54, 0xf5, 0x70, 0x3f, 0xee, 0xfe, 0xa3, 0x04, 0xb5, 0x80, 0x44, 0x84, 0x4e, 0xd4, 0xeb, 0x58, - 0x79, 0x46, 0x45, 0xa5, 0x4b, 0x52, 0xd1, 0xac, 0x53, 0x2a, 0x9f, 0xe9, 0x94, 0x66, 0x2d, 0x62, - 0xe5, 0x9b, 0x6b, 0x11, 0xef, 0x00, 0x1c, 0x51, 0x21, 0x55, 0x28, 0x09, 0x61, 0xee, 0x23, 0xd0, - 0xbc, 0xa2, 0xe1, 0x99, 0xa2, 0x51, 0x37, 0x7e, 0x07, 0x84, 0x30, 0xb4, 0x0b, 0x75, 0xc7, 0xd1, - 0x24, 0xbe, 0x24, 0xb5, 0x3b, 0x8c, 0xdc, 0x6d, 0xf7, 0xe1, 0x97, 0x2f, 0xdb, 0xde, 0x57, 0x2f, - 0xdb, 0xde, 0x3f, 0x5f, 0xb6, 0xbd, 0xcf, 0x5e, 0xb5, 0x6f, 0x7c, 0xf5, 0xaa, 0x7d, 0xe3, 0x6f, - 0xaf, 0xda, 0x37, 0x1e, 0x7e, 0x58, 0xd8, 0x14, 0x65, 0x23, 0xc2, 0xa6, 0x54, 0x3d, 0xd9, 0x1a, - 0x4e, 0x69, 0x12, 0x0f, 0x8a, 0x9f, 0x25, 0x4f, 0x2f, 0xf8, 0x30, 0x69, 0xb6, 0x3c, 0xac, 0x9a, - 0x45, 0xfc, 0xf4, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x93, 0xec, 0x2a, 0x30, 0xc6, 0x14, 0x00, - 0x00, + // 1744 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4f, 0x6f, 0x1b, 0xc7, + 0x15, 0xf7, 0x4a, 0x14, 0x29, 0x3e, 0x52, 0xa2, 0x34, 0x52, 0x9c, 0xb5, 0xda, 0x52, 0x2c, 0x8b, + 0xb6, 0x6c, 0x5d, 0x91, 0x91, 0x0b, 0xb4, 0x45, 0x50, 0x14, 0x91, 0x2c, 0x23, 0x11, 0x0a, 0x1b, + 0xc6, 0x4a, 0x69, 0x00, 0x17, 0xc5, 0x62, 0xb8, 0x3b, 0x22, 0xa7, 0xde, 0x9d, 0xa1, 0x67, 0x66, + 0x25, 0xb9, 0x9f, 0x22, 0x1f, 0xa1, 0xb7, 0x00, 0x41, 0xd1, 0x93, 0x8f, 0xfd, 0x00, 0x39, 0x06, + 0x3e, 0x15, 0x45, 0x61, 0x17, 0xf6, 0xb5, 0xb9, 0xf4, 0x13, 0x14, 0xf3, 0x67, 0x97, 0x2b, 0x45, + 0x35, 0x25, 0x47, 0xe9, 0x89, 0x9c, 0xf7, 0xe7, 0x37, 0x6f, 0x66, 0xde, 0xbc, 0xdf, 0x9b, 0x85, + 0x5f, 0x3d, 0xc9, 0x68, 0xf4, 0x58, 0xd2, 0xe4, 0x98, 0x88, 0x01, 0x65, 0x8a, 0x88, 0x68, 0x8c, + 0x29, 0x93, 0x0a, 0x3f, 0xa6, 0x6c, 0x34, 0x38, 0xde, 0xfe, 0xba, 0xb0, 0x3f, 0x11, 0x5c, 0x71, + 0xd4, 0x29, 0x79, 0xf6, 0xbf, 0x6e, 0x74, 0xbc, 0xbd, 0xb1, 0x3e, 0xe2, 0x23, 0x6e, 0x8c, 0x07, + 0xfa, 0x9f, 0xf5, 0xdb, 0xb8, 0x15, 0x71, 0x99, 0x72, 0x19, 0x5a, 0x85, 0x1d, 0x38, 0x55, 0xdb, + 0x8e, 0x06, 0x43, 0x2c, 0xc9, 0xe0, 0x78, 0x7b, 0x48, 0x14, 0xde, 0x1e, 0x44, 0x9c, 0x32, 0xa7, + 0xdf, 0x1c, 0x71, 0x3e, 0x4a, 0xc8, 0xc0, 0x8c, 0x86, 0xd9, 0xd1, 0x40, 0xd1, 0x94, 0x48, 0x85, + 0xd3, 0x89, 0x35, 0xe8, 0x7e, 0xd6, 0x84, 0xca, 0x23, 0xce, 0x08, 0xfa, 0x01, 0x2c, 0x45, 0x9c, + 0x31, 0x12, 0x29, 0xca, 0x59, 0x48, 0x63, 0xdf, 0xeb, 0x78, 0xbd, 0x7a, 0xd0, 0x9c, 0x0a, 0xf7, + 0x63, 0x74, 0x0b, 0x16, 0x4d, 0xc8, 0x5a, 0x3f, 0x67, 0xf4, 0x35, 0x33, 0xde, 0x8f, 0xd1, 0xc7, + 0xd0, 0x8a, 0xc9, 0x84, 0x4b, 0xaa, 0x42, 0x1c, 0xc7, 0x82, 0x48, 0xe9, 0xcf, 0x77, 0xbc, 0x5e, + 0xe3, 0xce, 0xcf, 0xfa, 0xb3, 0x96, 0xdd, 0xdf, 0xbf, 0xbb, 0xb3, 0x13, 0x45, 0x3c, 0x63, 0x2a, + 0x58, 0x76, 0x20, 0x3b, 0x16, 0x03, 0xfd, 0x1e, 0xd0, 0x09, 0x55, 0xe3, 0x58, 0xe0, 0x13, 0x9c, + 0x14, 0xc8, 0x95, 0xb7, 0x40, 0x5e, 0x9d, 0xe2, 0xe4, 0xe0, 0x7f, 0x80, 0xb5, 0x09, 0x11, 0x47, + 0x5c, 0xa4, 0x98, 0x45, 0xa4, 0x40, 0x5f, 0x78, 0x0b, 0x74, 0x54, 0x02, 0x2a, 0xc5, 0x1e, 0x93, + 0x84, 0x8c, 0xb0, 0xd9, 0xd2, 0x1c, 0xbd, 0xfa, 0x36, 0xb1, 0x4f, 0x71, 0x72, 0xf0, 0x1f, 0xc2, + 0x32, 0xb6, 0xda, 0x70, 0x22, 0xc8, 0x11, 0x3d, 0xf5, 0x6b, 0xe6, 0x40, 0x96, 0x9c, 0xf4, 0xa1, + 0x11, 0xa2, 0x4d, 0x68, 0x24, 0x3c, 0xc2, 0x49, 0x18, 0x13, 0xc6, 0x53, 0x7f, 0xd1, 0xd8, 0x80, + 0x11, 0xed, 0x69, 0x09, 0xfa, 0x1e, 0x80, 0x4e, 0x1e, 0xa7, 0xaf, 0x1b, 0x7d, 0x5d, 0x4b, 0xac, + 0x9a, 0x40, 0x4b, 0x90, 0x98, 0xa4, 0x13, 0xb3, 0x06, 0x81, 0x15, 0xf1, 0x41, 0xdb, 0xec, 0xfe, + 0xfa, 0x8b, 0x17, 0x9b, 0x37, 0xfe, 0xf1, 0x62, 0xf3, 0x47, 0x23, 0xaa, 0xc6, 0xd9, 0xb0, 0x1f, + 0xf1, 0xd4, 0xa5, 0xa6, 0xfb, 0xd9, 0x92, 0xf1, 0xe3, 0x81, 0x7a, 0x3a, 0x21, 0xb2, 0xbf, 0x47, + 0xa2, 0xe7, 0xcf, 0xb6, 0xc0, 0x65, 0xee, 0x1e, 0x89, 0x82, 0xe5, 0x29, 0x68, 0x80, 0x15, 0x41, + 0x0c, 0xd6, 0x13, 0x2c, 0x55, 0x78, 0x7e, 0xae, 0xc6, 0x35, 0xcc, 0x85, 0x34, 0x72, 0x70, 0x76, + 0xbe, 0xdf, 0x02, 0x1c, 0xe3, 0x84, 0xc6, 0x58, 0x71, 0x21, 0xfd, 0x66, 0x67, 0xbe, 0xd7, 0xb8, + 0x73, 0x7b, 0xf6, 0x91, 0xfc, 0x2e, 0xf7, 0x09, 0x4a, 0xee, 0x48, 0xc0, 0x0a, 0x1e, 0x8d, 0x84, + 0x3e, 0x20, 0x12, 0x6a, 0x3f, 0xa6, 0xfc, 0x25, 0x03, 0xb9, 0x7d, 0x05, 0xc8, 0x7d, 0xe3, 0xb8, + 0xbb, 0xfe, 0xf9, 0xcb, 0xcd, 0x95, 0x73, 0x42, 0x19, 0xb4, 0x8a, 0x09, 0xac, 0x44, 0x1f, 0x5b, + 0x9a, 0x25, 0x8a, 0x86, 0x92, 0xb0, 0xd8, 0x5f, 0xee, 0x78, 0xbd, 0xc5, 0xa0, 0x6e, 0x24, 0x07, + 0x84, 0xc5, 0xe8, 0x27, 0xb0, 0x92, 0xd0, 0x27, 0x19, 0x8d, 0xa9, 0x7a, 0x1a, 0xa6, 0x3c, 0xce, + 0x12, 0xe2, 0xb7, 0x8c, 0x51, 0xab, 0x90, 0xdf, 0x37, 0x62, 0xb4, 0x0d, 0xeb, 0xa5, 0x1b, 0x76, + 0x82, 0xa9, 0x1a, 0x09, 0x9e, 0x4d, 0xfc, 0x95, 0x8e, 0xd7, 0x5b, 0x0a, 0xd6, 0xa6, 0xba, 0x4f, + 0x72, 0x15, 0xfa, 0x25, 0xf8, 0x74, 0x18, 0x85, 0x8c, 0x9c, 0xaa, 0x70, 0xba, 0x0f, 0xe1, 0x18, + 0xcb, 0xb1, 0xbf, 0xda, 0xf1, 0x7a, 0xcd, 0xe0, 0x1d, 0x3a, 0x8c, 0x1e, 0x90, 0x53, 0x55, 0x2c, + 0x44, 0x7e, 0x84, 0xe5, 0x18, 0xed, 0x41, 0xbb, 0xb0, 0x0f, 0x25, 0x49, 0x5c, 0xb5, 0xc1, 0x89, + 0x4e, 0x48, 0xfd, 0xd7, 0x47, 0x1d, 0xaf, 0x57, 0x09, 0xbe, 0x5b, 0x58, 0x1d, 0xe4, 0x46, 0x3b, + 0x85, 0x0d, 0x1a, 0xc0, 0xda, 0x98, 0x27, 0x31, 0x65, 0x23, 0x59, 0x76, 0x5d, 0x33, 0xae, 0x28, + 0x57, 0x95, 0x1c, 0x7e, 0x0a, 0xab, 0x26, 0xbb, 0xc8, 0x84, 0x47, 0xe3, 0x70, 0x4c, 0xe8, 0x68, + 0xac, 0xfc, 0xf5, 0x8e, 0xd7, 0x9b, 0x0f, 0x5a, 0x5a, 0x71, 0x4f, 0xcb, 0x3f, 0x32, 0x62, 0xf4, + 0x00, 0xe6, 0xd5, 0x71, 0xe2, 0xbf, 0x73, 0x0d, 0x89, 0xa7, 0x81, 0xf4, 0x49, 0x64, 0x6c, 0xc8, + 0x99, 0x8e, 0x29, 0x9c, 0x10, 0x41, 0x79, 0xec, 0xdf, 0xb4, 0x53, 0x17, 0xf2, 0x87, 0x46, 0x8c, + 0x36, 0x60, 0x31, 0x26, 0x11, 0x4d, 0x71, 0x22, 0xfd, 0x77, 0x8d, 0x49, 0x31, 0x46, 0xb7, 0x61, + 0x75, 0x0a, 0x43, 0x18, 0x1e, 0x26, 0x24, 0xf6, 0x7d, 0x73, 0xa2, 0x53, 0xfc, 0x7b, 0x56, 0xae, + 0xe7, 0x74, 0x65, 0x54, 0x16, 0xb6, 0xb7, 0xec, 0xe9, 0xe7, 0xf2, 0xdc, 0xb4, 0x07, 0x2b, 0x82, + 0xa8, 0x4c, 0xb0, 0x50, 0x71, 0x93, 0x4b, 0x44, 0xf8, 0x1b, 0xc6, 0x74, 0xd9, 0xca, 0x0f, 0xf9, + 0x81, 0x91, 0x76, 0xff, 0x3c, 0x07, 0x30, 0x2d, 0x49, 0xe8, 0x0e, 0xd4, 0xf2, 0x8a, 0x66, 0x98, + 0x62, 0xd7, 0x7f, 0xfe, 0x6c, 0x6b, 0xdd, 0xad, 0xde, 0x15, 0xa9, 0x03, 0x25, 0x28, 0x1b, 0x05, + 0xb9, 0x21, 0x22, 0x50, 0x1b, 0xe2, 0x44, 0x97, 0x48, 0x7f, 0xce, 0xdc, 0x8f, 0x5b, 0x7d, 0xe7, + 0xa0, 0x0b, 0x4e, 0xdf, 0xf1, 0x57, 0xff, 0x2e, 0xa7, 0x6c, 0xf7, 0x3d, 0xbd, 0xf5, 0x9f, 0xbf, + 0xdc, 0xec, 0x5d, 0x62, 0xeb, 0xb5, 0x83, 0x0c, 0x72, 0x6c, 0xf4, 0x1d, 0xa8, 0x4f, 0xb8, 0x50, + 0x21, 0xc3, 0x29, 0x31, 0x24, 0x54, 0x0f, 0x16, 0xb5, 0xe0, 0x01, 0x4e, 0x09, 0xda, 0xfa, 0x9f, + 0x84, 0x52, 0xbf, 0x88, 0x22, 0x6e, 0xc3, 0xaa, 0x83, 0x2d, 0x5d, 0x8d, 0x05, 0x73, 0x35, 0x56, + 0x9c, 0xa2, 0xb8, 0x17, 0xdd, 0x0f, 0xa0, 0xb9, 0x47, 0xa5, 0x12, 0x74, 0x98, 0x99, 0xbc, 0xf3, + 0xa1, 0x76, 0x8c, 0x13, 0x3e, 0x21, 0xc2, 0xb1, 0x69, 0x3e, 0x44, 0x37, 0xa1, 0x8a, 0x53, 0xbd, + 0x8f, 0x86, 0x46, 0x2b, 0x81, 0x1b, 0x75, 0xbf, 0xaa, 0xc0, 0xca, 0x27, 0x45, 0x10, 0x01, 0x89, + 0xb8, 0x38, 0xcb, 0xba, 0xde, 0x59, 0xd6, 0xfd, 0x05, 0xd4, 0x1d, 0x35, 0x70, 0x61, 0x19, 0xf9, + 0x0d, 0xe7, 0x30, 0x35, 0x45, 0x01, 0x34, 0xe3, 0x52, 0xa4, 0xfe, 0xbc, 0x39, 0x8e, 0xfe, 0xec, + 0x72, 0x55, 0x5e, 0x5f, 0x70, 0x06, 0x43, 0xc7, 0x22, 0x48, 0x44, 0x27, 0x54, 0xd7, 0xbf, 0xca, + 0xac, 0x58, 0x0a, 0x53, 0x14, 0x15, 0x7b, 0xb1, 0x70, 0xfd, 0x49, 0xe1, 0xa0, 0xd1, 0x9f, 0xa0, + 0x31, 0xd4, 0x59, 0xee, 0x66, 0xb2, 0x24, 0xfc, 0x86, 0x99, 0x7e, 0xe3, 0x6e, 0xfe, 0x8f, 0x2f, + 0x39, 0xd3, 0xf3, 0x67, 0x5b, 0x0d, 0x07, 0xa6, 0x87, 0x01, 0xe8, 0xd9, 0x76, 0xec, 0xdc, 0x37, + 0xa1, 0xaa, 0x4e, 0x4d, 0x71, 0xb4, 0x14, 0xed, 0x46, 0x5a, 0x2e, 0x15, 0x56, 0x99, 0x34, 0xb4, + 0xbc, 0x10, 0xb8, 0x11, 0xba, 0x0f, 0xad, 0x88, 0xa7, 0x93, 0x84, 0x98, 0xe2, 0xa8, 0x3b, 0x36, + 0xc3, 0xcb, 0x8d, 0x3b, 0x1b, 0x7d, 0xdb, 0xce, 0xf5, 0xf3, 0x76, 0xae, 0x7f, 0x98, 0xb7, 0x73, + 0xbb, 0x8b, 0x3a, 0xe0, 0x4f, 0x5f, 0x6e, 0x7a, 0xc1, 0xf2, 0xd4, 0x59, 0xab, 0x75, 0x59, 0x11, + 0xe4, 0x49, 0x46, 0x32, 0x12, 0x1b, 0xee, 0x5e, 0x0c, 0x8a, 0x71, 0xf7, 0xaf, 0x1e, 0xb4, 0x3e, + 0xce, 0xcb, 0xc7, 0xec, 0x74, 0xfb, 0x3e, 0x34, 0x6d, 0x0d, 0x65, 0x59, 0x3a, 0x24, 0x36, 0xe3, + 0xe6, 0x83, 0x86, 0x91, 0x3d, 0x30, 0x22, 0x9d, 0x05, 0x45, 0xf1, 0xb6, 0x97, 0xef, 0x4d, 0x59, + 0x50, 0x98, 0xea, 0x7e, 0x46, 0x90, 0x04, 0x2b, 0x12, 0x87, 0x6e, 0xb3, 0x2a, 0x9d, 0x79, 0xdd, + 0xcf, 0x38, 0xe9, 0xa1, 0x11, 0x76, 0x3f, 0x9b, 0x03, 0xa4, 0xb9, 0x3c, 0x6f, 0x87, 0xae, 0x25, + 0xe6, 0xf7, 0xa0, 0x2a, 0x79, 0x26, 0x22, 0x32, 0x33, 0x60, 0x67, 0x87, 0xde, 0x87, 0x46, 0x4c, + 0xa4, 0xa2, 0xcc, 0x52, 0xcf, 0xac, 0x6c, 0x2f, 0x1b, 0x97, 0xee, 0xfe, 0x82, 0x09, 0x25, 0x4f, + 0xd1, 0x0b, 0x8e, 0xbd, 0xfa, 0xf6, 0xc7, 0xde, 0xfd, 0xca, 0x83, 0xe5, 0x43, 0x81, 0x99, 0x3c, + 0x22, 0xc2, 0xed, 0x92, 0x5e, 0xa7, 0x2d, 0xf1, 0xde, 0xcc, 0x75, 0x1a, 0xbb, 0xb3, 0x77, 0x7a, + 0xee, 0xf2, 0x77, 0xfa, 0x49, 0xb1, 0xc6, 0xf9, 0x6f, 0xfb, 0xa6, 0xe5, 0xa5, 0xf3, 0xdf, 0x15, + 0xa8, 0x17, 0xed, 0x06, 0xda, 0x81, 0x96, 0xab, 0xb5, 0xe1, 0x65, 0x69, 0x6a, 0xd9, 0x39, 0xec, + 0x14, 0x6c, 0xa5, 0xcf, 0x23, 0xa5, 0x52, 0x16, 0xed, 0xe8, 0xdc, 0x75, 0xb4, 0xbe, 0x53, 0x50, + 0xd3, 0x8a, 0x8e, 0x34, 0x59, 0xbb, 0xba, 0x1c, 0xca, 0x31, 0x16, 0x44, 0xba, 0x34, 0xfc, 0x66, + 0xf3, 0xb4, 0x0a, 0xd4, 0x03, 0x03, 0x8a, 0x42, 0x68, 0x1e, 0x73, 0x65, 0xda, 0x10, 0x7e, 0x42, + 0x84, 0x4b, 0xda, 0xab, 0x4c, 0xb2, 0xcf, 0x54, 0x69, 0x92, 0x7d, 0xa6, 0x82, 0x86, 0x45, 0x7c, + 0xa8, 0x01, 0x51, 0x00, 0x0b, 0x32, 0xe2, 0x82, 0x98, 0xbc, 0xfe, 0xa6, 0xe1, 0x5b, 0xa8, 0x52, + 0x8d, 0xac, 0xda, 0xda, 0xe9, 0x6a, 0xe4, 0x4d, 0xa8, 0xfe, 0x11, 0x53, 0xdd, 0xd8, 0xd4, 0x4c, + 0x49, 0x73, 0x23, 0xd4, 0x06, 0x50, 0x3c, 0x1d, 0x4a, 0xc5, 0x19, 0x89, 0x4d, 0x5d, 0x5d, 0x0c, + 0x4a, 0x12, 0xf4, 0x21, 0x34, 0xad, 0x65, 0x28, 0xa9, 0xee, 0x43, 0xae, 0x52, 0x58, 0x1b, 0xd6, + 0xf3, 0x40, 0x3b, 0x76, 0xff, 0xe2, 0x41, 0x6b, 0x2f, 0xdf, 0x61, 0xd7, 0x94, 0x9f, 0x61, 0x63, + 0xef, 0xf2, 0x6c, 0x8c, 0xa1, 0x66, 0x9f, 0x0d, 0xd2, 0xf5, 0x45, 0xd7, 0xf6, 0x6e, 0xc8, 0x71, + 0xbb, 0x7f, 0xf3, 0xa0, 0x75, 0x4e, 0x8b, 0x76, 0xaf, 0x7e, 0x47, 0xce, 0x3b, 0x20, 0x02, 0xd5, + 0x13, 0xdb, 0x4f, 0xdb, 0xbb, 0x71, 0xff, 0x6a, 0x87, 0xfe, 0x9f, 0x17, 0x9b, 0x4b, 0x4f, 0x71, + 0x9a, 0xbc, 0xdf, 0xb5, 0x28, 0xdd, 0x73, 0x59, 0x50, 0xcd, 0xc5, 0x73, 0x00, 0x7b, 0x45, 0xd1, + 0x47, 0x1f, 0x5e, 0xf8, 0xb2, 0x9e, 0x15, 0xfc, 0x05, 0xaf, 0xe8, 0x7b, 0xb0, 0x3a, 0x7d, 0x90, + 0xe4, 0x38, 0xb3, 0xea, 0xdc, 0x4a, 0xe1, 0x92, 0xc3, 0xfc, 0xff, 0xcb, 0x9d, 0xbe, 0x00, 0xee, + 0x21, 0x53, 0xb1, 0x2c, 0x62, 0x47, 0xba, 0xf7, 0x17, 0x25, 0x7e, 0x0c, 0xf5, 0xf3, 0xd0, 0xf2, + 0x4c, 0xab, 0x2c, 0xbf, 0xc7, 0xe2, 0xee, 0x01, 0xac, 0x3d, 0xe4, 0x42, 0xdd, 0x2d, 0xbe, 0xf0, + 0x1c, 0x66, 0x93, 0xe4, 0x92, 0x5f, 0x82, 0xde, 0x85, 0x9a, 0xe9, 0xb1, 0x8b, 0x0f, 0x41, 0x55, + 0x3d, 0xdc, 0x8f, 0xbb, 0xff, 0x9c, 0x83, 0x5a, 0x40, 0x22, 0x42, 0x27, 0xea, 0x4d, 0xac, 0x3c, + 0xa5, 0xa2, 0xb9, 0x4b, 0x52, 0xd1, 0xb4, 0x8b, 0x9a, 0x3f, 0xd3, 0x45, 0x4d, 0xdb, 0xc7, 0xca, + 0xb7, 0xd7, 0x3e, 0xde, 0x05, 0x38, 0xa2, 0x42, 0xaa, 0x50, 0x12, 0xc2, 0xdc, 0x07, 0xa2, 0x59, + 0x45, 0xc3, 0x33, 0x45, 0xa3, 0x6e, 0xfc, 0x0e, 0x08, 0x61, 0x68, 0x17, 0xea, 0x8e, 0xa3, 0x49, + 0x7c, 0x49, 0x6a, 0x77, 0x18, 0x85, 0xdb, 0xee, 0xa3, 0x2f, 0x5e, 0xb5, 0xbd, 0x2f, 0x5f, 0xb5, + 0xbd, 0x7f, 0xbd, 0x6a, 0x7b, 0x9f, 0xbe, 0x6e, 0xdf, 0xf8, 0xf2, 0x75, 0xfb, 0xc6, 0xdf, 0x5f, + 0xb7, 0x6f, 0x3c, 0xfa, 0xa0, 0xb4, 0x28, 0xca, 0x46, 0x84, 0x65, 0x54, 0x3d, 0xdd, 0x1a, 0x66, + 0x34, 0x89, 0x07, 0xe5, 0x4f, 0x96, 0xa7, 0x17, 0x7c, 0xb4, 0x34, 0x4b, 0x1e, 0x56, 0x4d, 0x10, + 0x3f, 0xff, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x58, 0x46, 0x44, 0xf7, 0xe2, 0x14, 0x00, 0x00, } func (m *Zone) Marshal() (dAtA []byte, err error) { @@ -1594,6 +1602,16 @@ func (m *WithdrawalRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Requeued { + i-- + if m.Requeued { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x50 + } n5, err5 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CompletionTime, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CompletionTime):]) if err5 != nil { return 0, err5 @@ -2395,6 +2413,9 @@ func (m *WithdrawalRecord) Size() (n int) { } l = github_com_gogo_protobuf_types.SizeOfStdTime(m.CompletionTime) n += 1 + l + sovInterchainstaking(uint64(l)) + if m.Requeued { + n += 2 + } return n } @@ -4004,6 +4025,26 @@ func (m *WithdrawalRecord) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Requeued", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowInterchainstaking + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Requeued = bool(v != 0) default: iNdEx = preIndex skippy, err := skipInterchainstaking(dAtA[iNdEx:]) diff --git a/x/interchainstaking/types/keys.go b/x/interchainstaking/types/keys.go index f263a59fd..8d29ac234 100644 --- a/x/interchainstaking/types/keys.go +++ b/x/interchainstaking/types/keys.go @@ -42,22 +42,20 @@ const ( ) var ( - KeyPrefixZone = []byte{0x01} - KeyPrefixIntent = []byte{0x02} - KeyPrefixPortMapping = []byte{0x03} - KeyPrefixReceipt = []byte{0x04} - KeyPrefixWithdrawalRecord = []byte{0x05} - KeyPrefixUnbondingRecord = []byte{0x06} - KeyPrefixDelegation = []byte{0x07} - KeyPrefixPerformanceDelegation = []byte{0x08} - KeyPrefixSnapshotIntent = []byte{0x09} - KeyPrefixRedelegationRecord = []byte{0x10} + KeyPrefixZone = []byte{0x01} + KeyPrefixIntent = []byte{0x02} + KeyPrefixPortMapping = []byte{0x03} + KeyPrefixReceipt = []byte{0x04} + KeyPrefixWithdrawalRecord = []byte{0x05} + KeyPrefixUnbondingRecord = []byte{0x06} + KeyPrefixDelegation = []byte{0x07} + KeyPrefixPerformanceDelegation = []byte{0x08} + KeyPrefixSnapshotIntent = []byte{0x09} + KeyPrefixRequeuedWithdrawalRecordSeq = []byte{0x0a} + // fill in missing 0b - 0f before adding 0x11! + KeyPrefixRedelegationRecord = []byte{0x10} ) -func KeyPrefix(p string) []byte { - return []byte(p) -} - // ParseStakingDelegationKey parses the KV store key for a delegation from Cosmos x/staking module, // as defined here: https://github.com/cosmos/cosmos-sdk/blob/v0.45.6/x/staking/types/keys.go#L180 func ParseStakingDelegationKey(key []byte) (sdk.AccAddress, sdk.ValAddress, error) { diff --git a/x/interchainstaking/types/proposals.go b/x/interchainstaking/types/proposals.go index b4780dfc3..83126e99d 100644 --- a/x/interchainstaking/types/proposals.go +++ b/x/interchainstaking/types/proposals.go @@ -58,6 +58,11 @@ func (m RegisterZoneProposal) ValidateBasic() error { if m.LiquidityModule { return errors.New("liquidity module is unsupported") } + + if m.Decimals == 0 { + return errors.New("decimals field is mandatory") + } + return nil } diff --git a/x/interchainstaking/types/query.pb.go b/x/interchainstaking/types/query.pb.go index 088052f0f..4b1e749eb 100644 --- a/x/interchainstaking/types/query.pb.go +++ b/x/interchainstaking/types/query.pb.go @@ -32,12 +32,13 @@ var _ = math.Inf const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type Statistics struct { - ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - Deposited int64 `protobuf:"varint,2,opt,name=deposited,proto3" json:"deposited,omitempty"` - Deposits int64 `protobuf:"varint,3,opt,name=deposits,proto3" json:"deposits,omitempty"` - Depositors int64 `protobuf:"varint,4,opt,name=depositors,proto3" json:"depositors,omitempty"` - Delegated int64 `protobuf:"varint,5,opt,name=delegated,proto3" json:"delegated,omitempty"` - Supply int64 `protobuf:"varint,6,opt,name=supply,proto3" json:"supply,omitempty"` + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Deposited int64 `protobuf:"varint,2,opt,name=deposited,proto3" json:"deposited,omitempty"` + Deposits int64 `protobuf:"varint,3,opt,name=deposits,proto3" json:"deposits,omitempty"` + Depositors int64 `protobuf:"varint,4,opt,name=depositors,proto3" json:"depositors,omitempty"` + Delegated int64 `protobuf:"varint,5,opt,name=delegated,proto3" json:"delegated,omitempty"` + Supply int64 `protobuf:"varint,6,opt,name=supply,proto3" json:"supply,omitempty"` + DistanceToTarget string `protobuf:"bytes,7,opt,name=distance_to_target,json=distanceToTarget,proto3" json:"distance_to_target,omitempty"` } func (m *Statistics) Reset() { *m = Statistics{} } @@ -115,6 +116,13 @@ func (m *Statistics) GetSupply() int64 { return 0 } +func (m *Statistics) GetDistanceToTarget() string { + if m != nil { + return m.DistanceToTarget + } + return "" +} + type QueryZonesInfoRequest struct { Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -1066,85 +1074,87 @@ func init() { } var fileDescriptor_c8e4d79429548821 = []byte{ - // 1240 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xd8, 0x49, 0x48, 0x5f, 0x04, 0x6d, 0xa6, 0x49, 0xeb, 0x9a, 0xe0, 0x44, 0x8b, 0x44, - 0x5b, 0x94, 0x7a, 0xe5, 0x14, 0xd1, 0x0f, 0xd4, 0x36, 0x71, 0xf3, 0xa1, 0xf0, 0x21, 0xc0, 0x2d, - 0x8a, 0x1a, 0x0e, 0x66, 0xed, 0x1d, 0x36, 0xab, 0x3a, 0x3b, 0xce, 0xee, 0x38, 0x25, 0x54, 0x3d, - 0xc0, 0x1f, 0x80, 0x40, 0x20, 0x04, 0x07, 0xfe, 0x02, 0xc4, 0x05, 0x21, 0x71, 0x85, 0x03, 0x52, - 0x25, 0x40, 0xaa, 0xe0, 0xc2, 0x29, 0x82, 0x04, 0x0e, 0x3d, 0x70, 0xa0, 0x77, 0x24, 0xb4, 0xb3, - 0x6f, 0xd7, 0xeb, 0xb5, 0x5d, 0x6f, 0x36, 0x96, 0xca, 0xcd, 0xf3, 0xf1, 0x7e, 0xf3, 0x7e, 0xbf, - 0x37, 0xf3, 0xf6, 0x97, 0xc0, 0xcc, 0x66, 0xc3, 0xac, 0xde, 0x74, 0xcc, 0xda, 0x16, 0xb3, 0x55, - 0xd3, 0x12, 0xcc, 0xae, 0xae, 0x6b, 0xa6, 0xe5, 0x08, 0xed, 0xa6, 0x69, 0x19, 0xea, 0x56, 0x41, - 0xdd, 0x6c, 0x30, 0x7b, 0x3b, 0x5f, 0xb7, 0xb9, 0xe0, 0x74, 0x3a, 0xb4, 0x3b, 0xdf, 0xb6, 0x3b, - 0xbf, 0x55, 0xc8, 0x8e, 0x1b, 0xdc, 0xe0, 0x72, 0xb3, 0xea, 0xfe, 0xf2, 0xe2, 0xb2, 0x27, 0xaa, - 0xdc, 0xd9, 0xe0, 0x4e, 0xd9, 0x5b, 0xf0, 0x06, 0xb8, 0x34, 0x69, 0x70, 0x6e, 0xd4, 0x98, 0xaa, - 0xd5, 0x4d, 0x55, 0xb3, 0x2c, 0x2e, 0x34, 0x61, 0x72, 0xcb, 0x5f, 0x7d, 0xd6, 0xdb, 0xab, 0x56, - 0x34, 0x87, 0x79, 0x99, 0xa8, 0x5b, 0x85, 0x0a, 0x13, 0x5a, 0x41, 0xad, 0x6b, 0x86, 0x69, 0xc9, - 0xcd, 0xb8, 0xf7, 0x7c, 0x4f, 0x2a, 0xed, 0x19, 0xcb, 0x48, 0xe5, 0x5b, 0x02, 0x70, 0xcd, 0x3d, - 0xd8, 0x11, 0x66, 0xd5, 0xa1, 0x27, 0x60, 0x44, 0x6e, 0x2a, 0x9b, 0x7a, 0x86, 0x4c, 0x93, 0x53, - 0x87, 0x4a, 0x8f, 0xc9, 0xf1, 0x8a, 0x4e, 0x27, 0xe1, 0x90, 0xce, 0xea, 0xdc, 0x31, 0x05, 0xd3, - 0x33, 0xa9, 0x69, 0x72, 0x2a, 0x5d, 0x6a, 0x4e, 0xd0, 0x2c, 0x8c, 0xe0, 0xc0, 0xc9, 0xa4, 0xe5, - 0x62, 0x30, 0xa6, 0x39, 0x00, 0xfc, 0xcd, 0x6d, 0x27, 0x33, 0x28, 0x57, 0x43, 0x33, 0x1e, 0x72, - 0x8d, 0x19, 0x9a, 0x8b, 0x3c, 0xe4, 0x23, 0xe3, 0x04, 0x3d, 0x06, 0xc3, 0x4e, 0xa3, 0x5e, 0xaf, - 0x6d, 0x67, 0x86, 0xe5, 0x12, 0x8e, 0x94, 0x32, 0x4c, 0xbc, 0xee, 0xaa, 0xb2, 0xc6, 0x2d, 0xe6, - 0xac, 0x58, 0x6f, 0xf3, 0x12, 0xdb, 0x6c, 0x30, 0x47, 0xd0, 0x25, 0x80, 0xa6, 0x40, 0x92, 0xc5, - 0xe8, 0xec, 0x33, 0x79, 0x54, 0xde, 0x55, 0x33, 0xef, 0xd5, 0x15, 0xd5, 0xcc, 0xbf, 0xa6, 0x19, - 0x0c, 0x63, 0x4b, 0xa1, 0x48, 0xe5, 0x3e, 0x81, 0x63, 0xd1, 0x13, 0x9c, 0x3a, 0xb7, 0x1c, 0x46, - 0x8b, 0x30, 0xf4, 0xae, 0x3b, 0x99, 0x21, 0xd3, 0x69, 0x89, 0xde, 0xeb, 0x72, 0xe4, 0x5d, 0x8c, - 0xe2, 0xe0, 0xdd, 0x9d, 0xa9, 0x81, 0x92, 0x17, 0xea, 0x62, 0x38, 0x42, 0x13, 0x4e, 0x26, 0x25, - 0x31, 0x66, 0x7a, 0x63, 0x34, 0xeb, 0x54, 0xf2, 0x42, 0xe9, 0x72, 0x0b, 0xd5, 0xb4, 0xa4, 0x7a, - 0xb2, 0x27, 0x55, 0x8f, 0x44, 0x0b, 0xd7, 0x25, 0x18, 0x0f, 0xa8, 0x86, 0xb5, 0xcc, 0x47, 0xef, - 0x43, 0xf1, 0xe8, 0x83, 0x9d, 0xa9, 0xc3, 0xdb, 0xda, 0x46, 0xed, 0xa2, 0xe2, 0xaf, 0x28, 0xc1, - 0x25, 0x51, 0xbe, 0x20, 0xa1, 0xaa, 0xb4, 0x48, 0x36, 0x07, 0x83, 0x2e, 0xef, 0xa0, 0x1e, 0xfb, - 0x51, 0x4c, 0x46, 0x86, 0x05, 0x23, 0x09, 0x05, 0x53, 0xae, 0x83, 0x22, 0xd3, 0x5b, 0xf0, 0x6e, - 0xdf, 0x7c, 0xb5, 0xca, 0x1b, 0x96, 0x58, 0xe2, 0xf6, 0x55, 0x37, 0x34, 0x29, 0xeb, 0xf7, 0x08, - 0x3c, 0xfd, 0x50, 0x58, 0xd4, 0x60, 0x0d, 0x8e, 0xe3, 0xb5, 0x2f, 0x6b, 0xde, 0x96, 0xb2, 0xa6, - 0xeb, 0x36, 0x73, 0x1c, 0x3c, 0x46, 0x79, 0xb0, 0x33, 0x95, 0xf3, 0x8e, 0xe9, 0xb2, 0x51, 0x29, - 0x4d, 0xe8, 0x2d, 0x87, 0xcc, 0xe3, 0xfc, 0x27, 0x04, 0x9e, 0xc4, 0x1c, 0xe4, 0xcb, 0xe1, 0xf6, - 0x8a, 0x25, 0x98, 0x25, 0x12, 0x72, 0xa2, 0x8b, 0x30, 0xa6, 0xfb, 0x48, 0x41, 0x96, 0x29, 0x19, - 0x98, 0xf9, 0xe5, 0x9b, 0x33, 0xe3, 0x78, 0xc9, 0xf0, 0xf8, 0x6b, 0xc2, 0x36, 0x2d, 0xa3, 0x74, - 0x24, 0x08, 0xf1, 0xd3, 0x32, 0x61, 0xb2, 0x73, 0x56, 0x28, 0xc9, 0x0a, 0x0c, 0x9b, 0x72, 0x06, - 0x2f, 0x46, 0xa1, 0x77, 0x55, 0xa3, 0x50, 0x08, 0xa0, 0x7c, 0x44, 0xe0, 0x78, 0xf8, 0x2c, 0xb7, - 0x97, 0x26, 0x65, 0xdf, 0xda, 0x43, 0x52, 0x89, 0x7b, 0xc8, 0x8f, 0x04, 0x32, 0xed, 0x39, 0x21, - 0xf7, 0xeb, 0x30, 0xaa, 0x37, 0xa7, 0xb1, 0x97, 0xcc, 0xc4, 0x16, 0xc0, 0xe4, 0x16, 0xbe, 0x8f, - 0x30, 0x0c, 0x3d, 0x02, 0x69, 0xb1, 0x55, 0xc3, 0x0e, 0xed, 0xfe, 0xec, 0x5f, 0x97, 0xf8, 0x80, - 0x60, 0x9b, 0x28, 0xb1, 0x2a, 0x33, 0xeb, 0xe2, 0x91, 0xcb, 0xfb, 0x95, 0xdf, 0x6e, 0x9a, 0x09, - 0xa1, 0xb6, 0x2f, 0xc1, 0x88, 0x8d, 0x73, 0x28, 0xec, 0xe9, 0xde, 0xc2, 0x22, 0x0a, 0xaa, 0x1a, - 0x00, 0x44, 0x04, 0x4c, 0x25, 0x17, 0x70, 0x87, 0xc0, 0x53, 0x32, 0xdf, 0x55, 0x53, 0xac, 0xeb, - 0xb6, 0x76, 0x4b, 0xab, 0x95, 0x58, 0x95, 0xdb, 0xba, 0xf3, 0x68, 0x9f, 0x69, 0xa4, 0x20, 0xe9, - 0xc4, 0x05, 0xf9, 0x81, 0x40, 0xae, 0x1b, 0xc1, 0xa0, 0x09, 0x8e, 0xde, 0x0a, 0x16, 0xfd, 0xe2, - 0xcc, 0xf6, 0x2e, 0x4e, 0x14, 0xd1, 0xbf, 0xfb, 0x21, 0xb0, 0xfe, 0x15, 0xea, 0x53, 0x82, 0x7d, - 0xeb, 0x0d, 0xab, 0xc2, 0x2d, 0xdd, 0x15, 0xed, 0x60, 0x75, 0xea, 0x97, 0xc0, 0xdf, 0xfb, 0x37, - 0xa8, 0x3d, 0x31, 0xd4, 0x77, 0x15, 0xa0, 0xe1, 0xaf, 0xf9, 0xf2, 0xc6, 0xe8, 0xaa, 0x11, 0x3c, - 0x54, 0x37, 0x04, 0xd5, 0x3f, 0x71, 0x3f, 0x27, 0x30, 0x85, 0xaf, 0xb6, 0xd9, 0xb8, 0xfa, 0xaa, - 0x6f, 0xf2, 0x8e, 0xf2, 0x33, 0x81, 0xe9, 0xee, 0xb9, 0xa1, 0xc4, 0x6f, 0xc1, 0xe3, 0x36, 0x6b, - 0x6f, 0xdd, 0xcf, 0xc5, 0xe9, 0x30, 0x51, 0x54, 0x14, 0xba, 0x15, 0xb0, 0x6f, 0x5a, 0xcf, 0x7e, - 0x36, 0x06, 0x43, 0x92, 0x0f, 0xfd, 0x92, 0xc0, 0x90, 0x74, 0xb2, 0xf4, 0x5c, 0xef, 0x3c, 0x3b, - 0x3a, 0xeb, 0xec, 0xf9, 0xfd, 0x07, 0x7a, 0x29, 0x29, 0xea, 0xfb, 0xbf, 0xfe, 0xf9, 0x71, 0xea, - 0x34, 0x3d, 0xa9, 0xf6, 0xfc, 0x4b, 0xc5, 0x73, 0xc7, 0x5f, 0x13, 0x18, 0x74, 0x61, 0xe8, 0xf3, - 0xfb, 0x38, 0x33, 0x9c, 0xeb, 0xb9, 0x7d, 0xc7, 0x61, 0xaa, 0x17, 0x64, 0xaa, 0x67, 0x69, 0x21, - 0x5e, 0xaa, 0xea, 0x6d, 0xff, 0x36, 0xde, 0xa1, 0xf7, 0x09, 0x3c, 0xd1, 0x6a, 0x01, 0xe9, 0x42, - 0xcc, 0x34, 0x1e, 0x6a, 0x48, 0xb3, 0x8b, 0x07, 0x44, 0x41, 0x6a, 0x2f, 0x4a, 0x6a, 0x0b, 0xb4, - 0x18, 0xb3, 0x0a, 0x21, 0x6e, 0x6a, 0xe0, 0x47, 0xf1, 0x8b, 0xf1, 0x0f, 0x81, 0xc3, 0x11, 0x27, - 0x46, 0x2f, 0xc5, 0x4e, 0xb3, 0x93, 0x45, 0xcd, 0x5e, 0x4e, 0x1a, 0x8e, 0xf4, 0xca, 0x92, 0xde, - 0x0d, 0xba, 0x9a, 0x88, 0x9e, 0xff, 0x11, 0xf5, 0xdc, 0xa4, 0x7a, 0xbb, 0xed, 0xb3, 0x7a, 0x87, - 0xfe, 0x44, 0x60, 0x34, 0x64, 0xe4, 0xe8, 0x85, 0xfd, 0x25, 0x1c, 0x32, 0xa4, 0xd9, 0x8b, 0x49, - 0x42, 0x91, 0xe7, 0x92, 0xe4, 0x39, 0x47, 0x2f, 0x27, 0xe7, 0x29, 0xd3, 0xff, 0x8e, 0xc0, 0x88, - 0x6f, 0x9c, 0x62, 0xbf, 0xb3, 0x88, 0xf5, 0x8b, 0xfd, 0xce, 0xa2, 0x0e, 0x4d, 0xb9, 0x2a, 0x59, - 0x5c, 0xa2, 0x2f, 0x24, 0x60, 0x11, 0x38, 0xb3, 0x7f, 0x09, 0x4c, 0xb8, 0x2f, 0xb8, 0xcd, 0x6e, - 0xd0, 0x2b, 0x31, 0xf3, 0xea, 0xe6, 0xc4, 0xb2, 0x73, 0xc9, 0x01, 0x90, 0xa1, 0x26, 0x19, 0xbe, - 0x49, 0x6f, 0x24, 0x60, 0xd8, 0x74, 0x35, 0x65, 0xdb, 0x83, 0xed, 0x78, 0x23, 0xff, 0x22, 0x30, - 0xf6, 0xbf, 0xe4, 0xfe, 0x8a, 0xe4, 0xbe, 0x4c, 0x17, 0xfb, 0xc2, 0x9d, 0xfe, 0x41, 0xe0, 0x48, - 0xd4, 0xf1, 0xd0, 0xb8, 0xfd, 0xa2, 0x8b, 0x87, 0xcb, 0x5e, 0x49, 0x1c, 0x8f, 0x24, 0x5f, 0x96, - 0x24, 0x97, 0xe8, 0x42, 0x02, 0x92, 0x81, 0xb1, 0x0a, 0x38, 0xfe, 0x4d, 0xe0, 0x68, 0x07, 0xd7, - 0x41, 0xe7, 0x63, 0xbf, 0xb0, 0x6e, 0x6e, 0x2a, 0x5b, 0x3c, 0x08, 0x04, 0x92, 0x7d, 0x55, 0x92, - 0x5d, 0xa1, 0xcb, 0x89, 0xde, 0x6b, 0x13, 0xd7, 0xe7, 0x5b, 0x5c, 0xbb, 0xbb, 0x9b, 0x23, 0xf7, - 0x76, 0x73, 0xe4, 0xf7, 0xdd, 0x1c, 0xf9, 0x70, 0x2f, 0x37, 0x70, 0x6f, 0x2f, 0x37, 0xf0, 0xdb, - 0x5e, 0x6e, 0x60, 0x6d, 0xce, 0x30, 0xc5, 0x7a, 0xa3, 0x92, 0xaf, 0xf2, 0x0d, 0xd5, 0xb4, 0x0c, - 0x66, 0x35, 0x4c, 0xb1, 0x7d, 0xa6, 0xd2, 0x30, 0x6b, 0x7a, 0xcb, 0xe1, 0xef, 0x74, 0x38, 0x5e, - 0x6c, 0xd7, 0x99, 0x53, 0x19, 0x96, 0xff, 0xdd, 0x3c, 0xfb, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x77, 0x33, 0xa5, 0x32, 0xe4, 0x15, 0x00, 0x00, + // 1268 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcd, 0x6f, 0x1b, 0xc5, + 0x1b, 0xce, 0xd8, 0x49, 0x9a, 0xbe, 0xd1, 0xef, 0xd7, 0x74, 0xda, 0xb4, 0xae, 0x09, 0x4e, 0xb4, + 0x48, 0xb4, 0x45, 0xa9, 0x57, 0x4e, 0x11, 0xfd, 0x40, 0x6d, 0x13, 0x37, 0x1f, 0x0a, 0x1f, 0x02, + 0xdc, 0xa0, 0xa8, 0xe1, 0x60, 0xd6, 0xde, 0x61, 0x33, 0xaa, 0xb3, 0xe3, 0xec, 0x8c, 0x53, 0x42, + 0xd5, 0x03, 0xfc, 0x01, 0x08, 0x04, 0x42, 0x70, 0xe0, 0x2f, 0x40, 0x5c, 0x10, 0x7f, 0x00, 0x1c, + 0x90, 0x2a, 0x01, 0x52, 0x05, 0x17, 0x4e, 0x11, 0x24, 0xf4, 0xd0, 0x03, 0x07, 0x7a, 0x47, 0x42, + 0x3b, 0x3b, 0xbb, 0x5e, 0xaf, 0xed, 0x7a, 0xb3, 0xb1, 0x54, 0x6e, 0x9e, 0x8f, 0xf7, 0x99, 0xe7, + 0x79, 0xde, 0x99, 0x77, 0xdf, 0x04, 0xa6, 0x37, 0x1b, 0xb4, 0x7a, 0x8b, 0xd3, 0xda, 0x16, 0x71, + 0x74, 0x6a, 0x0b, 0xe2, 0x54, 0xd7, 0x0d, 0x6a, 0x73, 0x61, 0xdc, 0xa2, 0xb6, 0xa5, 0x6f, 0x15, + 0xf4, 0xcd, 0x06, 0x71, 0xb6, 0xf3, 0x75, 0x87, 0x09, 0x86, 0xa7, 0x42, 0xbb, 0xf3, 0x6d, 0xbb, + 0xf3, 0x5b, 0x85, 0xec, 0x71, 0x8b, 0x59, 0x4c, 0x6e, 0xd6, 0xdd, 0x5f, 0x5e, 0x5c, 0xf6, 0x54, + 0x95, 0xf1, 0x0d, 0xc6, 0xcb, 0xde, 0x82, 0x37, 0x50, 0x4b, 0x13, 0x16, 0x63, 0x56, 0x8d, 0xe8, + 0x46, 0x9d, 0xea, 0x86, 0x6d, 0x33, 0x61, 0x08, 0xca, 0x6c, 0x7f, 0xf5, 0x39, 0x6f, 0xaf, 0x5e, + 0x31, 0x38, 0xf1, 0x98, 0xe8, 0x5b, 0x85, 0x0a, 0x11, 0x46, 0x41, 0xaf, 0x1b, 0x16, 0xb5, 0xe5, + 0x66, 0xb5, 0xf7, 0x62, 0x4f, 0x29, 0xed, 0x8c, 0x65, 0xa4, 0xf6, 0x00, 0x01, 0xdc, 0x70, 0x0f, + 0xe6, 0x82, 0x56, 0x39, 0x3e, 0x05, 0x23, 0x72, 0x53, 0x99, 0x9a, 0x19, 0x34, 0x85, 0xce, 0x1c, + 0x2e, 0x1d, 0x92, 0xe3, 0x65, 0x13, 0x4f, 0xc0, 0x61, 0x93, 0xd4, 0x19, 0xa7, 0x82, 0x98, 0x99, + 0xd4, 0x14, 0x3a, 0x93, 0x2e, 0x35, 0x27, 0x70, 0x16, 0x46, 0xd4, 0x80, 0x67, 0xd2, 0x72, 0x31, + 0x18, 0xe3, 0x1c, 0x80, 0xfa, 0xcd, 0x1c, 0x9e, 0x19, 0x94, 0xab, 0xa1, 0x19, 0x0f, 0xb9, 0x46, + 0x2c, 0xc3, 0x45, 0x1e, 0xf2, 0x91, 0xd5, 0x04, 0x3e, 0x01, 0xc3, 0xbc, 0x51, 0xaf, 0xd7, 0xb6, + 0x33, 0xc3, 0x72, 0x49, 0x8d, 0xf0, 0x34, 0x60, 0x93, 0x72, 0x61, 0xd8, 0x55, 0x52, 0x16, 0xac, + 0x2c, 0x0c, 0xc7, 0x22, 0x22, 0x73, 0x48, 0x92, 0x1e, 0xf3, 0x57, 0x56, 0xd8, 0x8a, 0x9c, 0xd7, + 0xca, 0x30, 0xfe, 0x86, 0xeb, 0xe1, 0x1a, 0xb3, 0x09, 0x5f, 0xb6, 0xdf, 0x61, 0x25, 0xb2, 0xd9, + 0x20, 0x5c, 0xe0, 0x45, 0x80, 0xa6, 0x9d, 0x52, 0xf3, 0xe8, 0xcc, 0xb3, 0x79, 0x95, 0x27, 0xd7, + 0xfb, 0xbc, 0x77, 0x0b, 0x94, 0xf7, 0xf9, 0xd7, 0x0d, 0x8b, 0xa8, 0xd8, 0x52, 0x28, 0x52, 0x7b, + 0x88, 0xe0, 0x44, 0xf4, 0x04, 0x5e, 0x67, 0x36, 0x27, 0xb8, 0x08, 0x43, 0xef, 0xb9, 0x93, 0x19, + 0x34, 0x95, 0x96, 0xe8, 0xbd, 0xae, 0x52, 0xde, 0xc5, 0x28, 0x0e, 0xde, 0xdb, 0x99, 0x1c, 0x28, + 0x79, 0xa1, 0x2e, 0x06, 0x17, 0x86, 0xe0, 0x99, 0x94, 0xc4, 0x98, 0xee, 0x8d, 0xd1, 0xcc, 0x6a, + 0xc9, 0x0b, 0xc5, 0x4b, 0x2d, 0x52, 0xd3, 0x52, 0xea, 0xe9, 0x9e, 0x52, 0x3d, 0x11, 0x2d, 0x5a, + 0x17, 0xe1, 0x78, 0x20, 0x35, 0xec, 0x65, 0x3e, 0x7a, 0x7b, 0x8a, 0xc7, 0x1e, 0xed, 0x4c, 0x1e, + 0xd9, 0x36, 0x36, 0x6a, 0x97, 0x35, 0x7f, 0x45, 0x0b, 0xae, 0x94, 0xf6, 0x25, 0x0a, 0x65, 0xa5, + 0xc5, 0xb2, 0x59, 0x18, 0x74, 0x75, 0x07, 0xf9, 0xd8, 0x8f, 0x63, 0x32, 0x32, 0x6c, 0x18, 0x4a, + 0x68, 0x98, 0xb6, 0x02, 0x9a, 0xa4, 0x37, 0xef, 0xdd, 0xd5, 0xb9, 0x6a, 0x95, 0x35, 0x6c, 0xb1, + 0xc8, 0x9c, 0xeb, 0x6e, 0x68, 0x52, 0xd5, 0xef, 0x23, 0x78, 0xe6, 0xb1, 0xb0, 0xca, 0x83, 0x35, + 0x38, 0xa9, 0x1e, 0x49, 0xd9, 0xf0, 0xb6, 0x94, 0x0d, 0xd3, 0x74, 0x08, 0xe7, 0xea, 0x18, 0xed, + 0xd1, 0xce, 0x64, 0xce, 0x3b, 0xa6, 0xcb, 0x46, 0xad, 0x34, 0x6e, 0xb6, 0x1c, 0x32, 0xa7, 0xe6, + 0x3f, 0x45, 0xf0, 0x94, 0xe2, 0x20, 0xdf, 0x19, 0x73, 0x96, 0x6d, 0x41, 0x6c, 0x91, 0x50, 0x13, + 0x5e, 0x80, 0xa3, 0xa6, 0x8f, 0x14, 0xb0, 0x4c, 0xc9, 0xc0, 0xcc, 0x2f, 0xdf, 0x9e, 0x3b, 0xae, + 0x2e, 0x99, 0x3a, 0xfe, 0x86, 0x70, 0xa8, 0x6d, 0x95, 0xc6, 0x82, 0x10, 0x9f, 0x16, 0x85, 0x89, + 0xce, 0xac, 0x94, 0x25, 0xcb, 0x30, 0x4c, 0xe5, 0x8c, 0xba, 0x18, 0x85, 0xde, 0x59, 0x8d, 0x42, + 0x29, 0x00, 0xed, 0x63, 0x04, 0x27, 0xc3, 0x67, 0xb9, 0x95, 0x37, 0xa9, 0xfa, 0xd6, 0x1a, 0x92, + 0x4a, 0x5c, 0x43, 0x7e, 0x44, 0x90, 0x69, 0xe7, 0xa4, 0xb4, 0xaf, 0xc0, 0xa8, 0xd9, 0x9c, 0x56, + 0xb5, 0x64, 0x3a, 0xb6, 0x01, 0x94, 0xd9, 0xea, 0x7d, 0x84, 0x61, 0xf0, 0x18, 0xa4, 0xc5, 0x56, + 0x4d, 0xd5, 0x73, 0xf7, 0x67, 0xff, 0xaa, 0xc4, 0x87, 0x48, 0x95, 0x89, 0x12, 0xa9, 0x12, 0x5a, + 0x17, 0x4f, 0xdc, 0xde, 0xaf, 0xfd, 0x72, 0xd3, 0x24, 0xa4, 0xbc, 0x7d, 0x19, 0x46, 0x1c, 0x35, + 0xa7, 0x8c, 0x3d, 0xdb, 0xdb, 0x58, 0x85, 0xa2, 0x5c, 0x0d, 0x00, 0x22, 0x06, 0xa6, 0x92, 0x1b, + 0xb8, 0x83, 0xe0, 0x69, 0xc9, 0x77, 0x95, 0x8a, 0x75, 0xd3, 0x31, 0x6e, 0x1b, 0xb5, 0x12, 0xa9, + 0x32, 0xc7, 0xe4, 0x4f, 0xf6, 0x99, 0x46, 0x12, 0x92, 0x4e, 0x9c, 0x90, 0x1f, 0x10, 0xe4, 0xba, + 0x09, 0x0c, 0x8a, 0xe0, 0xe8, 0xed, 0x60, 0xd1, 0x4f, 0xce, 0x4c, 0xef, 0xe4, 0x44, 0x11, 0xfd, + 0xbb, 0x1f, 0x02, 0xeb, 0x5f, 0xa2, 0x3e, 0x43, 0xaa, 0x6e, 0xbd, 0x69, 0x57, 0x98, 0x6d, 0xba, + 0xa6, 0x1d, 0x2c, 0x4f, 0xfd, 0x32, 0xf8, 0x7b, 0xff, 0x06, 0xb5, 0x13, 0x53, 0xfe, 0xae, 0x02, + 0x34, 0xfc, 0x35, 0xdf, 0xde, 0x18, 0x55, 0x35, 0x82, 0xa7, 0xdc, 0x0d, 0x41, 0xf5, 0xcf, 0xdc, + 0x2f, 0x10, 0x4c, 0xaa, 0x57, 0xdb, 0x2c, 0x5c, 0x7d, 0xf5, 0x37, 0x79, 0x45, 0xf9, 0x19, 0xc1, + 0x54, 0x77, 0x6e, 0xca, 0xe2, 0xb7, 0xe1, 0x7f, 0x0e, 0x69, 0x2f, 0xdd, 0xcf, 0xc7, 0xa9, 0x30, + 0x51, 0x54, 0x65, 0x74, 0x2b, 0x60, 0xdf, 0xbc, 0x9e, 0xf9, 0xfc, 0x28, 0x0c, 0x49, 0x3d, 0xf8, + 0x2b, 0x04, 0x43, 0xb2, 0x93, 0xc5, 0x17, 0x7a, 0xf3, 0xec, 0xd8, 0x59, 0x67, 0x2f, 0xee, 0x3f, + 0xd0, 0xa3, 0xa4, 0xe9, 0x1f, 0xfc, 0xfa, 0xe7, 0x27, 0xa9, 0xb3, 0xf8, 0xb4, 0xde, 0xf3, 0xef, + 0x1a, 0xaf, 0x3b, 0xfe, 0x06, 0xc1, 0xa0, 0x0b, 0x83, 0x5f, 0xd8, 0xc7, 0x99, 0x61, 0xae, 0x17, + 0xf6, 0x1d, 0xa7, 0xa8, 0x5e, 0x92, 0x54, 0xcf, 0xe3, 0x42, 0x3c, 0xaa, 0xfa, 0x1d, 0xff, 0x36, + 0xde, 0xc5, 0x0f, 0x11, 0xfc, 0xbf, 0xb5, 0x05, 0xc4, 0xf3, 0x31, 0x69, 0x3c, 0xb6, 0x21, 0xcd, + 0x2e, 0x1c, 0x10, 0x45, 0x49, 0x7b, 0x49, 0x4a, 0x9b, 0xc7, 0xc5, 0x98, 0x59, 0x08, 0x69, 0xd3, + 0x83, 0x7e, 0x54, 0x7d, 0x31, 0xfe, 0x46, 0x70, 0x24, 0xd2, 0x89, 0xe1, 0x2b, 0xb1, 0x69, 0x76, + 0x6a, 0x51, 0xb3, 0x57, 0x93, 0x86, 0x2b, 0x79, 0x65, 0x29, 0xef, 0x26, 0x5e, 0x4d, 0x24, 0xcf, + 0xff, 0x88, 0x7a, 0xdd, 0xa4, 0x7e, 0xa7, 0xed, 0xb3, 0x7a, 0x17, 0xff, 0x84, 0x60, 0x34, 0xd4, + 0xc8, 0xe1, 0x4b, 0xfb, 0x23, 0x1c, 0x6a, 0x48, 0xb3, 0x97, 0x93, 0x84, 0x2a, 0x9d, 0x8b, 0x52, + 0xe7, 0x2c, 0xbe, 0x9a, 0x5c, 0xa7, 0xa4, 0xff, 0x1d, 0x82, 0x11, 0xbf, 0x71, 0x8a, 0xfd, 0xce, + 0x22, 0xad, 0x5f, 0xec, 0x77, 0x16, 0xed, 0xd0, 0xb4, 0xeb, 0x52, 0xc5, 0x15, 0xfc, 0x62, 0x02, + 0x15, 0x41, 0x67, 0xf6, 0x0f, 0x82, 0x71, 0xf7, 0x05, 0xb7, 0xb5, 0x1b, 0xf8, 0x5a, 0x4c, 0x5e, + 0xdd, 0x3a, 0xb1, 0xec, 0x6c, 0x72, 0x00, 0xa5, 0xd0, 0x90, 0x0a, 0xdf, 0xc2, 0x37, 0x13, 0x28, + 0x6c, 0x76, 0x35, 0x65, 0xc7, 0x83, 0xed, 0x78, 0x23, 0x1f, 0x20, 0x38, 0xfa, 0x9f, 0xd4, 0xfe, + 0xaa, 0xd4, 0xbe, 0x84, 0x17, 0xfa, 0xa2, 0x1d, 0xff, 0x81, 0x60, 0x2c, 0xda, 0xf1, 0xe0, 0xb8, + 0xf5, 0xa2, 0x4b, 0x0f, 0x97, 0xbd, 0x96, 0x38, 0x5e, 0x89, 0x7c, 0x45, 0x8a, 0x5c, 0xc4, 0xf3, + 0x09, 0x44, 0x06, 0x8d, 0x55, 0xa0, 0xf1, 0x2f, 0x04, 0xc7, 0x3a, 0x74, 0x1d, 0x78, 0x2e, 0xf6, + 0x0b, 0xeb, 0xd6, 0x4d, 0x65, 0x8b, 0x07, 0x81, 0x50, 0x62, 0x5f, 0x93, 0x62, 0x97, 0xf1, 0x52, + 0xa2, 0xf7, 0xda, 0xc4, 0xf5, 0xf5, 0x16, 0xd7, 0xee, 0xed, 0xe6, 0xd0, 0xfd, 0xdd, 0x1c, 0xfa, + 0x7d, 0x37, 0x87, 0x3e, 0xda, 0xcb, 0x0d, 0xdc, 0xdf, 0xcb, 0x0d, 0xfc, 0xb6, 0x97, 0x1b, 0x58, + 0x9b, 0xb5, 0xa8, 0x58, 0x6f, 0x54, 0xf2, 0x55, 0xb6, 0xa1, 0x53, 0xdb, 0x22, 0x76, 0x83, 0x8a, + 0xed, 0x73, 0x95, 0x06, 0xad, 0x99, 0x2d, 0x87, 0xbf, 0xdb, 0xe1, 0x78, 0xb1, 0x5d, 0x27, 0xbc, + 0x32, 0x2c, 0xff, 0x17, 0x7a, 0xfe, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x82, 0x0b, 0x1e, + 0x12, 0x16, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1593,6 +1603,13 @@ func (m *Statistics) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.DistanceToTarget) > 0 { + i -= len(m.DistanceToTarget) + copy(dAtA[i:], m.DistanceToTarget) + i = encodeVarintQuery(dAtA, i, uint64(len(m.DistanceToTarget))) + i-- + dAtA[i] = 0x3a + } if m.Supply != 0 { i = encodeVarintQuery(dAtA, i, uint64(m.Supply)) i-- @@ -2436,6 +2453,10 @@ func (m *Statistics) Size() (n int) { if m.Supply != 0 { n += 1 + sovQuery(uint64(m.Supply)) } + l = len(m.DistanceToTarget) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -2910,6 +2931,38 @@ func (m *Statistics) Unmarshal(dAtA []byte) error { break } } + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DistanceToTarget", 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.DistanceToTarget = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:])