diff --git a/.gitmodules b/.gitmodules index ac88c34b0e..e826f596bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,7 +18,7 @@ path = deps/juno url = https://github.com/CosmosContracts/juno.git [submodule "deps/osmosis"] - # Commit: v16.1.1-no-fees + # Commit: v20.5.0-no-fees path = deps/osmosis url = https://github.com/Stride-Labs/osmosis.git [submodule "deps/stargaze"] diff --git a/Makefile b/Makefile index b095fe8142..99632af020 100644 --- a/Makefile +++ b/Makefile @@ -151,6 +151,12 @@ upgrade-integration-tests-part-1: start-docker-all start-upgrade-integration-tes setup-ics: UPGRADE_HEIGHT=150 bash $(DOCKERNET_HOME)/upgrades/setup_ics.sh +############################################################################### +### LocalNet ### +############################################################################### +start-local-node: + @bash scripts/start_local_node.sh + ############################################################################### ### Local to Mainnet ### ############################################################################### diff --git a/README.md b/README.md index 175067eaf5..95e3e98325 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ close soup mirror crew erode defy knock trigger gather eyebrow tent farm gym glo This mnemonic will have tokens on every chain running locally. #### Running integration tests -Ensure submoules are updated +Ensure submodules are updated ``` git submodule update --init --recursive ``` diff --git a/app/app.go b/app/app.go index d42ca579e3..804b23dd22 100644 --- a/app/app.go +++ b/app/app.go @@ -590,6 +590,7 @@ func NewStrideApp( keys[stakeibcmoduletypes.StoreKey], keys[stakeibcmoduletypes.MemStoreKey], app.GetSubspace(stakeibcmoduletypes.ModuleName), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), app.AccountKeeper, app.BankKeeper, app.ICAControllerKeeper, diff --git a/app/apptesting/test_helpers.go b/app/apptesting/test_helpers.go index 6ad11e6f32..ee6432706a 100644 --- a/app/apptesting/test_helpers.go +++ b/app/apptesting/test_helpers.go @@ -12,6 +12,8 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/cosmos/gogoproto/proto" @@ -231,7 +233,10 @@ func (s *AppTestHelper) CreateICAChannel(owner string) (channelID, portID string _, transferChannelExists := s.App.IBCKeeper.ChannelKeeper.GetChannel(s.Ctx, ibctesting.TransferPort, ibctesting.FirstChannelID) if !transferChannelExists { ownerSplit := strings.Split(owner, ".") - s.Require().Equal(2, len(ownerSplit), "owner should be of the form: {HostZone}.{AccountName}") + isHostZoneICA := len(ownerSplit) == 2 + isTradeRouteICA := len(ownerSplit) == 3 + s.Require().True(isHostZoneICA || isTradeRouteICA, + "owner should be either of the form: {chainId}.{AccountName} or {chainId}.{rewarDenom}-{hostDenom}.{accountName}") hostChainID := ownerSplit[0] s.CreateTransferChannel(hostChainID) @@ -352,6 +357,34 @@ func (s *AppTestHelper) UpdateChannelState(portId, channelId string, channelStat s.App.IBCKeeper.ChannelKeeper.SetChannel(s.Ctx, portId, channelId, channel) } +// Helper function to check if an ICA was submitted by seeing if the sequence number incremented +func (s *AppTestHelper) CheckICATxSubmitted(portId, channelId string, icaFunction func() error) { + // Get the sequence before the tested funciton is run + startSequence := s.MustGetNextSequenceNumber(portId, channelId) + + // Run the test function and confirm there's no error + err := icaFunction() + s.Require().NoError(err, "no error expected executing tested function") + + // Check that the sequence number incremented + endSequence := s.MustGetNextSequenceNumber(portId, channelId) + s.Require().Equal(startSequence+1, endSequence, "sequence number should have incremented from tested function") +} + +// Helper function to check if an ICA was NOT submitted by seeing if the sequence number did not increment +func (s *AppTestHelper) CheckICATxNotSubmitted(portId, channelId string, icaFunction func() error) { + // Get the sequence before the tested funciton is run + startSequence := s.MustGetNextSequenceNumber(portId, channelId) + + // Run the test function and confirm there's no error + err := icaFunction() + s.Require().NoError(err, "no error expected executing tested function") + + // Check that the sequence number did not change + endSequence := s.MustGetNextSequenceNumber(portId, channelId) + s.Require().Equal(startSequence, endSequence, "sequence number should NOT have incremented from tested function") +} + // Constructs an ICA Packet Acknowledgement compatible with ibc-go v5+ func ICAPacketAcknowledgement(t *testing.T, msgType string, msgResponses []proto.Message) channeltypes.Acknowledgement { txMsgData := &sdk.TxMsgData{ @@ -409,6 +442,13 @@ func (s *AppTestHelper) GetIBCDenomTrace(denom string) transfertypes.DenomTrace return transfertypes.ParseDenomTrace(prefixedDenom) } +// Helper function to get the next sequence number for testing when an ICA was submitted +func (s *AppTestHelper) MustGetNextSequenceNumber(portId, channelId string) uint64 { + sequence, found := s.App.StakeibcKeeper.IBCKeeper.ChannelKeeper.GetNextSequenceSend(s.Ctx, portId, channelId) + s.Require().True(found, "sequence number for port %s and channel %s was not found", portId, channelId) + return sequence +} + // Creates and stores an IBC denom from a base denom on transfer channel-0 // This is only required for tests that use the transfer keeper and require that the IBC // denom is present in the store @@ -437,6 +477,46 @@ func (s *AppTestHelper) MockClientLatestHeight(height uint64) { s.App.IBCKeeper.ClientKeeper.SetClientState(s.Ctx, FirstClientId, &clientState) } +// Helper function to mock out a client and connection to test +// mapping from connection ID back to chain ID +// This also mocks out the consensus state to enable testing registering interchain accounts +func (s *AppTestHelper) MockClientAndConnection(chainId, clientId, connectionId string) { + clientHeight := clienttypes.Height{ + RevisionHeight: uint64(s.Ctx.BlockHeight()), + } + clientState := tendermint.ClientState{ + ChainId: chainId, + LatestHeight: clientHeight, + TrustingPeriod: time.Minute * 10, + } + s.App.IBCKeeper.ClientKeeper.SetClientState(s.Ctx, clientId, &clientState) + + consensusState := tendermint.ConsensusState{ + Timestamp: s.Ctx.BlockTime(), + } + s.App.IBCKeeper.ClientKeeper.SetClientConsensusState(s.Ctx, clientId, clientHeight, &consensusState) + + connection := connectiontypes.ConnectionEnd{ + ClientId: clientId, + Versions: []*connectiontypes.Version{connectiontypes.DefaultIBCVersion}, + } + s.App.IBCKeeper.ConnectionKeeper.SetConnection(s.Ctx, connectionId, connection) +} + +// Helper function to mock out an ICA address +func (s *AppTestHelper) MockICAChannel(connectionId, channelId, owner, address string) { + // Create an open channel with the ICA port + portId, _ := icatypes.NewControllerPortID(owner) + channel := channeltypes.Channel{ + State: channeltypes.OPEN, + } + s.App.IBCKeeper.ChannelKeeper.SetChannel(s.Ctx, portId, channelId, channel) + + // Then set the address and make the channel active + s.App.ICAControllerKeeper.SetInterchainAccountAddress(s.Ctx, connectionId, portId, address) + s.App.ICAControllerKeeper.SetActiveChannelID(s.Ctx, connectionId, portId, channelId) +} + func (s *AppTestHelper) ConfirmUpgradeSucceededs(upgradeName string, upgradeHeight int64) { s.Ctx = s.Ctx.WithBlockHeight(upgradeHeight - 1) plan := upgradetypes.Plan{Name: upgradeName, Height: upgradeHeight} @@ -452,6 +532,23 @@ func (s *AppTestHelper) ConfirmUpgradeSucceededs(upgradeName string, upgradeHeig }) } +// Returns the bank store key prefix for an address and denom +// Useful for testing balance ICQs +func (s *AppTestHelper) GetBankStoreKeyPrefix(address, denom string) []byte { + _, addressBz, err := bech32.DecodeAndConvert(address) + s.Require().NoError(err, "no error expected when bech decoding address") + return append(banktypes.CreateAccountBalancesPrefix(addressBz), []byte(denom)...) +} + +// Extracts the address and denom from a bank store prefix +// Useful for testing balance ICQs as it can confirm that the serialized query request +// data has the proper address and denom +func (s *AppTestHelper) ExtractAddressAndDenomFromBankPrefix(data []byte) (address, denom string) { + addressBz, denom, err := banktypes.AddressAndDenomFromBalancesStore(data[1:]) // Remove BalancePrefix byte + s.Require().NoError(err, "no error expected when getting address and denom from balance store") + return addressBz.String(), denom +} + // Generates a valid and invalid test address (used for non-keeper tests) func GenerateTestAddrs() (string, string) { pk1 := ed25519.GenPrivKey().PubKey() diff --git a/app/proposals_whitelisting.go b/app/proposals_whitelisting.go index 94bcac3109..3b5247755f 100644 --- a/app/proposals_whitelisting.go +++ b/app/proposals_whitelisting.go @@ -32,6 +32,9 @@ var WhiteListModule = map[string]struct{}{ "/cosmos.upgrade.v1beta1.MsgCancelUpgrade": {}, "/stride.icaoracle.MsgToggleOracle": {}, "/stride.icaoracle.MsgRemoveOracle": {}, + "/stride.stakeibc.MsgCreateTradeRoute": {}, + "/stride.stakeibc.MsgUpdateTradeRoute": {}, + "/stride.stakeibc.MsgDeleteTradeRoute": {}, } func IsModuleWhiteList(typeUrl string) bool { diff --git a/dockernet/README.md b/dockernet/README.md index 37c9c5534f..662e30c29a 100644 --- a/dockernet/README.md +++ b/dockernet/README.md @@ -42,12 +42,10 @@ make build-docker build={z} volumes: - ./dockernet/state/{new-host-zone}2:/home/{new-host-zone}/.{new-host-zone}d - ... - - {new-host-zone}5: + {new-host-zone}3: image: stridezone:{new-host-zone} volumes: - - ./dockernet/state/{new-host-zone}5:/home/{new-host-zone}/.{new-host-zone}d + - ./dockernet/state/{new-host-zone}3:/home/{new-host-zone}/.{new-host-zone}d ... relayer-{chain}: image: stridezone:relayer diff --git a/dockernet/config.sh b/dockernet/config.sh index 286eb15e2a..a6afe699f6 100755 --- a/dockernet/config.sh +++ b/dockernet/config.sh @@ -37,6 +37,7 @@ if [[ "${ALL_HOST_CHAINS:-false}" == "true" ]]; then elif [[ "${#HOST_CHAINS[@]}" == "0" ]]; then HOST_CHAINS=(GAIA) fi +REWARD_CONVERTER_HOST_ZONE=${HOST_CHAINS[0]} # DENOMS STRD_DENOM="ustrd" @@ -108,7 +109,7 @@ IBC_STARS_DENOM=$IBC_STARS_CHANNEL_3_DENOM # CHAIN PARAMS BLOCK_TIME='1s' -STRIDE_HOUR_EPOCH_DURATION="90s" +STRIDE_HOUR_EPOCH_DURATION="60s" STRIDE_DAY_EPOCH_DURATION="140s" STRIDE_EPOCH_EPOCH_DURATION="35s" STRIDE_MINT_EPOCH_DURATION="20s" @@ -336,15 +337,24 @@ STRIDE_RELAYER_MNEMONICS=( "$RELAYER_GAIA_ICS_MNEMONIC" "$RELAYER_DYDX_MNEMONIC" ) -# Mnemonics for connections between two non-stride chains -RELAYER_NOBLE_DYDX_MNEMONIC="sentence fruit crumble sail bar knife exact flame apart prosper hint myth clean among tiny burden depart purity select envelope identify cross physical emerge" -RELAYER_DYDX_NOBLE_MNEMONIC="aerobic breeze claw climb bounce morning tank victory eight funny employ bracket hire reduce fine flee lava domain warfare loop theme fly tattoo must" +# Mnemonics for connections between accessory chains +RELAYER_STRIDE_OSMO_MNEMONIC="father october lonely ticket leave regret pudding buffalo return asthma plastic piano beef orient ill clip right phone ready pottery helmet hip solid galaxy" +RELAYER_OSMO_STRIDE_MNEMONIC="narrow assist come feel canyon anxiety three reason satoshi inspire region little attend impulse what student dog armor economy faculty dutch distance upon calm" +RELAYER_STRIDE_NOBLE_MNEMONIC="absent confirm lumber hobby glide alter remain yard mixed fiscal series kitchen effort protect pistol hire bless police year struggle near hour wisdom jewel" +RELAYER_NOBLE_STRIDE_MNEMONIC="jar point equal question fatigue frog disorder wasp labor obtain head print orbit entire frown high sadness dash retire idea coffee rubber rough until" RELAYER_NOBLE_OSMO_MNEMONIC="actual field visual wage orbit add human unit happy rich evil chair entire person february cactus deputy impact gasp elbow sunset brand possible fly" RELAYER_OSMO_NOBLE_MNEMONIC="obey clinic miss grunt inflict laugh sell moral kitchen tumble gold song flavor rather horn exhaust state amazing poverty differ approve spike village device" +# Mnemonics between host zone and accessory chains when running with GAIA as the host +RELAYER_GAIA_NOBLE_MNEMONIC="aerobic breeze claw climb bounce morning tank victory eight funny employ bracket hire reduce fine flee lava domain warfare loop theme fly tattoo must" +RELAYER_NOBLE_GAIA_MNEMONIC="sentence fruit crumble sail bar knife exact flame apart prosper hint myth clean among tiny burden depart purity select envelope identify cross physical emerge" +RELAYER_GAIA_OSMO_MNEMONIC="small fire step promote fox reward book seek arctic session illegal loyal because brass spoil minute wonder jazz shoe price muffin churn evil monitor" +RELAYER_OSMO_GAIA_MNEMONIC="risk wool reason sweet current strategy female miracle squeeze that wire develop ocean rapid domain lift blame monkey sick round museum item maze trumpet" +# Mnemonics between host zone and accessory chains when running with DYDX as the host +RELAYER_NOBLE_DYDX_MNEMONIC="sentence fruit crumble sail bar knife exact flame apart prosper hint myth clean among tiny burden depart purity select envelope identify cross physical emerge" +RELAYER_DYDX_NOBLE_MNEMONIC="aerobic breeze claw climb bounce morning tank victory eight funny employ bracket hire reduce fine flee lava domain warfare loop theme fly tattoo must" RELAYER_DYDX_OSMO_MNEMONIC="small fire step promote fox reward book seek arctic session illegal loyal because brass spoil minute wonder jazz shoe price muffin churn evil monitor" RELAYER_OSMO_DYDX_MNEMONIC="risk wool reason sweet current strategy female miracle squeeze that wire develop ocean rapid domain lift blame monkey sick round museum item maze trumpet" - STRIDE_ADDRESS() { # After an upgrade, the keys query can sometimes print migration info, # so we need to filter by valid addresses using the prefix @@ -512,6 +522,41 @@ GET_COUNTERPARTY_TRANSFER_CHANNEL_ID() { $main_cmd q ibc channel end transfer $channel_id | grep -A 2 counterparty | grep channel_id | awk '{print $2}' } +GET_LATEST_PROPOSAL_ID() { + chain="$1" + + main_cmd=$(GET_VAR_VALUE ${chain}_MAIN_CMD) + $main_cmd q gov proposals | grep ' id:' | tail -1 | awk '{printf $2}' | tr -d '"' +} + +WATCH_PROPOSAL_STATUS() { + chain="$1" + proposal_id="$2" + + main_cmd=$(GET_VAR_VALUE ${chain}_MAIN_CMD) + + # Continually polls the proposal status until it passes or fails + while true; do + status=$($main_cmd query gov proposal $proposal_id | grep "status" | awk '{printf $2}') + if [[ "$status" == "PROPOSAL_STATUS_VOTING_PERIOD" ]]; then + echo " Proposal still in progress..." + sleep 5 + elif [[ "$status" == "PROPOSAL_STATUS_PASSED" ]]; then + echo " Proposal passed!" + exit 0 + elif [[ "$status" == "PROPOSAL_STATUS_REJECTED" ]]; then + echo " Proposal rejected!" + exit 1 + elif [[ "$status" == "PROPOSAL_STATUS_FAILED" ]]; then + echo " Proposal failed!" + exit 1 + else + echo "ERROR: Unknown proposal status: $status" + exit 1 + fi + done +} + TRIM_TX() { grep -E "code:|txhash:" | sed 's/^/ /' } diff --git a/dockernet/config/ica_host.json b/dockernet/config/ica_host.json index 3a8a8abf0d..d7bbd9d4d9 100644 --- a/dockernet/config/ica_host.json +++ b/dockernet/config/ica_host.json @@ -20,7 +20,8 @@ "/cosmos.distribution.v1beta1.MsgFundCommunityPool", "/ibc.applications.transfer.v1.MsgTransfer", "/cosmwasm.wasm.v1.MsgExecuteContract", - "/cosmwasm.wasm.v1.MsgInstantiateContract" + "/cosmwasm.wasm.v1.MsgInstantiateContract", + "/osmosis.gamm.v1beta1.MsgSwapExactAmountIn" ] } } diff --git a/dockernet/config/relayer_config_dydx_noble.yaml b/dockernet/config/relayer_config_reward_converter.yaml similarity index 52% rename from dockernet/config/relayer_config_dydx_noble.yaml rename to dockernet/config/relayer_config_reward_converter.yaml index a8d9fc5ac9..50de6afd85 100644 --- a/dockernet/config/relayer_config_dydx_noble.yaml +++ b/dockernet/config/relayer_config_reward_converter.yaml @@ -4,6 +4,36 @@ global: memo: "" light-cache-size: 20 chains: + stride: + type: cosmos + value: + key: stride + chain-id: STRIDE + rpc-addr: http://stride1:26657 + account-prefix: stride + keyring-backend: test + gas-adjustment: 1.3 + gas-prices: 0.02ustrd + coin-type: 118 + debug: false + timeout: 20s + output-format: json + sign-mode: direct + gaia: + type: cosmos + value: + key: gaia + chain-id: GAIA + rpc-addr: http://gaia1:26657 + account-prefix: cosmos + keyring-backend: test + gas-adjustment: 1.3 + gas-prices: 0.02uatom + coin-type: 118 + debug: false + timeout: 20s + output-format: json + sign-mode: direct dydx: type: cosmos value: @@ -50,9 +80,18 @@ chains: output-format: json sign-mode: direct paths: - dydx-noble: + # Paths for accessory chains + stride-osmo: src: - chain-id: DYDX + chain-id: STRIDE + dst: + chain-id: OSMO + src-channel-filter: + rule: "" + channel-list: [] + stride-noble: + src: + chain-id: STRIDE dst: chain-id: NOBLE src-channel-filter: @@ -66,11 +105,37 @@ paths: src-channel-filter: rule: "" channel-list: [] - osmo-dydx: + # Paths for host chain (if running GAIA) + gaia-noble: + src: + chain-id: GAIA + dst: + chain-id: NOBLE + src-channel-filter: + rule: "" + channel-list: [] + osmo-gaia: src: chain-id: OSMO dst: + chain-id: GAIA + src-channel-filter: + rule: "" + channel-list: [] + # Paths for host chain (if running DYDX) + dydx-noble: + src: chain-id: DYDX + dst: + chain-id: NOBLE src-channel-filter: rule: "" channel-list: [] + osmo-dydx: + src: + chain-id: OSMO + dst: + chain-id: DYDX + src-channel-filter: + rule: "" + channel-list: [] \ No newline at end of file diff --git a/dockernet/docker-compose.yml b/dockernet/docker-compose.yml index d9afb44b23..85248776f8 100644 --- a/dockernet/docker-compose.yml +++ b/dockernet/docker-compose.yml @@ -1,5 +1,6 @@ version: "3" services: + # Stride nodes stride1: image: stridezone:stride volumes: @@ -19,6 +20,7 @@ services: volumes: - ./state/stride3:/home/stride/.stride + # Host zones gaia1: image: stridezone:gaia volumes: @@ -38,16 +40,6 @@ services: volumes: - ./state/gaia3:/home/gaia/.gaia - gaia4: - image: stridezone:gaia - volumes: - - ./state/gaia4:/home/gaia/.gaia - - gaia5: - image: stridezone:gaia - volumes: - - ./state/gaia5:/home/gaia/.gaia - juno1: image: stridezone:juno volumes: @@ -67,16 +59,6 @@ services: volumes: - ./state/juno3:/home/juno/.juno - juno4: - image: stridezone:juno - volumes: - - ./state/juno4:/home/juno/.juno - - juno5: - image: stridezone:juno - volumes: - - ./state/juno5:/home/juno/.juno - osmo1: image: stridezone:osmo volumes: @@ -96,16 +78,6 @@ services: volumes: - ./state/osmo3:/home/osmosis/.osmosisd - osmo4: - image: stridezone:osmo - volumes: - - ./state/osmo4:/home/osmosis/.osmosisd - - osmo5: - image: stridezone:osmo - volumes: - - ./state/osmo5:/home/osmosis/.osmosisd - stars1: image: stridezone:stars volumes: @@ -125,16 +97,6 @@ services: volumes: - ./state/stars3:/home/stars/.starsd - stars4: - image: stridezone:stars - volumes: - - ./state/stars4:/home/stars/.starsd - - stars5: - image: stridezone:stars - volumes: - - ./state/stars5:/home/stars/.starsd - # For the host chain, we must override the command to prevent an old binary from # being run when testing upgrades host1: @@ -159,18 +121,6 @@ services: volumes: - ./state/host3:/home/stride/.stride - host4: - image: stridezone:stride - command: strided start - volumes: - - ./state/host4:/home/stride/.stride - - host5: - image: stridezone:stride - command: strided start - volumes: - - ./state/host5:/home/stride/.stride - evmos1: image: stridezone:evmos volumes: @@ -190,16 +140,6 @@ services: volumes: - ./state/evmos3:/home/evmos/.evmosd - evmos4: - image: stridezone:evmos - volumes: - - ./state/evmos4:/home/evmos/.evmosd - - evmos5: - image: stridezone:evmos - volumes: - - ./state/evmos5:/home/evmos/.evmosd - dydx1: image: stridezone:dydx volumes: @@ -219,16 +159,6 @@ services: volumes: - ./state/dydx3:/home/dydx/.dydxprotocol - dydx4: - image: stridezone:dydx - volumes: - - ./state/dydx4:/home/dydx/.dydxprotocol - - dydx5: - image: stridezone:dydx - volumes: - - ./state/dydx5:/home/dydx/.dydxprotocol - noble1: image: stridezone:noble volumes: @@ -248,16 +178,6 @@ services: volumes: - ./state/noble3:/home/noble/.noble - noble4: - image: stridezone:noble - volumes: - - ./state/noble4:/home/noble/.noble - - noble5: - image: stridezone:noble - volumes: - - ./state/noble5:/home/noble/.noble - # Fill in new host zone being tested here hermes: @@ -267,6 +187,7 @@ services: - ./state/hermes/config.toml:/home/hermes/.hermes/config.toml restart: always + # Host zone relayers relayer-gaia: image: stridezone:relayer volumes: @@ -323,6 +244,7 @@ services: restart: always command: [ "bash", "start.sh", "stride-dydx" ] + # Relayers for rate limiter tests relayer-juno-osmo: image: stridezone:relayer volumes: @@ -330,12 +252,13 @@ services: restart: always command: [ "bash", "start.sh", "juno-osmo" ] - relayer-dydx-noble: + # Relayers for reward converter accessory chains + relayer-stride-noble: image: stridezone:relayer volumes: - - ./state/relayer-dydx-noble:/home/relayer/.relayer + - ./state/relayer-stride-noble:/home/relayer/.relayer restart: always - command: [ "bash", "start.sh", "dydx-noble" ] + command: [ "bash", "start.sh", "stride-noble" ] relayer-noble-osmo: image: stridezone:relayer @@ -344,9 +267,39 @@ services: restart: always command: [ "bash", "start.sh", "noble-osmo" ] + relayer-stride-osmo: + image: stridezone:relayer + volumes: + - ./state/relayer-stride-osmo:/home/relayer/.relayer + restart: always + command: [ "bash", "start.sh", "stride-osmo" ] + + # Relayers for reward converter with dydx + relayer-dydx-noble: + image: stridezone:relayer + volumes: + - ./state/relayer-dydx-noble:/home/relayer/.relayer + restart: always + command: [ "bash", "start.sh", "dydx-noble" ] + relayer-osmo-dydx: image: stridezone:relayer volumes: - ./state/relayer-osmo-dydx:/home/relayer/.relayer restart: always command: [ "bash", "start.sh", "osmo-dydx" ] + + # Relayers for reward converter with gaia + relayer-gaia-noble: + image: stridezone:relayer + volumes: + - ./state/relayer-gaia-noble:/home/relayer/.relayer + restart: always + command: [ "bash", "start.sh", "gaia-noble" ] + + relayer-osmo-gaia: + image: stridezone:relayer + volumes: + - ./state/relayer-osmo-gaia:/home/relayer/.relayer + restart: always + command: [ "bash", "start.sh", "osmo-gaia" ] \ No newline at end of file diff --git a/dockernet/dockerfiles/Dockerfile.osmo b/dockernet/dockerfiles/Dockerfile.osmo index 957f257637..e8e0278b3b 100644 --- a/dockernet/dockerfiles/Dockerfile.osmo +++ b/dockernet/dockerfiles/Dockerfile.osmo @@ -4,7 +4,7 @@ WORKDIR /opt/ RUN set -eux; apk add --no-cache ca-certificates build-base; apk add git linux-headers -ENV COMMIT_HASH=v16.1.1-no-fees +ENV COMMIT_HASH=v20.5.0-no-fees RUN git clone https://github.com/Stride-Labs/osmosis.git \ && cd osmosis \ diff --git a/dockernet/scripts/community-pool-staking/README.md b/dockernet/scripts/community-pool-staking/README.md index bc840bb33c..5585e6b6df 100644 --- a/dockernet/scripts/community-pool-staking/README.md +++ b/dockernet/scripts/community-pool-staking/README.md @@ -1,7 +1,7 @@ ## Community Pool Staking Integration Tests ### Liquid Staking and Redemptions * To test only liquid staking and redemptions from the community pool (without reinvestment), the setup is much simpler -* Set `HOST_CHAINS` to `(DYDX)` in `config.sh` +* Set `HOST_CHAINS` to either `(DYDX)` or `(GAIA)` in `config.sh` * Start dockernet ```bash make start-docker @@ -27,7 +27,7 @@ bash dockernet/scripts/community-pool-staking/stake_proposal.sh ### Reinvestment * To test reinvestment, you must start up noble and osmosis as well - * Set `HOST_CHAINS` to `(DYDX)` in `config.sh` + * Set `HOST_CHAINS` to either `(DYDX)` or `(GAIA)` in `config.sh` * Set `ACCESSORY_CHAINS` to `(NOBLE OSMO)` in `config.sh * Start the network ```bash @@ -41,7 +41,11 @@ bash dockernet/scripts/community-pool-staking/start_relayers.sh ```bash bash dockernet/scripts/community-pool-staking/create_pool.sh ``` -* Finally, test the reinvestment flow by sending USDC to the withdrawal address +* Register the trade route to configure the conversion of reward tokens to host tokens +```bash +bash dockernet/scripts/community-pool-staking/add_trade_route.sh +``` +* Finally, test the reinvestment flow by sending USDC to the withdrawal address. View `logs/balances.log` to watch the funds traverse the different accounts ```bash bash dockernet/scripts/community-pool-staking/reinvest.sh -``` \ No newline at end of file +``` diff --git a/dockernet/scripts/community-pool-staking/add_trade_route.sh b/dockernet/scripts/community-pool-staking/add_trade_route.sh new file mode 100644 index 0000000000..173b7a9647 --- /dev/null +++ b/dockernet/scripts/community-pool-staking/add_trade_route.sh @@ -0,0 +1,120 @@ +#!/bin/bash +set -eu +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +source ${SCRIPT_DIR}/../../config.sh + +HOST_CHAIN=$REWARD_CONVERTER_HOST_ZONE +HOST_VAL_ADDRESS=$(${HOST_CHAIN}_ADDRESS) +HOST_CHAIN_ID=$(GET_VAR_VALUE ${HOST_CHAIN}_CHAIN_ID) +HOST_DENOM=$(GET_VAR_VALUE ${HOST_CHAIN}_DENOM) + +GAS="--gas-prices 0.1ustrd --gas auto --gas-adjustment 1.3" + +echo "Determining relevant connections and channels..." +stride_to_noble_client=$(GET_CLIENT_ID_FROM_CHAIN_ID STRIDE NOBLE) +stride_to_noble_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID STRIDE $stride_to_noble_client) + +stride_to_osmo_client=$(GET_CLIENT_ID_FROM_CHAIN_ID STRIDE OSMO) +stride_to_osmo_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID STRIDE $stride_to_osmo_client) + +host_to_noble_client=$(GET_CLIENT_ID_FROM_CHAIN_ID $HOST_CHAIN NOBLE) +host_to_noble_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID $HOST_CHAIN $host_to_noble_client) +host_to_noble_channel=$(GET_TRANSFER_CHANNEL_ID_FROM_CONNECTION_ID $HOST_CHAIN $host_to_noble_connection) + +noble_to_host_client=$(GET_CLIENT_ID_FROM_CHAIN_ID NOBLE $HOST_CHAIN) +noble_to_host_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID NOBLE $noble_to_host_client) +noble_to_host_channel=$(GET_TRANSFER_CHANNEL_ID_FROM_CONNECTION_ID NOBLE $noble_to_host_connection) + +noble_to_osmo_client=$(GET_CLIENT_ID_FROM_CHAIN_ID NOBLE OSMO) +noble_to_osmo_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID NOBLE $noble_to_osmo_client) +noble_to_osmo_channel=$(GET_TRANSFER_CHANNEL_ID_FROM_CONNECTION_ID NOBLE $noble_to_osmo_connection) + +osmo_to_host_client=$(GET_CLIENT_ID_FROM_CHAIN_ID OSMO $HOST_CHAIN) +osmo_to_host_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID OSMO $osmo_to_host_client) +osmo_to_host_channel=$(GET_TRANSFER_CHANNEL_ID_FROM_CONNECTION_ID OSMO $osmo_to_host_connection) + +osmo_to_noble_client=$(GET_CLIENT_ID_FROM_CHAIN_ID OSMO NOBLE) +osmo_to_noble_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID OSMO $osmo_to_noble_client) +osmo_to_noble_channel=$(GET_TRANSFER_CHANNEL_ID_FROM_CONNECTION_ID OSMO $osmo_to_noble_connection) + +echo -e "\nSTRIDE -> NOBLE:" +echo " Client: $stride_to_noble_client" +echo " Connection: $stride_to_noble_connection" + +echo -e "\nSTRIDE -> OSMO:" +echo " Client: $stride_to_osmo_client" +echo " Connection: $stride_to_osmo_connection" + +echo -e "\n$HOST_CHAIN -> NOBLE:" +echo " Client: $host_to_noble_client" +echo " Connection: $host_to_noble_connection" +echo " Transfer Channel: $host_to_noble_channel -> $noble_to_host_channel" + +echo -e "\nNOBLE -> OSMO:" +echo " Client: $noble_to_osmo_client" +echo " Connection: $noble_to_osmo_connection" +echo " Transfer Channel: $noble_to_osmo_channel" + +echo -e "\nOSMO -> $HOST_CHAIN:" +echo " Client: $osmo_to_host_client" +echo " Connection: $osmo_to_host_connection" +echo " Transfer Channel: $osmo_to_host_channel" + +echo -e "\nTransferring $USDC_DENOM to $HOST_DENOM to create ibc denom..." +$NOBLE_MAIN_CMD tx ibc-transfer transfer transfer $noble_to_host_channel $HOST_VAL_ADDRESS 10000${USDC_DENOM} \ + --from ${NOBLE_VAL_PREFIX}1 -y | TRIM_TX +sleep 15 + +echo -e "\nDetermining IBC Denoms..." +usdc_denom_on_host=$(GET_IBC_DENOM $HOST_CHAIN_ID $host_to_noble_channel $USDC_DENOM) +usdc_denom_on_osmo=$(GET_IBC_DENOM OSMO $osmo_to_noble_channel $USDC_DENOM) +host_denom_on_osmo=$(GET_IBC_DENOM OSMO $osmo_to_host_channel $HOST_DENOM) + +echo " ibc/$USDC_DENOM on Host: $usdc_denom_on_host" +echo " ibc/$USDC_DENOM on Osmosis: $usdc_denom_on_osmo" +echo " ibc/$HOST_DENOM on Osmosis: $host_denom_on_osmo" + +proposal_file=${STATE}/${STRIDE_NODE_PREFIX}1/trade_route.json +cat << EOF > $proposal_file +{ + "title": "Create a new trade route for host chain X", + "metadata": "Create a new trade route for host chain X", + "summary": "Create a new trade route for host chain X", + "messages": [ + { + "@type": "/stride.stakeibc.MsgCreateTradeRoute", + "authority": "stride10d07y265gmmuvt4z0w9aw880jnsr700jefnezl", + "host_chain_id": "$HOST_CHAIN_ID", + "stride_to_reward_connection_id": "$stride_to_noble_connection", + "stride_to_trade_connection_id": "$stride_to_osmo_connection", + "host_to_reward_transfer_channel_id": "$host_to_noble_channel", + "reward_to_trade_transfer_channel_id": "$noble_to_osmo_channel", + "trade_to_host_transfer_channel_id": "$osmo_to_host_channel", + "reward_denom_on_host": "$usdc_denom_on_host", + "reward_denom_on_reward": "$USDC_DENOM", + "reward_denom_on_trade": "$usdc_denom_on_osmo", + "host_denom_on_trade": "$host_denom_on_osmo", + "host_denom_on_host": "$HOST_DENOM", + "pool_id": 1, + "max_allowed_swap_loss_rate": "0.15" + } + ], + "deposit": "2000000000ustrd" +} +EOF + +echo -e "\nCreate trade route proposal file:" +cat $proposal_file + +echo -e "\n>>> Submitting proposal to register trade route..." +$STRIDE_MAIN_CMD tx gov submit-proposal $proposal_file --from val1 -y $GAS | TRIM_TX +sleep 5 + +echo -e "\n>>> Voting on proposal..." +proposal_id=$(GET_LATEST_PROPOSAL_ID STRIDE) +$STRIDE_MAIN_CMD tx gov vote $proposal_id yes --from val1 -y | TRIM_TX +$STRIDE_MAIN_CMD tx gov vote $proposal_id yes --from val2 -y | TRIM_TX +$STRIDE_MAIN_CMD tx gov vote $proposal_id yes --from val3 -y | TRIM_TX + +echo -e "\nProposal Status:" +WATCH_PROPOSAL_STATUS STRIDE $proposal_id \ No newline at end of file diff --git a/dockernet/scripts/community-pool-staking/claim.sh b/dockernet/scripts/community-pool-staking/claim.sh index 70b5043507..5b8f22aba1 100644 --- a/dockernet/scripts/community-pool-staking/claim.sh +++ b/dockernet/scripts/community-pool-staking/claim.sh @@ -2,20 +2,24 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source ${SCRIPT_DIR}/../../config.sh -community_pool_return_address=$(GET_ICA_ADDR DYDX community_pool_return) -community_pool_holding_address=$(GET_HOST_ZONE_FIELD DYDX community_pool_redeem_holding_address) +HOST_CHAIN=$REWARD_CONVERTER_HOST_ZONE +HOST_MAIN_CMD=$(GET_VAR_VALUE ${HOST_CHAIN}_MAIN_CMD) +HOST_DENOM=$(GET_VAR_VALUE ${HOST_CHAIN}_DENOM) + +community_pool_return_address=$(GET_ICA_ADDR $HOST_CHAIN community_pool_return) +community_pool_holding_address=$(GET_HOST_ZONE_FIELD $HOST_CHAIN community_pool_redeem_holding_address) # check balances before claiming redeemed stake echo ">>> Balances before claim..." -$DYDX_MAIN_CMD q bank balances $community_pool_return_address +$HOST_MAIN_CMD q bank balances $community_pool_return_address #claim stake echo -e "\n>>> Claiming redeemed tokens..." epoch=$($STRIDE_MAIN_CMD q records list-user-redemption-record | grep -B 3 -m 1 "receiver: $community_pool_return_address" | grep "epoch_number"| NUMBERS_ONLY) -$STRIDE_MAIN_CMD tx stakeibc claim-undelegated-tokens DYDX $epoch $community_pool_holding_address --from ${STRIDE_VAL_PREFIX}1 -y | TRIM_TX +$STRIDE_MAIN_CMD tx stakeibc claim-undelegated-tokens $HOST_CHAIN_ID $epoch $community_pool_holding_address --from ${STRIDE_VAL_PREFIX}1 -y | TRIM_TX sleep 5 # check balances after claiming redeemed stake echo -e "\n>>> Balances after claim..." -$DYDX_MAIN_CMD q bank balances $community_pool_return_address +$HOST_MAIN_CMD q bank balances $community_pool_return_address diff --git a/dockernet/scripts/community-pool-staking/create_pool.sh b/dockernet/scripts/community-pool-staking/create_pool.sh index 67e1398540..016874f1aa 100644 --- a/dockernet/scripts/community-pool-staking/create_pool.sh +++ b/dockernet/scripts/community-pool-staking/create_pool.sh @@ -3,41 +3,42 @@ set -eu SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source ${SCRIPT_DIR}/../../config.sh +HOST_CHAIN=$REWARD_CONVERTER_HOST_ZONE +HOST_MAIN_CMD=$(GET_VAR_VALUE ${HOST_CHAIN}_MAIN_CMD) +HOST_VAL_PREFIX=$(GET_VAR_VALUE ${HOST_CHAIN}_VAL_PREFIX) +HOST_DENOM=$(GET_VAR_VALUE ${HOST_CHAIN}_DENOM) + LIQUIDITY=1000000000000 GAS="--gas-prices 0.1uosmo --gas auto --gas-adjustment 1.3" echo "Determining relevant channels..." -dydx_to_osmo_client=$(GET_CLIENT_ID_FROM_CHAIN_ID DYDX OSMO) -dydx_to_osmo_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID DYDX $dydx_to_osmo_client) -dydx_to_osmo_channel=$(GET_TRANSFER_CHANNEL_ID_FROM_CONNECTION_ID DYDX $dydx_to_osmo_connection) -osmo_to_dydx_channel=$(GET_COUNTERPARTY_TRANSFER_CHANNEL_ID DYDX $dydx_to_osmo_channel) -dydx_denom_on_osmo=$(GET_IBC_DENOM OSMO $osmo_to_dydx_channel $DYDX_DENOM) +host_to_osmo_client=$(GET_CLIENT_ID_FROM_CHAIN_ID $HOST_CHAIN OSMO) +host_to_osmo_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID $HOST_CHAIN $host_to_osmo_client) +host_to_osmo_channel=$(GET_TRANSFER_CHANNEL_ID_FROM_CONNECTION_ID $HOST_CHAIN $host_to_osmo_connection) +osmo_to_host_channel=$(GET_COUNTERPARTY_TRANSFER_CHANNEL_ID $HOST_CHAIN $host_to_osmo_channel) -echo -e "\nDYDX -> OSMO:" -echo " Client: $dydx_to_osmo_client" -echo " Connection: $dydx_to_osmo_connection" -echo " Transfer Channel: $dydx_to_osmo_channel -> $osmo_to_dydx_channel" -echo " IBC Denom: $dydx_denom_on_osmo" +echo -e "\n$HOST_CHAIN -> OSMO:" +echo " Client: $host_to_osmo_client" +echo " Connection: $host_to_osmo_connection" +echo " Transfer Channel: $host_to_osmo_channel -> $osmo_to_host_channel" noble_to_osmo_client=$(GET_CLIENT_ID_FROM_CHAIN_ID NOBLE OSMO) noble_to_osmo_connection=$(GET_CONNECTION_ID_FROM_CLIENT_ID NOBLE $noble_to_osmo_client) noble_to_osmo_channel=$(GET_TRANSFER_CHANNEL_ID_FROM_CONNECTION_ID NOBLE $noble_to_osmo_connection) osmo_to_noble_channel=$(GET_COUNTERPARTY_TRANSFER_CHANNEL_ID NOBLE $noble_to_osmo_channel) -usdc_denom_on_osmo=$(GET_IBC_DENOM OSMO $osmo_to_noble_channel $USDC_DENOM) echo -e "\nNOBLE -> OSMO:" echo " Client: $noble_to_osmo_client" echo " Connection: $noble_to_osmo_connection" echo " Transfer Channel: $noble_to_osmo_channel -> $osmo_to_noble_channel" -echo " IBC Denom: $usdc_denom_on_osmo" -echo -e "\nSending dydx/usdc to osmosis for initial liquidity..." +echo -e "\nSending $HOST_DENOM and $USDC_DENOM to osmosis for initial liquidity..." -echo ">>> DYDX to Osmosis:" -$DYDX_MAIN_CMD tx ibc-transfer transfer transfer $dydx_to_osmo_channel $(OSMO_ADDRESS) ${LIQUIDITY}${DYDX_DENOM} \ - --from ${DYDX_VAL_PREFIX}1 -y | TRIM_TX +echo ">>> $HOST_DENOM to Osmosis:" +$HOST_MAIN_CMD tx ibc-transfer transfer transfer $host_to_osmo_channel $(OSMO_ADDRESS) ${LIQUIDITY}${HOST_DENOM} \ + --from ${HOST_VAL_PREFIX}1 -y | TRIM_TX -echo ">>> USDC to Osmosis:" +echo ">>> $USDC_DENOM to Osmosis:" $NOBLE_MAIN_CMD tx ibc-transfer transfer transfer $noble_to_osmo_channel $(OSMO_ADDRESS) ${LIQUIDITY}${USDC_DENOM} \ --from ${NOBLE_VAL_PREFIX}1 -y | TRIM_TX sleep 15 @@ -45,12 +46,19 @@ sleep 15 echo ">>> Balances:" $OSMO_MAIN_CMD q bank balances $(OSMO_ADDRESS) -echo -e "\nCreating dydx/usdc pool on osmosis..." +echo -e "\nDetermining IBC Denoms..." +host_denom_on_osmo=$(GET_IBC_DENOM OSMO $osmo_to_host_channel $HOST_DENOM) +usdc_denom_on_osmo=$(GET_IBC_DENOM OSMO $osmo_to_noble_channel $USDC_DENOM) + +echo " ibc/$HOST_DENOM on Osmosis: $host_denom_on_osmo" +echo " ibc/$USDC_DENOM on Osmosis: $usdc_denom_on_osmo" + +echo -e "\nCreating $HOST_DENOM/$USDC_DENOM pool on osmosis..." pool_file=${STATE}/${OSMO_NODE_PREFIX}1/pool.json cat << EOF > $pool_file { - "weights": "5${dydx_denom_on_osmo},5${usdc_denom_on_osmo}", - "initial-deposit": "1000000000000${dydx_denom_on_osmo},1000000000000${usdc_denom_on_osmo}", + "weights": "5${host_denom_on_osmo},5${usdc_denom_on_osmo}", + "initial-deposit": "1000000000000${host_denom_on_osmo},1000000000000${usdc_denom_on_osmo}", "swap-fee": "0.01", "exit-fee": "0.0", "future-governor": "" diff --git a/dockernet/scripts/community-pool-staking/redeem.sh b/dockernet/scripts/community-pool-staking/redeem.sh index 90cef0defe..4c7f4c5389 100644 --- a/dockernet/scripts/community-pool-staking/redeem.sh +++ b/dockernet/scripts/community-pool-staking/redeem.sh @@ -3,18 +3,23 @@ set -eu SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source ${SCRIPT_DIR}/../../config.sh +HOST_CHAIN=$REWARD_CONVERTER_HOST_ZONE +HOST_MAIN_CMD=$(GET_VAR_VALUE ${HOST_CHAIN}_MAIN_CMD) +HOST_VAL_PREFIX=$(GET_VAR_VALUE ${HOST_CHAIN}_VAL_PREFIX) +HOST_DENOM=$(GET_VAR_VALUE ${HOST_CHAIN}_DENOM) + # Transfer to stride echo ">>> Transfering native token to Stride..." -$DYDX_MAIN_CMD tx ibc-transfer transfer transfer channel-0 $(STRIDE_ADDRESS) 1000000${DYDX_DENOM} --from ${DYDX_VAL_PREFIX}1 -y | TRIM_TX +$HOST_MAIN_CMD tx ibc-transfer transfer transfer channel-0 $(STRIDE_ADDRESS) 1000000${HOST_DENOM} --from ${HOST_VAL_PREFIX}1 -y | TRIM_TX sleep 10 #Liquid stake echo -e "\n>>> Liquid staking..." -$STRIDE_MAIN_CMD tx stakeibc liquid-stake 1000000 ${DYDX_DENOM} --from ${STRIDE_VAL_PREFIX}1 -y | TRIM_TX +$STRIDE_MAIN_CMD tx stakeibc liquid-stake 1000000 ${HOST_DENOM} --from ${STRIDE_VAL_PREFIX}1 -y | TRIM_TX sleep 5 # Send stATOM to community pool return address echo -e "\n>>> Transfer stToken to deposit ICA..." -$STRIDE_MAIN_CMD tx ibc-transfer transfer transfer channel-0 $(GET_ICA_ADDR DYDX community_pool_deposit) \ - 900000${STDYDX_DENOM} --from ${STRIDE_VAL_PREFIX}1 -y | TRIM_TX +$STRIDE_MAIN_CMD tx ibc-transfer transfer transfer channel-0 $(GET_ICA_ADDR $HOST_CHAIN community_pool_deposit) \ + 900000st${HOST_DENOM} --from ${STRIDE_VAL_PREFIX}1 -y | TRIM_TX sleep 10 diff --git a/dockernet/scripts/community-pool-staking/reinvest.sh b/dockernet/scripts/community-pool-staking/reinvest.sh index 2ab30c70c0..cbf89cb64a 100644 --- a/dockernet/scripts/community-pool-staking/reinvest.sh +++ b/dockernet/scripts/community-pool-staking/reinvest.sh @@ -4,5 +4,5 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source ${SCRIPT_DIR}/../../config.sh echo ">>> Sending usdc tokens to withdrawal ICA to simulate rewards..." -$NOBLE_MAIN_CMD tx ibc-transfer transfer transfer channel-0 $(GET_ICA_ADDR DYDX withdrawal) 1000000${USDC_DENOM} \ +$NOBLE_MAIN_CMD tx ibc-transfer transfer transfer channel-0 $(GET_ICA_ADDR $REWARD_CONVERTER_HOST_ZONE withdrawal) 1000000${USDC_DENOM} \ --from ${NOBLE_VAL_PREFIX}1 -y | TRIM_TX \ No newline at end of file diff --git a/dockernet/scripts/community-pool-staking/setup_relayers.sh b/dockernet/scripts/community-pool-staking/setup_relayers.sh index a59e8dc19e..209bac6d34 100644 --- a/dockernet/scripts/community-pool-staking/setup_relayers.sh +++ b/dockernet/scripts/community-pool-staking/setup_relayers.sh @@ -3,14 +3,18 @@ set -eu SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source ${SCRIPT_DIR}/../../config.sh -for path in "dydx-noble" "noble-osmo" "osmo-dydx"; do +# Host chain can be dydx or gaia +HOST_CHAIN=$REWARD_CONVERTER_HOST_ZONE +host_chain=$(printf "$HOST_CHAIN" | awk '{ print tolower($0) }') + +for path in "$host_chain-noble" "noble-osmo" "osmo-$host_chain" "stride-osmo" "stride-noble"; do relayer_logs=${LOGS}/relayer-${path}.log relayer_config=$STATE/relayer-${path}/config relayer_exec="$DOCKER_COMPOSE run --rm relayer-$path" mkdir -p $relayer_config chmod -R 777 $STATE/relayer-${path} - cp ${DOCKERNET_HOME}/config/relayer_config_dydx_noble.yaml $relayer_config/config.yaml + cp ${DOCKERNET_HOME}/config/relayer_config_reward_converter.yaml $relayer_config/config.yaml IFS='-' read -r zone_1 zone_2 <<< "$path" @@ -51,4 +55,4 @@ for path in "dydx-noble" "noble-osmo" "osmo-dydx"; do $DOCKER_COMPOSE up -d relayer-${path} SAVE_DOCKER_LOGS relayer-${path} $relayer_logs -done +done \ No newline at end of file diff --git a/dockernet/scripts/community-pool-staking/stake.sh b/dockernet/scripts/community-pool-staking/stake.sh index b8676ebb9d..d2107709e9 100644 --- a/dockernet/scripts/community-pool-staking/stake.sh +++ b/dockernet/scripts/community-pool-staking/stake.sh @@ -3,5 +3,11 @@ set -eu SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source ${SCRIPT_DIR}/../../config.sh +HOST_CHAIN=$REWARD_CONVERTER_HOST_ZONE +HOST_MAIN_CMD=$(GET_VAR_VALUE ${HOST_CHAIN}_MAIN_CMD) +HOST_VAL_PREFIX=$(GET_VAR_VALUE ${HOST_CHAIN}_VAL_PREFIX) +HOST_VAL_ADDRESS=$(${HOST_CHAIN}_ADDRESS) +HOST_DENOM=$(GET_VAR_VALUE ${HOST_CHAIN}_DENOM) + echo ">>> Sending native tokens to deposit ICA to simulate community pool liquid stake..." -$DYDX_MAIN_CMD tx bank send $(DYDX_ADDRESS) $(GET_ICA_ADDR DYDX community_pool_deposit) 1000000${DYDX_DENOM} --from ${DYDX_VAL_PREFIX}1 -y | TRIM_TX \ No newline at end of file +$HOST_MAIN_CMD tx bank send $HOST_VAL_ADDRESS $(GET_ICA_ADDR $HOST_CHAIN community_pool_deposit) 1000000${HOST_DENOM} --from ${HOST_VAL_PREFIX}1 -y | TRIM_TX \ No newline at end of file diff --git a/dockernet/scripts/community-pool-staking/stake_proposal.sh b/dockernet/scripts/community-pool-staking/stake_proposal.sh index 8426a4b6a4..3554163a2b 100644 --- a/dockernet/scripts/community-pool-staking/stake_proposal.sh +++ b/dockernet/scripts/community-pool-staking/stake_proposal.sh @@ -4,7 +4,7 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) source ${SCRIPT_DIR}/../../config.sh deposit_ica_account=$(GET_ICA_ADDR DYDX community_pool_deposit) -proposal_file=${STATE}/${DYDX_NODE_PREFIX}1/pool.json +proposal_file=${STATE}/${DYDX_NODE_PREFIX}1/proposal.json cat << EOF > $proposal_file { "title": "Community Spend: Liquid stake", diff --git a/dockernet/src/create_logs.sh b/dockernet/src/create_logs.sh index 6464d55a7f..16aac5f568 100755 --- a/dockernet/src/create_logs.sh +++ b/dockernet/src/create_logs.sh @@ -11,6 +11,7 @@ TEMP_LOGS_DIR=$LOGS_DIR/temp STATE_LOG=state.log BALANCES_LOG=balances.log +CHANNELS_LOG=channels.log mkdir -p $TEMP_LOGS_DIR @@ -18,6 +19,7 @@ while true; do N_VALIDATORS_STRIDE=$($STRIDE_MAIN_CMD q tendermint-validator-set | grep -o address | wc -l | tr -dc '0-9') echo "STRIDE @ $($STRIDE_MAIN_CMD q tendermint-validator-set | head -n 1 | tr -dc '0-9') | $N_VALIDATORS_STRIDE VALS" >$TEMP_LOGS_DIR/$STATE_LOG echo "STRIDE @ $($STRIDE_MAIN_CMD q tendermint-validator-set | head -n 1 | tr -dc '0-9') | $N_VALIDATORS_STRIDE VALS" >$TEMP_LOGS_DIR/$BALANCES_LOG + echo "STRIDE @ $($STRIDE_MAIN_CMD q tendermint-validator-set | head -n 1 | tr -dc '0-9') | $N_VALIDATORS_STRIDE VALS" >$TEMP_LOGS_DIR/$CHANNELS_LOG for chain in ${HOST_CHAINS[@]}; do HOST_MAIN_CMD=$(GET_VAR_VALUE ${chain}_MAIN_CMD) @@ -37,10 +39,15 @@ while true; do $STRIDE_MAIN_CMD q records list-user-redemption-record >> $TEMP_LOGS_DIR/$STATE_LOG printf '\n%s\n' "LIST-LSM-TOKEN-DEPOSIT-RECORDS" >>$TEMP_LOGS_DIR/$STATE_LOG $STRIDE_MAIN_CMD q records lsm-deposits >> $TEMP_LOGS_DIR/$STATE_LOG + printf '\n%s\n' "LIST-TRADE-ROUTES" >>$TEMP_LOGS_DIR/$STATE_LOG + $STRIDE_MAIN_CMD q stakeibc list-trade-routes >> $TEMP_LOGS_DIR/$STATE_LOG printf '\n%s\n' "BALANCES STRIDE" >>$TEMP_LOGS_DIR/$BALANCES_LOG $STRIDE_MAIN_CMD q bank balances $(STRIDE_ADDRESS) >>$TEMP_LOGS_DIR/$BALANCES_LOG + printf '\n%s\n' "========================== STRIDE =============================" >> $TEMP_LOGS_DIR/$CHANNELS_LOG + $STRIDE_MAIN_CMD q ibc channel channels | grep -E "channel_id|port|state" >> $TEMP_LOGS_DIR/$CHANNELS_LOG || true + for chain in ${HOST_CHAINS[@]}; do HOST_CHAIN_ID=$(GET_VAR_VALUE ${chain}_CHAIN_ID) HOST_MAIN_CMD=$(GET_VAR_VALUE ${chain}_MAIN_CMD) @@ -84,6 +91,22 @@ while true; do $STRIDE_MAIN_CMD q bank balances $COMMUNITY_POOL_STAKE_ADDR >> $TEMP_LOGS_DIR/$BALANCES_LOG printf '\n%s\n' "COMMUNITY POOL REDEEM HOLDING ACCT BALANCE" >> $TEMP_LOGS_DIR/$BALANCES_LOG $STRIDE_MAIN_CMD q bank balances $COMMUNITY_POOL_REDEEM_ADDR >> $TEMP_LOGS_DIR/$BALANCES_LOG + + printf '\n%s\n' "========================== $chain =============================" >> $TEMP_LOGS_DIR/$CHANNELS_LOG + $HOST_MAIN_CMD q ibc channel channels | grep -E "channel_id|port|state" >> $TEMP_LOGS_DIR/$CHANNELS_LOG || true + done + + + TRADE_ICA_ADDR=$($STRIDE_MAIN_CMD q stakeibc list-trade-routes | grep trade_account -A 2 | grep address | awk '{print $2}') + if [[ "$TRADE_ICA_ADDR" == "$OSMO_ADDRESS_PREFIX"* ]]; then + printf '\n%s\n' "TRADE ACCT BALANCE" >> $TEMP_LOGS_DIR/$BALANCES_LOG + $OSMO_MAIN_CMD q bank balances $TRADE_ICA_ADDR >> $TEMP_LOGS_DIR/$BALANCES_LOG + fi + + for chain in ${ACCESSORY_CHAINS[@]:-}; do + ACCESSORY_MAIN_CMD=$(GET_VAR_VALUE ${chain}_MAIN_CMD) + printf '\n%s\n' "========================== $chain =============================" >> $TEMP_LOGS_DIR/$CHANNELS_LOG + $ACCESSORY_MAIN_CMD q ibc channel channels | grep -E "channel_id|port|state" >> $TEMP_LOGS_DIR/$CHANNELS_LOG || true done mv $TEMP_LOGS_DIR/*.log $LOGS_DIR diff --git a/dockernet/src/init_chain.sh b/dockernet/src/init_chain.sh index 66ed6f8c51..18300b3c0e 100644 --- a/dockernet/src/init_chain.sh +++ b/dockernet/src/init_chain.sh @@ -255,6 +255,7 @@ else add_relayer_account "$RELAYER_GAIA_ICS_ACCT" "$RELAYER_GAIA_ICS_MNEMONIC" fi if [ "$CHAIN" == "NOBLE" ]; then + add_relayer_account stride-noble "$RELAYER_NOBLE_STRIDE_MNEMONIC" add_relayer_account noble-dydx "$RELAYER_NOBLE_DYDX_MNEMONIC" add_relayer_account noble-osmo "$RELAYER_NOBLE_OSMO_MNEMONIC" fi diff --git a/dockernet/tests/run_all_tests.sh b/dockernet/tests/run_all_tests.sh index 9868c3a96a..1d030948bd 100755 --- a/dockernet/tests/run_all_tests.sh +++ b/dockernet/tests/run_all_tests.sh @@ -1,10 +1,11 @@ #!/bin/bash SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +source ${SCRIPT_DIR}/../config.sh # run test files BATS=${SCRIPT_DIR}/bats/bats-core/bin/bats INTEGRATION_TEST_FILE=${SCRIPT_DIR}/integration_tests.bats -CHAIN_NAME=GAIA TRANSFER_CHANNEL_NUMBER=0 $BATS $INTEGRATION_TEST_FILE -CHAIN_NAME=EVMOS TRANSFER_CHANNEL_NUMBER=1 $BATS $INTEGRATION_TEST_FILE -CHAIN_NAME=HOST TRANSFER_CHANNEL_NUMBER=2 $BATS $INTEGRATION_TEST_FILE +for i in ${!HOST_CHAINS[@]}; do + CHAIN_NAME=${HOST_CHAINS[i]} TRANSFER_CHANNEL_NUMBER=$i $BATS $INTEGRATION_TEST_FILE +done \ No newline at end of file diff --git a/proto/osmosis/gamm/v1beta1/osmosis.proto b/proto/osmosis/gamm/v1beta1/osmosis.proto new file mode 100644 index 0000000000..05c0a6049f --- /dev/null +++ b/proto/osmosis/gamm/v1beta1/osmosis.proto @@ -0,0 +1,88 @@ +syntax = "proto3"; +package osmosis.gamm.v1beta1; + +import "gogoproto/gogo.proto"; +import "amino/amino.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "google/protobuf/timestamp.proto"; + +option go_package = "github.com/Stride-Labs/stride/v16/x/stakeibc/types"; + +// MsgSwapExactAmountIn stores the tx Msg type to swap tokens in the trade ICA +message MsgSwapExactAmountIn { + option (amino.name) = "osmosis/gamm/swap-exact-amount-in"; + + string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ]; + repeated SwapAmountInRoute routes = 2 [ (gogoproto.nullable) = false ]; + cosmos.base.v1beta1.Coin token_in = 3 [ + (gogoproto.moretags) = "yaml:\"token_in\"", + (gogoproto.nullable) = false + ]; + string token_out_min_amount = 4 [ + + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.moretags) = "yaml:\"token_out_min_amount\"", + (gogoproto.nullable) = false + ]; +} + +message SwapAmountInRoute { + uint64 pool_id = 1 [ (gogoproto.moretags) = "yaml:\"pool_id\"" ]; + string token_out_denom = 2 + [ (gogoproto.moretags) = "yaml:\"token_out_denom\"" ]; +} + +// A TwapRecord stores the most recent price of a pair of denom's +message OsmosisTwapRecord { + uint64 pool_id = 1; + // Lexicographically smaller denom of the pair + string asset0_denom = 2; + // Lexicographically larger denom of the pair + string asset1_denom = 3; + // height this record corresponds to, for debugging purposes + int64 height = 4 [ + (gogoproto.moretags) = "yaml:\"record_height\"", + (gogoproto.jsontag) = "record_height" + ]; + // This field should only exist until we have a global registry in the state + // machine, mapping prior block heights within {TIME RANGE} to times. + google.protobuf.Timestamp time = 5 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"record_time\"" + ]; + + // We store the last spot prices in the struct, so that we can interpolate + // accumulator values for times between when accumulator records are stored. + string p0_last_spot_price = 6 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + string p1_last_spot_price = 7 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + + string p0_arithmetic_twap_accumulator = 8 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + string p1_arithmetic_twap_accumulator = 9 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + + string geometric_twap_accumulator = 10 [ + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false + ]; + + // This field contains the time in which the last spot price error occured. + // It is used to alert the caller if they are getting a potentially erroneous + // TWAP, due to an unforeseen underlying error. + google.protobuf.Timestamp last_error_time = 11 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true, + (gogoproto.moretags) = "yaml:\"last_error_time\"" + ]; +} diff --git a/proto/stride/stakeibc/callbacks.proto b/proto/stride/stakeibc/callbacks.proto index 62239b3ed8..ee94fcd2c7 100644 --- a/proto/stride/stakeibc/callbacks.proto +++ b/proto/stride/stakeibc/callbacks.proto @@ -94,3 +94,8 @@ message CommunityPoolBalanceQueryCallback { ICAAccountType ica_type = 1; string denom = 2; } + +message TradeRouteCallback { + string reward_denom = 1; + string host_denom = 2; +} diff --git a/proto/stride/stakeibc/ica_account.proto b/proto/stride/stakeibc/ica_account.proto index 857cdaee31..f4e77dcbff 100644 --- a/proto/stride/stakeibc/ica_account.proto +++ b/proto/stride/stakeibc/ica_account.proto @@ -10,4 +10,13 @@ enum ICAAccountType { REDEMPTION = 3; COMMUNITY_POOL_DEPOSIT = 4; COMMUNITY_POOL_RETURN = 5; + CONVERTER_UNWIND = 6; + CONVERTER_TRADE = 7; +} + +message ICAAccount { + string chain_id = 1; + ICAAccountType type = 2; + string connection_id = 3; + string address = 4; } diff --git a/proto/stride/stakeibc/query.proto b/proto/stride/stakeibc/query.proto index feb50668e3..ed942eebe4 100644 --- a/proto/stride/stakeibc/query.proto +++ b/proto/stride/stakeibc/query.proto @@ -9,6 +9,7 @@ import "stride/stakeibc/validator.proto"; import "stride/stakeibc/host_zone.proto"; import "stride/stakeibc/epoch_tracker.proto"; import "stride/stakeibc/address_unbonding.proto"; +import "stride/stakeibc/trade_route.proto"; option go_package = "github.com/Stride-Labs/stride/v16/x/stakeibc/types"; @@ -73,6 +74,12 @@ service Query { option (google.api.http).get = "/Stride-Labs/stride/stakeibc/unbondings/{address}"; } + + // Queries all trade routes + rpc AllTradeRoutes(QueryAllTradeRoutes) + returns (QueryAllTradeRoutesResponse) { + option (google.api.http).get = "/Stride-Labs/stride/stakeibc/trade_routes"; + } } // QueryInterchainAccountFromAddressRequest is the request type for the @@ -146,3 +153,9 @@ message QueryAddressUnbondingsResponse { repeated AddressUnbonding address_unbondings = 1 [ (gogoproto.nullable) = false ]; } + +message QueryAllTradeRoutes {}; + +message QueryAllTradeRoutesResponse { + repeated TradeRoute trade_routes = 1 [ (gogoproto.nullable) = false ]; +} diff --git a/proto/stride/stakeibc/trade_route.proto b/proto/stride/stakeibc/trade_route.proto new file mode 100644 index 0000000000..9bf90218bc --- /dev/null +++ b/proto/stride/stakeibc/trade_route.proto @@ -0,0 +1,90 @@ +syntax = "proto3"; +package stride.stakeibc; + +import "gogoproto/gogo.proto"; +import "stride/stakeibc/ica_account.proto"; +import "cosmos_proto/cosmos.proto"; + +option go_package = "github.com/Stride-Labs/stride/v16/x/stakeibc/types"; + +// Stores pool information needed to execute the swap along a trade route +message TradeConfig { + // Currently Osmosis is the only trade chain so this is an osmosis pool id + uint64 pool_id = 1; + + // Spot price in the pool to convert the reward denom to the host denom + // output_tokens = swap_price * input tokens + // This value may be slightly stale as it is updated by an ICQ + string swap_price = 2 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + // unix time in seconds that the price was last updated + uint64 price_update_timestamp = 3; + + // Threshold defining the percentage of tokens that could be lost in the trade + // This captures both the loss from slippage and from a stale price on stride + // 0.05 means the output from the trade can be no less than a 5% deviation + // from the current value + string max_allowed_swap_loss_rate = 4 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", + (gogoproto.nullable) = false + ]; + + // min and max set boundaries of reward denom on trade chain we will swap + // min also decides when reward token transfers are worth it (transfer fees) + string min_swap_amount = 5 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + string max_swap_amount = 6 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} + +// TradeRoute represents a round trip including info on transfer and how to do +// the swap. It makes the assumption that the reward token is always foreign to +// the host so therefore the first two hops are to unwind the ibc denom enroute +// to the trade chain and the last hop is the return so funds start/end in the +// withdrawl ICA on hostZone +// The structure is key'd on reward denom and host denom in their native forms +// (i.e. reward_denom_on_reward_zone and host_denom_on_host_zone) +message TradeRoute { + // ibc denom for the reward on the host zone + string reward_denom_on_host_zone = 1; + // should be the native denom for the reward chain + string reward_denom_on_reward_zone = 2; + // ibc denom of the reward on the trade chain, input to the swap + string reward_denom_on_trade_zone = 3; + // ibc of the host denom on the trade chain, output from the swap + string host_denom_on_trade_zone = 4; + // should be the same as the native host denom on the host chain + string host_denom_on_host_zone = 5; + + // ICAAccount on the host zone with the reward tokens + // This is the same as the host zone withdrawal ICA account + ICAAccount host_account = 6 [ (gogoproto.nullable) = false ]; + // ICAAccount on the reward zone that is acts as the intermediate + // receiver of the transfer from host zone to trade zone + ICAAccount reward_account = 7 [ (gogoproto.nullable) = false ]; + // ICAAccount responsible for executing the swap of reward + // tokens for host tokens + ICAAccount trade_account = 8 [ (gogoproto.nullable) = false ]; + + // Channel responsible for the transfer of reward tokens from the host + // zone to the reward zone. This is the channel ID on the host zone side + string host_to_reward_channel_id = 9; + // Channel responsible for the transfer of reward tokens from the reward + // zone to the trade zone. This is the channel ID on the reward zone side + string reward_to_trade_channel_id = 10; + // Channel responsible for the transfer of host tokens from the trade + // zone, back to the host zone. This is the channel ID on the trade zone side + string trade_to_host_channel_id = 11; + + // specifies the configuration needed to execute the swap + // such as pool_id, slippage, min trade amount, etc. + TradeConfig trade_config = 12 [ (gogoproto.nullable) = false ]; +} diff --git a/proto/stride/stakeibc/tx.proto b/proto/stride/stakeibc/tx.proto index 91c4b3d908..e3a0d795e4 100644 --- a/proto/stride/stakeibc/tx.proto +++ b/proto/stride/stakeibc/tx.proto @@ -1,13 +1,14 @@ syntax = "proto3"; package stride.stakeibc; -import "stride/stakeibc/ica_account.proto"; import "stride/stakeibc/validator.proto"; option go_package = "github.com/Stride-Labs/stride/v16/x/stakeibc/types"; import "gogoproto/gogo.proto"; import "cosmos_proto/cosmos.proto"; import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/msg/v1/msg.proto"; +import "amino/amino.proto"; // Msg defines the Msg service. service Msg { @@ -35,6 +36,12 @@ service Msg { rpc UpdateInnerRedemptionRateBounds(MsgUpdateInnerRedemptionRateBounds) returns (MsgUpdateInnerRedemptionRateBoundsResponse); rpc ResumeHostZone(MsgResumeHostZone) returns (MsgResumeHostZoneResponse); + rpc CreateTradeRoute(MsgCreateTradeRoute) + returns (MsgCreateTradeRouteResponse); + rpc DeleteTradeRoute(MsgDeleteTradeRoute) + returns (MsgDeleteTradeRouteResponse); + rpc UpdateTradeRoute(MsgUpdateTradeRoute) + returns (MsgUpdateTradeRouteResponse); } message MsgUpdateInnerRedemptionRateBounds { @@ -170,7 +177,8 @@ message MsgDeleteValidatorResponse {} message MsgRestoreInterchainAccount { string creator = 1; string chain_id = 2; - ICAAccountType account_type = 3; + string connection_id = 3; + string account_owner = 4; } message MsgRestoreInterchainAccountResponse {} @@ -180,6 +188,7 @@ message MsgUpdateValidatorSharesExchRate { string valoper = 3; } message MsgUpdateValidatorSharesExchRateResponse {} + message MsgUndelegateHost { string creator = 1; string amount = 2 [ @@ -200,4 +209,114 @@ message MsgResumeHostZone { string creator = 1; string chain_id = 2; } -message MsgResumeHostZoneResponse {} \ No newline at end of file +message MsgResumeHostZoneResponse {} + +// Creates a new trade route +message MsgCreateTradeRoute { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "stride/x/stakeibc/MsgCreateTradeRoute"; + + // authority is the address that controls the module (defaults to x/gov unless + // overwritten). + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // The chain ID of the host zone + string host_chain_id = 2; + + // Connection IDs between stride and the other zones + string stride_to_reward_connection_id = 3; + string stride_to_trade_connection_id = 4; + + // Transfer channels between the host, reward, and trade zones + string host_to_reward_transfer_channel_id = 5; + string reward_to_trade_transfer_channel_id = 6; + string trade_to_host_transfer_channel_id = 7; + + // ibc denom for the reward token on the host zone (e.g. ibc/usdc on dYdX) + string reward_denom_on_host = 8; + // native denom of reward token on the reward zone (e.g. usdc on Noble) + string reward_denom_on_reward = 9; + // ibc denom of the reward token on the trade zone (e.g. ibc/usdc on Osmosis) + string reward_denom_on_trade = 10; + // ibc denom of the host's token on the trade zone (e.g. ibc/dydx on Osmosis) + string host_denom_on_trade = 11; + // the host zone's native denom (e.g. dydx on dYdX) + string host_denom_on_host = 12; + + // The osmosis pool ID + uint64 pool_id = 13; + + // Threshold defining the percentage of tokens that could be lost in the trade + // This captures both the loss from slippage and from a stale price on stride + // "0.05" means the output from the trade can be no less than a 5% deviation + // from the current value + string max_allowed_swap_loss_rate = 14; + + // minimum amount of reward tokens to initate a swap + // if not provided, defaults to 0 + string min_swap_amount = 15 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // maximum amount of reward tokens in a single swap + // if not provided, defaults to 10e24 + string max_swap_amount = 16 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} +message MsgCreateTradeRouteResponse {} + +// Deletes a trade route +message MsgDeleteTradeRoute { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "stride/x/stakeibc/MsgDeleteTradeRoute"; + + // authority is the address that controls the module (defaults to x/gov unless + // overwritten). + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // The reward denom of the route in it's native form (e.g. usdc) + string reward_denom = 2; + // The host zone's denom in it's native form (e.g. dydx) + string host_denom = 3; +} +message MsgDeleteTradeRouteResponse {} + +// Updates the config of a trade route +message MsgUpdateTradeRoute { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "stride/x/stakeibc/MsgUpdateTradeRoute"; + + // authority is the address that controls the module (defaults to x/gov unless + // overwritten). + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + + // The reward denom of the route in it's native form (e.g. usdc) + string reward_denom = 2; + // The host zone's denom in it's native form (e.g. dydx) + string host_denom = 3; + + // The osmosis pool ID + uint64 pool_id = 4; + + // Threshold defining the percentage of tokens that could be lost in the trade + // This captures both the loss from slippage and from a stale price on stride + // "0.05" means the output from the trade can be no less than a 5% deviation + // from the current value + string max_allowed_swap_loss_rate = 5; + + // minimum amount of reward tokens to initate a swap + // if not provided, defaults to 0 + string min_swap_amount = 6 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; + // maximum amount of reward tokens in a single swap + // if not provided, defaults to 10e24 + string max_swap_amount = 7 [ + (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int", + (gogoproto.nullable) = false + ]; +} +message MsgUpdateTradeRouteResponse {} diff --git a/scripts/protocgen.sh b/scripts/protocgen.sh index b6f56f13a1..fdb200c311 100644 --- a/scripts/protocgen.sh +++ b/scripts/protocgen.sh @@ -20,6 +20,7 @@ cd proto generate_protos "./stride" generate_protos "./cosmos" generate_protos "./cosmwasm" +generate_protos "./osmosis" cd .. diff --git a/scripts/start_local_node.sh b/scripts/start_local_node.sh index 8ed852028b..fa9ae2a12a 100644 --- a/scripts/start_local_node.sh +++ b/scripts/start_local_node.sh @@ -38,6 +38,8 @@ sed -i -E "s|chain-id = \"\"|chain-id = \"${CHAIN_ID}\"|g" $client_toml sed -i -E "s|keyring-backend = \"os\"|keyring-backend = \"test\"|g" $client_toml sed -i -E "s|node = \".*\"|node = \"tcp://localhost:26657\"|g" $client_toml +sed -i -E "s|\"stake\"|\"${DENOM}\"|g" $genesis_json + jq '(.app_state.epochs.epochs[] | select(.identifier=="day") ).duration = $epochLen' --arg epochLen $STRIDE_DAY_EPOCH_DURATION $genesis_json > json.tmp && mv json.tmp $genesis_json jq '(.app_state.epochs.epochs[] | select(.identifier=="stride_epoch") ).duration = $epochLen' --arg epochLen $STRIDE_EPOCH_EPOCH_DURATION $genesis_json > json.tmp && mv json.tmp $genesis_json jq '.app_state.gov.params.max_deposit_period = $newVal' --arg newVal "$MAX_DEPOSIT_PERIOD" $genesis_json > json.tmp && mv json.tmp $genesis_json @@ -62,6 +64,17 @@ $STRIDED add-genesis-account $($STRIDED keys show val -a) 100000000000${DENOM} echo "$STRIDE_ADMIN_MNEMONIC" | $STRIDED keys add admin --recover --keyring-backend=test $STRIDED add-genesis-account $($STRIDED keys show admin -a) 100000000000${DENOM} -$STRIDED start +# Start the daemon in the background +$STRIDED start & +pid=$! +sleep 10 +# Add a governator +echo "Adding governator..." +pub_key=$($STRIDED tendermint show-validator) +$STRIDED tx staking create-validator --amount 1000000000${DENOM} --from val \ + --pubkey=$pub_key --commission-rate="0.10" --commission-max-rate="0.20" \ + --commission-max-change-rate="0.01" --min-self-delegation="1" -y +# Bring the daemon back to the foreground +wait $pid \ No newline at end of file diff --git a/x/README.md b/x/README.md index c1cd156b36..b3f96e9257 100644 --- a/x/README.md +++ b/x/README.md @@ -13,7 +13,7 @@ category: 62c5c5ff03a5bf069004def2 `interchainquery` - Issues queries between IBC chains, verifies state proof and executes callbacks. `epochs` - Makes on-chain timers which other modules can execute code during. `mint` - Controls token supply emissions, and what modules they are directed to. -`ratelimit` - IBC middleware wrapping the transfer module, thottles large IBC transfers. +`ratelimit` - IBC middleware wrapping the transfer module, throttles large IBC transfers. ### Attribution diff --git a/x/claim/README.md b/x/claim/README.md index 0a2f360919..7c30ce9a89 100644 --- a/x/claim/README.md +++ b/x/claim/README.md @@ -6,7 +6,7 @@ category: 6392913957c533007128548e # The Claim Module -Users are required participate in core network activities to claim their airdrop. An Airdrop recipient is given 20% of the airdrop amount which is not in vesting, and then they have to perform the following activities to get the rest: +Users are required to participate in core network activities to claim their airdrop. An Airdrop recipient is given 20% of the airdrop amount which is not in vesting, and then they have to perform the following activities to get the rest: * 20% vesting over 3 months by staking * 60% vesting over 3 months by liquid staking @@ -23,7 +23,7 @@ ActionLiquidStake Action = 0 ActionDelegateStake Action = 1 ``` -These actions are monitored by registring claim **hooks** to the stakeibc, and staking modules. +These actions are monitored by registering claim **hooks** to the stakeibc, and staking modules. This means that when you perform an action, the claims module will immediately unlock those coins if they are applicable. These actions can be performed in any order. @@ -45,7 +45,7 @@ So for example, `[true, true]` means that `ActionLiquidStake` and `ActionDelegat type ClaimRecord struct { // address of claim user Address string - // weight that represent the portion from total allocation + // weight that represents the portion from total allocation Weight sdk.Dec // true if action is completed // index of bool in array refers to action enum # @@ -122,7 +122,7 @@ message ClaimRecord { // address of claim user string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ]; - // weight that represent the portion from total allocations + // weight that represents the portion from total allocations double weight = 2; // true if action is completed diff --git a/x/epochs/README.md b/x/epochs/README.md index 3f8f774a4c..6c55b3f51e 100644 --- a/x/epochs/README.md +++ b/x/epochs/README.md @@ -36,7 +36,7 @@ When an epoch triggers the execution of code, that code is executed at the first Stride uses three epoch identifiers as found in `x/epochs/genesis.go` 1. `DAY_EPOCH`: this identifies an epoch that lasts 24 hours. -2. `STRIDE_EPOCH`: this identifies an epoch that lasts 5 minutes on local mode tesnet (although this may be changed) and longer on public testnet and mainnet, and is used in the `x/stakeibc/` module as a time interval in accordance with which the Stride app chain performs certain functions, such as autocompound stakig rewards. +2. `STRIDE_EPOCH`: this identifies an epoch that lasts 5 minutes on local mode testnet (although this may be changed) and longer on public testnet and mainnet, and is used in the `x/stakeibc/` module as a time interval in accordance with which the Stride app chain performs certain functions, such as autocompound staking rewards. ## State diff --git a/x/icaoracle/keeper/keeper.go b/x/icaoracle/keeper/keeper.go index 7cb8eaeceb..1a59943e99 100644 --- a/x/icaoracle/keeper/keeper.go +++ b/x/icaoracle/keeper/keeper.go @@ -59,7 +59,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -// GetAuthority returns the x/staking module's authority. +// GetAuthority returns the x/icaoracle module's authority. func (k Keeper) GetAuthority() string { return k.authority } diff --git a/x/interchainquery/types/keys.go b/x/interchainquery/types/keys.go index 21117a0623..7da8303e94 100644 --- a/x/interchainquery/types/keys.go +++ b/x/interchainquery/types/keys.go @@ -1,5 +1,7 @@ package types +import fmt "fmt" + const ( // ModuleName defines the module name ModuleName = "interchainquery" @@ -31,6 +33,14 @@ const ( STAKING_STORE_QUERY_WITH_PROOF = "store/staking/key" // The bank store is key'd by the account address BANK_STORE_QUERY_WITH_PROOF = "store/bank/key" + // The Osmosis twap store - key'd by the pool ID and denom's + TWAP_STORE_QUERY_WITH_PROOF = "store/twap/key" +) + +var ( + // Osmosis TWAP query info + OsmosisKeySeparator = "|" + OsmosisMostRecentTWAPsPrefix = "recent_twap" + OsmosisKeySeparator ) var ( @@ -42,3 +52,13 @@ var ( func KeyPrefix(p string) []byte { return []byte(p) } + +func FormatOsmosisMostRecentTWAPKey(poolId uint64, denom1, denom2 string) []byte { + // Sort denoms + if denom1 > denom2 { + denom1, denom2 = denom2, denom1 + } + + poolIdBz := fmt.Sprintf("%0.20d", poolId) + return []byte(fmt.Sprintf("%s%s%s%s%s%s", OsmosisMostRecentTWAPsPrefix, poolIdBz, OsmosisKeySeparator, denom1, OsmosisKeySeparator, denom2)) +} diff --git a/x/mint/README.md b/x/mint/README.md index de77a81d94..0a5114cbb3 100644 --- a/x/mint/README.md +++ b/x/mint/README.md @@ -73,7 +73,7 @@ func (m Minter) EpochProvision(params Params) sdk.Coin { 3. `epoch_identifier` defines the epoch identifier to be used for mint module e.g. "weekly" 4. `reduction_period_in_epochs` defines the number of epochs to pass to reduce mint amount 5. `reduction_factor` defines the reduction factor of tokens at every `reduction_period_in_epochs` -6. `distribution_proportions` defines distribution rules for minted tokens, when developer rewards address is empty, it distribute tokens to community pool. +6. `distribution_proportions` defines distribution rules for minted tokens, when developer rewards address is empty, it distributes tokens to community pool. 7. `weighted_developer_rewards_receivers` provides the addresses that receives developer rewards by weight 8. `minting_rewards_distribution_start_epoch` defines the start epoch of minting to make sure minting start after initial pools are set diff --git a/x/stakeibc/client/cli/query.go b/x/stakeibc/client/cli/query.go index 0d687a6029..cd89779275 100644 --- a/x/stakeibc/client/cli/query.go +++ b/x/stakeibc/client/cli/query.go @@ -29,6 +29,7 @@ func GetQueryCmd(queryRoute string) *cobra.Command { cmd.AddCommand(CmdListEpochTracker()) cmd.AddCommand(CmdShowEpochTracker()) cmd.AddCommand(CmdNextPacketSequence()) + cmd.AddCommand(CmdListTradeRoutes()) return cmd } diff --git a/x/stakeibc/client/cli/query_trade_routes.go b/x/stakeibc/client/cli/query_trade_routes.go new file mode 100644 index 0000000000..6c370d9177 --- /dev/null +++ b/x/stakeibc/client/cli/query_trade_routes.go @@ -0,0 +1,36 @@ +package cli + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func CmdListTradeRoutes() *cobra.Command { + cmd := &cobra.Command{ + Use: "list-trade-routes", + Short: "list all trade routes", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx := client.GetClientContextFromCmd(cmd) + + queryClient := types.NewQueryClient(clientCtx) + + params := &types.QueryAllTradeRoutes{} + res, err := queryClient.AllTradeRoutes(context.Background(), params) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddPaginationFlagsToCmd(cmd, cmd.Use) + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/stakeibc/client/cli/tx_restore_interchain_account.go b/x/stakeibc/client/cli/tx_restore_interchain_account.go index 92b9adb29f..eefdcfc1f9 100644 --- a/x/stakeibc/client/cli/tx_restore_interchain_account.go +++ b/x/stakeibc/client/cli/tx_restore_interchain_account.go @@ -1,8 +1,6 @@ package cli import ( - "errors" - "fmt" "strings" "github.com/cosmos/cosmos-sdk/client" @@ -15,24 +13,26 @@ import ( func CmdRestoreInterchainAccount() *cobra.Command { cmd := &cobra.Command{ - Use: "restore-interchain-account [chain-id] [account-type]", + Use: "restore-interchain-account [chain-id] [connection-id] [account-owner]", Short: "Broadcast message restore-interchain-account", Long: strings.TrimSpace( - fmt.Sprintf(`Restores a closed channel associated with an interchain account. -Specify the interchain account type as either: %s, %s, %s, or %s`, - types.ICAAccountType_DELEGATION, - types.ICAAccountType_WITHDRAWAL, - types.ICAAccountType_REDEMPTION, - types.ICAAccountType_FEE)), - Args: cobra.ExactArgs(2), + `Restores a closed channel associated with an interchain account. +Specify the chain ID and account owner - where the owner is the alias for the ICA account + +For host zone ICA accounts, the owner is of the form {chainId}.{accountType} +ex: +>>> strided tx restore-interchain-account cosmoshub-4 connection-0 cosmoshub-4.DELEGATION + +For trade route ICA accounts, the owner is of the form: + {chainId}.{rewardDenom}-{hostDenom}.{accountType} +ex: +>>> strided tx restore-interchain-account dydx-mainnet-1 connection-1 dydx-mainnet-1.uusdc-udydx.CONVERTER_TRADE + `), + Args: cobra.ExactArgs(3), RunE: func(cmd *cobra.Command, args []string) (err error) { - argChainId := args[0] - argAccountType := args[1] - - accountType, found := types.ICAAccountType_value[argAccountType] - if !found { - return errors.New("Invalid account type.") - } + chainId := args[0] + connectionId := args[1] + accountOwner := args[2] clientCtx, err := client.GetClientTxContext(cmd) if err != nil { @@ -41,8 +41,9 @@ Specify the interchain account type as either: %s, %s, %s, or %s`, msg := types.NewMsgRestoreInterchainAccount( clientCtx.GetFromAddress().String(), - argChainId, - types.ICAAccountType(accountType), + chainId, + connectionId, + accountOwner, ) if err := msg.ValidateBasic(); err != nil { return err diff --git a/x/stakeibc/handler.go b/x/stakeibc/handler.go index 7663e7aa21..46ab96a0af 100644 --- a/x/stakeibc/handler.go +++ b/x/stakeibc/handler.go @@ -70,6 +70,15 @@ func NewMessageHandler(k keeper.Keeper) sdk.Handler { case *types.MsgResumeHostZone: res, err := msgServer.ResumeHostZone(sdk.WrapSDKContext(ctx), msg) return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgCreateTradeRoute: + res, err := msgServer.CreateTradeRoute(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgDeleteTradeRoute: + res, err := msgServer.DeleteTradeRoute(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + case *types.MsgUpdateTradeRoute: + res, err := msgServer.UpdateTradeRoute(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) default: errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) return nil, errorsmod.Wrap(sdkerrors.ErrUnknownRequest, errMsg) diff --git a/x/stakeibc/ibc_middleware.go b/x/stakeibc/ibc_middleware.go index 8bda28c7f7..151dd990af 100644 --- a/x/stakeibc/ibc_middleware.go +++ b/x/stakeibc/ibc_middleware.go @@ -5,15 +5,12 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" - icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported" - ratelimittypes "github.com/Stride-Labs/stride/v16/x/ratelimit/types" "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" - "github.com/Stride-Labs/stride/v16/x/stakeibc/types" ) var _ porttypes.Middleware = &IBCMiddleware{} @@ -67,118 +64,10 @@ func (im IBCMiddleware) OnChanOpenAck( counterpartyVersion string, ) error { im.keeper.Logger(ctx).Info(fmt.Sprintf("OnChanOpenAck: portID %s, channelID %s, counterpartyChannelID %s, counterpartyVersion %s", portID, channelID, counterpartyChannelID, counterpartyVersion)) - controllerConnectionId, err := im.keeper.GetConnectionId(ctx, portID) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("Unable to get connection for port: %s", portID)) - } - address, found := im.keeper.ICAControllerKeeper.GetInterchainAccountAddress(ctx, controllerConnectionId, portID) - if !found { - ctx.Logger().Error(fmt.Sprintf("Expected to find an address for %s/%s", controllerConnectionId, portID)) - return nil - } - // get host chain id from connection - // fetch counterparty connection - hostChainId, err := im.keeper.GetChainID(ctx, controllerConnectionId) - if err != nil { - ctx.Logger().Error(fmt.Sprintf("Unable to obtain counterparty chain for connection: %s, port: %s, err: %s", controllerConnectionId, portID, err.Error())) - return nil - } - // get zone info - zoneInfo, found := im.keeper.GetHostZone(ctx, hostChainId) - if !found { - ctx.Logger().Error(fmt.Sprintf("Expected to find zone info for %v", hostChainId)) - return nil - } - ctx.Logger().Info(fmt.Sprintf("Found matching address for chain: %s, address %s, port %s", zoneInfo.ChainId, address, portID)) - - // expected port IDs for each ICA account type - withdrawalPortID, err := icatypes.NewControllerPortID(types.FormatICAAccountOwner(hostChainId, types.ICAAccountType_WITHDRAWAL)) - if err != nil { - return err - } - feePortID, err := icatypes.NewControllerPortID(types.FormatICAAccountOwner(hostChainId, types.ICAAccountType_FEE)) - if err != nil { - return err - } - delegationPortID, err := icatypes.NewControllerPortID(types.FormatICAAccountOwner(hostChainId, types.ICAAccountType_DELEGATION)) - if err != nil { - return err - } - redemptionPortID, err := icatypes.NewControllerPortID(types.FormatICAAccountOwner(hostChainId, types.ICAAccountType_REDEMPTION)) - if err != nil { - return err - } - communityPoolDepositOwner := types.FormatICAAccountOwner(hostChainId, types.ICAAccountType_COMMUNITY_POOL_DEPOSIT) - communityPoolDepositPortID, err := icatypes.NewControllerPortID(communityPoolDepositOwner) - if err != nil { + if err := im.keeper.OnChanOpenAck(ctx, portID, channelID); err != nil { + ctx.Logger().Error(fmt.Sprintf("Error during stakeibc OnChanOpenAck: %s", err.Error())) return err } - communityPoolReturnOwner := types.FormatICAAccountOwner(hostChainId, types.ICAAccountType_COMMUNITY_POOL_RETURN) - communityPoolReturnPortID, err := icatypes.NewControllerPortID(communityPoolReturnOwner) - if err != nil { - return err - } - - // Set ICA account addresses - switch { - case portID == withdrawalPortID: - zoneInfo.WithdrawalIcaAddress = address - case portID == feePortID: - zoneInfo.FeeIcaAddress = address - case portID == delegationPortID: - zoneInfo.DelegationIcaAddress = address - case portID == redemptionPortID: - zoneInfo.RedemptionIcaAddress = address - case portID == communityPoolDepositPortID: - zoneInfo.CommunityPoolDepositIcaAddress = address - case portID == communityPoolReturnPortID: - zoneInfo.CommunityPoolReturnIcaAddress = address - default: - ctx.Logger().Error(fmt.Sprintf("Missing portId: %s", portID)) - } - - // Once the delegation channel is registered, whitelist epochly transfers so they're not rate limited - // Epochly transfers go from the deposit address to the delegation address - if portID == delegationPortID { - im.keeper.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ - Sender: zoneInfo.DepositAddress, - Receiver: zoneInfo.DelegationIcaAddress, - }) - } - - // Once the fee channel is registered, whitelist reward transfers so they're not rate limited - // Reward transfers go from the fee address to the reward collector - if portID == feePortID { - rewardCollectorAddress := im.keeper.AccountKeeper.GetModuleAccount(ctx, types.RewardCollectorName).GetAddress() - im.keeper.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ - Sender: zoneInfo.FeeIcaAddress, - Receiver: rewardCollectorAddress.String(), - }) - } - - // Once the community pool deposit ICA is registered, whitelist epochly community pool transfers - // from the deposit ICA to the community pool holding accounts - if portID == communityPoolDepositPortID { - im.keeper.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ - Sender: zoneInfo.CommunityPoolDepositIcaAddress, - Receiver: zoneInfo.CommunityPoolStakeHoldingAddress, - }) - im.keeper.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ - Sender: zoneInfo.CommunityPoolDepositIcaAddress, - Receiver: zoneInfo.CommunityPoolRedeemHoldingAddress, - }) - } - - // Once the community pool return ICA is registered, whitelist epochly community pool transfers - // from the community pool stake holding account to the community pool return ICA - if portID == communityPoolReturnPortID { - im.keeper.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ - Sender: zoneInfo.CommunityPoolStakeHoldingAddress, - Receiver: zoneInfo.CommunityPoolReturnIcaAddress, - }) - } - - im.keeper.SetHostZone(ctx, zoneInfo) // call underlying app's OnChanOpenAck return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) diff --git a/x/stakeibc/keeper/grpc_query_trade_routes.go b/x/stakeibc/keeper/grpc_query_trade_routes.go new file mode 100644 index 0000000000..5bccce8b4d --- /dev/null +++ b/x/stakeibc/keeper/grpc_query_trade_routes.go @@ -0,0 +1,23 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func (k Keeper) AllTradeRoutes(c context.Context, req *types.QueryAllTradeRoutes) (*types.QueryAllTradeRoutesResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(c) + + routes := k.GetAllTradeRoutes(ctx) + + return &types.QueryAllTradeRoutesResponse{TradeRoutes: routes}, nil +} diff --git a/x/stakeibc/keeper/hooks.go b/x/stakeibc/keeper/hooks.go index 1282481d8d..7bef44a506 100644 --- a/x/stakeibc/keeper/hooks.go +++ b/x/stakeibc/keeper/hooks.go @@ -45,6 +45,9 @@ func (k Keeper) BeforeEpochStart(ctx sdk.Context, epochInfo epochstypes.EpochInf delegationInterval := k.GetParam(ctx, types.KeyDelegateInterval) reinvestInterval := k.GetParam(ctx, types.KeyReinvestInterval) + // Claim accrued staking rewards at the beginning of the epoch + k.ClaimAccruedStakingRewards(ctx) + // Create a new deposit record for each host zone and the grab all deposit records k.CreateDepositRecordsForEpoch(ctx, epochNumber) depositRecords := k.RecordsKeeper.GetAllDepositRecord(ctx) @@ -83,10 +86,18 @@ func (k Keeper) BeforeEpochStart(ctx sdk.Context, epochInfo epochstypes.EpochInf // Transfers in and out of tokens for hostZones which have community pools k.ProcessAllCommunityPoolTokens(ctx) + + // Do transfers for all reward and swapped tokens defined by the trade routes every stride epoch + k.TransferAllRewardTokens(ctx) } if epochInfo.Identifier == epochstypes.MINT_EPOCH { k.AllocateHostZoneReward(ctx) } + // At the hour epoch, query the swap price on each trade route and initiate the token swap + if epochInfo.Identifier == epochstypes.HOUR_EPOCH { + k.UpdateAllSwapPrices(ctx) + k.SwapAllRewardTokens(ctx) + } } func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochInfo epochstypes.EpochInfo) {} @@ -151,6 +162,18 @@ func (k Keeper) SetWithdrawalAddress(ctx sdk.Context) { } } +// Claim staking rewards for each host zone +func (k Keeper) ClaimAccruedStakingRewards(ctx sdk.Context) { + k.Logger(ctx).Info("Claiming Accrued Staking Rewards...") + + for _, hostZone := range k.GetAllActiveHostZone(ctx) { + err := k.ClaimAccruedStakingRewardsOnHost(ctx, hostZone) + if err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to claim accrued staking rewards on %s, err: %s", hostZone.ChainId, err)) + } + } +} + // Updates the redemption rate for each host zone // At a high level, the redemption rate is equal to the amount of native tokens locked divided by the stTokens in existence. // The equation is broken down further into the following sub-components: diff --git a/x/stakeibc/keeper/host_zone.go b/x/stakeibc/keeper/host_zone.go index 2630c54f54..4aefc39ab0 100644 --- a/x/stakeibc/keeper/host_zone.go +++ b/x/stakeibc/keeper/host_zone.go @@ -35,6 +35,18 @@ func (k Keeper) GetHostZone(ctx sdk.Context, chainId string) (val types.HostZone return val, true } +// GetActiveHostZone returns an error if the host zone is not found or if it's found, but is halted +func (k Keeper) GetActiveHostZone(ctx sdk.Context, chainId string) (hostZone types.HostZone, err error) { + hostZone, found := k.GetHostZone(ctx, chainId) + if !found { + return hostZone, types.ErrHostZoneNotFound.Wrapf("host zone %s not found", chainId) + } + if hostZone.Halted { + return hostZone, types.ErrHaltedHostZone.Wrapf("host zone %s is halted", chainId) + } + return hostZone, nil +} + // GetHostZoneFromHostDenom returns a HostZone from a HostDenom func (k Keeper) GetHostZoneFromHostDenom(ctx sdk.Context, denom string) (*types.HostZone, error) { var matchZone types.HostZone @@ -62,9 +74,9 @@ func (k Keeper) GetHostZoneFromTransferChannelID(ctx sdk.Context, channelID stri } // RemoveHostZone removes a hostZone from the store -func (k Keeper) RemoveHostZone(ctx sdk.Context, chain_id string) { +func (k Keeper) RemoveHostZone(ctx sdk.Context, chainId string) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.HostZoneKey)) - store.Delete([]byte(chain_id)) + store.Delete([]byte(chainId)) } // GetAllHostZone returns all hostZone diff --git a/x/stakeibc/keeper/ibc.go b/x/stakeibc/keeper/ibc.go new file mode 100644 index 0000000000..50391c7f05 --- /dev/null +++ b/x/stakeibc/keeper/ibc.go @@ -0,0 +1,194 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + + ratelimittypes "github.com/Stride-Labs/stride/v16/x/ratelimit/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func (k Keeper) OnChanOpenAck(ctx sdk.Context, portID, channelID string) error { + // Lookup the ICA address and chainId from the port and connection + controllerConnectionId, found := k.GetConnectionIdFromICAPortId(ctx, portID) + if !found { + k.Logger(ctx).Info(fmt.Sprintf("portId %s has no associated ICA account", portID)) + return nil + } + address, found := k.ICAControllerKeeper.GetInterchainAccountAddress(ctx, controllerConnectionId, portID) + if !found { + k.Logger(ctx).Info(fmt.Sprintf("No ICA address associated with connection %s and port %s", controllerConnectionId, portID)) + return nil + } + chainId, err := k.GetChainIdFromConnectionId(ctx, controllerConnectionId) + if err != nil { + return err + } + k.Logger(ctx).Info(fmt.Sprintf("Found matching address for chain: %s, address %s, port %s", chainId, address, portID)) + + // Check if the chainId matches one of the host zones, and if so, + // store the relevant ICA address on the host zone struct + if err := k.StoreHostZoneIcaAddress(ctx, chainId, portID, address); err != nil { + return err + } + + // Check if the chainId matches any ICAs from trade routes, and if so, + // store the relevant ICA addresses in the trade route structs + if err := k.StoreTradeRouteIcaAddress(ctx, chainId, portID, address); err != nil { + return err + } + + return nil +} + +// Checks if the chainId matches a given host zone, and the address matches a relevant ICA account +// If so, stores the ICA address on the host zone struct +// Also whitelists ICA addresses from rate limiting +func (k Keeper) StoreHostZoneIcaAddress(ctx sdk.Context, chainId, portId, address string) error { + // Check if the chainId matches a host zone + // If the chainId does not match (for instance, a reward zone in a trade route is not a host zone) + // then we can ignore the ICA address checks + hostZone, found := k.GetHostZone(ctx, chainId) + if !found { + k.Logger(ctx).Info(fmt.Sprintf("chainId %s has no associated host zone", chainId)) + return nil + } + + // expected port IDs for each ICA account type + delegationOwner := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_DELEGATION) + delegationPortID, err := icatypes.NewControllerPortID(delegationOwner) + if err != nil { + return err + } + withdrawalOwner := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_WITHDRAWAL) + withdrawalPortID, err := icatypes.NewControllerPortID(withdrawalOwner) + if err != nil { + return err + } + feeOwner := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_FEE) + feePortID, err := icatypes.NewControllerPortID(feeOwner) + if err != nil { + return err + } + redemptionOwner := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_REDEMPTION) + redemptionPortID, err := icatypes.NewControllerPortID(redemptionOwner) + if err != nil { + return err + } + communityPoolDepositOwner := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_COMMUNITY_POOL_DEPOSIT) + communityPoolDepositPortID, err := icatypes.NewControllerPortID(communityPoolDepositOwner) + if err != nil { + return err + } + communityPoolReturnOwner := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_COMMUNITY_POOL_RETURN) + communityPoolReturnPortID, err := icatypes.NewControllerPortID(communityPoolReturnOwner) + if err != nil { + return err + } + + // Set ICA account addresses + switch { + case portId == withdrawalPortID: + hostZone.WithdrawalIcaAddress = address + case portId == feePortID: + hostZone.FeeIcaAddress = address + case portId == delegationPortID: + hostZone.DelegationIcaAddress = address + case portId == redemptionPortID: + hostZone.RedemptionIcaAddress = address + case portId == communityPoolDepositPortID: + hostZone.CommunityPoolDepositIcaAddress = address + case portId == communityPoolReturnPortID: + hostZone.CommunityPoolReturnIcaAddress = address + default: + k.Logger(ctx).Info(fmt.Sprintf("portId %s has an associated host zone, but does not match any ICA accounts", portId)) + return nil + } + + k.SetHostZone(ctx, hostZone) + + // Once the delegation channel is registered, whitelist epochly transfers so they're not rate limited + // Epochly transfers go from the deposit address to the delegation address + if portId == delegationPortID { + k.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ + Sender: hostZone.DepositAddress, + Receiver: hostZone.DelegationIcaAddress, + }) + } + + // Once the fee channel is registered, whitelist reward transfers so they're not rate limited + // Reward transfers go from the fee address to the reward collector + if portId == feePortID { + rewardCollectorAddress := k.AccountKeeper.GetModuleAccount(ctx, types.RewardCollectorName).GetAddress() + k.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ + Sender: hostZone.FeeIcaAddress, + Receiver: rewardCollectorAddress.String(), + }) + } + + // Once the community pool deposit ICA is registered, whitelist epochly community pool transfers + // from the deposit ICA to the community pool holding accounts + if portId == communityPoolDepositPortID { + k.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ + Sender: hostZone.CommunityPoolDepositIcaAddress, + Receiver: hostZone.CommunityPoolStakeHoldingAddress, + }) + k.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ + Sender: hostZone.CommunityPoolDepositIcaAddress, + Receiver: hostZone.CommunityPoolRedeemHoldingAddress, + }) + } + + // Once the community pool return ICA is registered, whitelist epochly community pool transfers + // from the community pool stake holding account to the community pool return ICA + if portId == communityPoolReturnPortID { + k.RatelimitKeeper.SetWhitelistedAddressPair(ctx, ratelimittypes.WhitelistedAddressPair{ + Sender: hostZone.CommunityPoolStakeHoldingAddress, + Receiver: hostZone.CommunityPoolReturnIcaAddress, + }) + } + + return nil +} + +// Checks if the port matches an ICA account on the trade route, and if so, stores the +// relevant ICA address on the trade route +func (k Keeper) StoreTradeRouteIcaAddress(ctx sdk.Context, callbackChainId, callbackPortId, address string) error { + // Check if the port Id matches either the trade or unwind ICA on the tradeRoute + // If the chainId and port Id from the callback match the account + // on a trade route, set the ICA address in the relevant places, + // including the from/to addresses on each hop + for _, route := range k.GetAllTradeRoutes(ctx) { + // Build the expected port ID for the reward and trade accounts, + // using the chainId and route ID + rewardAccount := route.RewardAccount + rewardOwner := types.FormatTradeRouteICAOwnerFromRouteId(rewardAccount.ChainId, route.GetRouteId(), rewardAccount.Type) + rewardPortId, err := icatypes.NewControllerPortID(rewardOwner) + if err != nil { + return err + } + + tradeAccount := route.TradeAccount + tradeOwner := types.FormatTradeRouteICAOwnerFromRouteId(tradeAccount.ChainId, route.GetRouteId(), tradeAccount.Type) + tradePortId, err := icatypes.NewControllerPortID(tradeOwner) + if err != nil { + return err + } + + // Check if route IDs match the callback chainId/portId + if route.RewardAccount.ChainId == callbackChainId && callbackPortId == rewardPortId { + k.Logger(ctx).Info(fmt.Sprintf("ICA Address %s found for Unwind ICA on %s", address, route.Description())) + route.RewardAccount.Address = address + + } else if route.TradeAccount.ChainId == callbackChainId && callbackPortId == tradePortId { + k.Logger(ctx).Info(fmt.Sprintf("ICA Address %s found for Trade ICA on %s", address, route.Description())) + route.TradeAccount.Address = address + } + + k.SetTradeRoute(ctx, route) + } + + return nil +} diff --git a/x/stakeibc/keeper/ibc_test.go b/x/stakeibc/keeper/ibc_test.go new file mode 100644 index 0000000000..6edc972eff --- /dev/null +++ b/x/stakeibc/keeper/ibc_test.go @@ -0,0 +1,294 @@ +package keeper_test + +import ( + icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// ------------------------------------------ +// OnChanOpenAck +// ------------------------------------------ + +func (s *KeeperTestSuite) TestOnChanOpenAck() { + // Define the mocked out ids for both the delegation and trade accounts + delegationChainId := "delegation-1" + delegationAddress := "delegation-address" + delegationConnectionId := "connection-0" + delegationChannelId := "channel-0" + delegationClientId := "07-tendermint-0" + + tradeChainId := "trade-1" + tradeAddress := "trade-address" + tradeConnectionId := "connection-1" + tradeChannelId := "channel-1" + tradeClientId := "07-tendermint-1" + + // Create a host zone with out any ICA addresses + s.App.StakeibcKeeper.SetHostZone(s.Ctx, types.HostZone{ + ChainId: delegationChainId, + }) + + // Create a trade route without any ICA addresses + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + TradeAccount: types.ICAAccount{ + ChainId: tradeChainId, + Type: types.ICAAccountType_CONVERTER_TRADE, + }, + }) + + // Create the ICA channels for both the delegation and trade accounts + delegationOwner := types.FormatHostZoneICAOwner(delegationChainId, types.ICAAccountType_DELEGATION) + delegationPortId, _ := icatypes.NewControllerPortID(delegationOwner) + + tradeOwner := types.FormatTradeRouteICAOwner(tradeChainId, RewardDenom, HostDenom, types.ICAAccountType_CONVERTER_TRADE) + tradePortId, _ := icatypes.NewControllerPortID(tradeOwner) + + // Mock out an ICA address for each + s.App.ICAControllerKeeper.SetInterchainAccountAddress(s.Ctx, delegationConnectionId, delegationPortId, delegationAddress) + s.App.ICAControllerKeeper.SetInterchainAccountAddress(s.Ctx, tradeConnectionId, tradePortId, tradeAddress) + + // Mock out a client and connection for each channel so the callback can map back from portId to chainId + s.MockClientAndConnection(delegationChainId, delegationClientId, delegationConnectionId) + s.MockClientAndConnection(tradeChainId, tradeClientId, tradeConnectionId) + + // Call the callback with the delegation ICA port and confirm the delegation address is set + err := s.App.StakeibcKeeper.OnChanOpenAck(s.Ctx, delegationPortId, delegationChannelId) + s.Require().NoError(err, "no error expected when running callback with delegation port") + + hostZone := s.MustGetHostZone(delegationChainId) + s.Require().Equal(delegationAddress, hostZone.DelegationIcaAddress, "delegation address") + + // Call the callback with the trade ICA port and confirm the trade address is set + err = s.App.StakeibcKeeper.OnChanOpenAck(s.Ctx, tradePortId, tradeChannelId) + s.Require().NoError(err, "no error expected when running callback with trade port") + + tradeRoute, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, RewardDenom, HostDenom) + s.Require().True(found, "trade route should have been round") + s.Require().Equal(tradeAddress, tradeRoute.TradeAccount.Address, "trade address") + + // Call the callback with a non-ICA port and confirm the host zone and trade route remained unchanged + err = s.App.StakeibcKeeper.OnChanOpenAck(s.Ctx, tradePortId, tradeChannelId) + s.Require().NoError(err, "no error expected when running callback with non-ICA port") + + finalHostZone := s.MustGetHostZone(delegationChainId) + s.Require().Equal(hostZone, finalHostZone, "host zone should not have been modified") + + finalTradeRoute, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, RewardDenom, HostDenom) + s.Require().True(found, "trade route should have been round") + s.Require().Equal(tradeRoute, finalTradeRoute, "trade route should not have been modified") +} + +// ------------------------------------------ +// StoreHostZoneIcaAddress +// ------------------------------------------ + +// Helper function to check that a single ICA address was stored on the host zone +// The address stored will match the string of the ICA account type +func (s *KeeperTestSuite) checkHostZoneAddressStored(accountType types.ICAAccountType) { + // Determine the expected ICA addresses based on whether the account in question + // is registered in this test case + delegationAddress := "" + if accountType == types.ICAAccountType_DELEGATION { + delegationAddress = accountType.String() + } + withdrawalAddress := "" + if accountType == types.ICAAccountType_WITHDRAWAL { + withdrawalAddress = accountType.String() + } + redemptionAddress := "" + if accountType == types.ICAAccountType_REDEMPTION { + redemptionAddress = accountType.String() + } + feeAddress := "" + if accountType == types.ICAAccountType_FEE { + feeAddress = accountType.String() + } + communityPoolDepositAddress := "" + if accountType == types.ICAAccountType_COMMUNITY_POOL_DEPOSIT { + communityPoolDepositAddress = accountType.String() + } + communityPoolReturnAddress := "" + if accountType == types.ICAAccountType_COMMUNITY_POOL_RETURN { + communityPoolReturnAddress = accountType.String() + } + + // Confirm the expected addresses with the host zone + hostZone := s.MustGetHostZone(HostChainId) + + s.Require().Equal(delegationAddress, hostZone.DelegationIcaAddress, "delegation address") + s.Require().Equal(withdrawalAddress, hostZone.WithdrawalIcaAddress, "withdrawal address") + s.Require().Equal(redemptionAddress, hostZone.RedemptionIcaAddress, "redemption address") + s.Require().Equal(feeAddress, hostZone.FeeIcaAddress, "fee address") + s.Require().Equal(communityPoolDepositAddress, hostZone.CommunityPoolDepositIcaAddress, "community pool deposit address") + s.Require().Equal(communityPoolReturnAddress, hostZone.CommunityPoolReturnIcaAddress, "commuity pool return address") +} + +// Helper function to check that relevant ICA addresses are whitelisted after the callback +func (s *KeeperTestSuite) checkAddressesWhitelisted(accountType types.ICAAccountType) { + if accountType == types.ICAAccountType_DELEGATION { + isWhitelisted := s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, DepositAddress, accountType.String()) + s.Require().True(isWhitelisted, "deposit -> delegation whitelist") + } + + if accountType == types.ICAAccountType_FEE { + sender := accountType.String() + receiver := s.App.AccountKeeper.GetModuleAccount(s.Ctx, types.RewardCollectorName).GetAddress().String() + + isWhitelisted := s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, sender, receiver) + s.Require().True(isWhitelisted, "fee -> reward collector whitelist") + } + + if accountType == types.ICAAccountType_COMMUNITY_POOL_DEPOSIT { + sender := accountType.String() + + receiver := CommunityPoolStakeHoldingAddress + isWhitelisted := s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, sender, receiver) + s.Require().True(isWhitelisted, "community pool deposit -> community pool stake holding") + + receiver = CommunityPoolRedeemHoldingAddress + isWhitelisted = s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, sender, receiver) + s.Require().True(isWhitelisted, "community pool deposit -> community pool redeem holding") + } + + if accountType == types.ICAAccountType_COMMUNITY_POOL_RETURN { + sender := CommunityPoolStakeHoldingAddress + receiver := accountType.String() + + isWhitelisted := s.App.RatelimitKeeper.IsAddressPairWhitelisted(s.Ctx, sender, receiver) + s.Require().True(isWhitelisted, "community pool stake holding -> community pool return") + } +} + +func (s *KeeperTestSuite) TestStoreHostZoneIcaAddress() { + // We'll run a test case for each ICA account, with two of them not being relevant for the host zone + icaAccountTypes := []types.ICAAccountType{ + types.ICAAccountType_DELEGATION, + types.ICAAccountType_WITHDRAWAL, + types.ICAAccountType_REDEMPTION, + types.ICAAccountType_FEE, + types.ICAAccountType_COMMUNITY_POOL_DEPOSIT, + types.ICAAccountType_COMMUNITY_POOL_RETURN, + + types.ICAAccountType_CONVERTER_TRADE, // not on the host zone + -1, // indicates test case for non-ICA port + } + + for _, accountType := range icaAccountTypes { + // Reset the host zone for each test and wipe all addresses + s.App.StakeibcKeeper.SetHostZone(s.Ctx, types.HostZone{ + ChainId: HostChainId, + DepositAddress: DepositAddress, + CommunityPoolStakeHoldingAddress: CommunityPoolStakeHoldingAddress, + CommunityPoolRedeemHoldingAddress: CommunityPoolRedeemHoldingAddress, + }) + + // Determine the port Id from the account type + // If the portId is -1, pass a non-ica port + portId := "not-ica-port" + if accountType != -1 { + owner := types.FormatHostZoneICAOwner(HostChainId, accountType) + portId, _ = icatypes.NewControllerPortID(owner) + } + + // Call StoreHostZoneIcaAddress with the portId + // use the account name as the address to make the matching easier + address := accountType.String() + err := s.App.StakeibcKeeper.StoreHostZoneIcaAddress(s.Ctx, HostChainId, portId, address) + s.Require().NoError(err, "no error expected when calling store host zone ICA for %s", accountType.String()) + + // Check if the updated addresses matches expectations + s.checkHostZoneAddressStored(accountType) + + // Check that the relevant accounts are white listed from the rate limiter + s.checkAddressesWhitelisted(accountType) + } +} + +// ------------------------------------------ +// StoreTradeRouteIcaAddress +// ------------------------------------------ + +// Helper function to check that a single ICA address was stored on the trade route +// The address stored will match the string of the ICA account type +func (s *KeeperTestSuite) checkTradeRouteAddressStored(accountType types.ICAAccountType) { + // Determine the expected ICA addresses based on whether the account in question + // is registered in this test case + unwindAddress := "" + if accountType == types.ICAAccountType_CONVERTER_UNWIND { + unwindAddress = types.ICAAccountType_CONVERTER_UNWIND.String() + } + tradeAddress := "" + if accountType == types.ICAAccountType_CONVERTER_TRADE { + tradeAddress = types.ICAAccountType_CONVERTER_TRADE.String() + } + + // Confirm the expected addresses with the host zone + tradeRoute, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, RewardDenom, HostDenom) + s.Require().True(found, "trade route should have been found") + + s.Require().Equal(unwindAddress, tradeRoute.RewardAccount.Address, "unwind address") + s.Require().Equal(tradeAddress, tradeRoute.TradeAccount.Address, "trade address") +} + +func (s *KeeperTestSuite) TestStoreTradeRouteIcaAddress() { + // We'll run a test case for each the two ICA accounts, and 2 test cases for ports not on the trade route + icaAccountTypes := []types.ICAAccountType{ + types.ICAAccountType_CONVERTER_UNWIND, + types.ICAAccountType_CONVERTER_TRADE, + + types.ICAAccountType_DELEGATION, // not on the trade route + -1, // indicates test case for non-ICA port + } + + emptyTradeRoute := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + RewardAccount: types.ICAAccount{ + ChainId: HostChainId, + Type: types.ICAAccountType_CONVERTER_UNWIND, + }, + TradeAccount: types.ICAAccount{ + ChainId: HostChainId, + Type: types.ICAAccountType_CONVERTER_TRADE, + }, + } + + for _, accountType := range icaAccountTypes { + // Reset the trade route for each test and wipe all addresses + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, emptyTradeRoute) + + // Determine the port Id from the account type + // If the portId is -1, pass a non-ica port + portId := "not-ica-port" + if accountType != -1 { + owner := types.FormatTradeRouteICAOwner(HostChainId, RewardDenom, HostDenom, accountType) + portId, _ = icatypes.NewControllerPortID(owner) + } + + // Call StoreTradeRouteIcaAddress with the portId + // use the account name as the address to make the matching easier + address := accountType.String() + err := s.App.StakeibcKeeper.StoreTradeRouteIcaAddress(s.Ctx, HostChainId, portId, address) + s.Require().NoError(err, "no error expected when calling store trade route ICA for %s", accountType.String()) + + // Check if the updated addresses matches expectations + s.checkTradeRouteAddressStored(accountType) + } + + // Check with a matching port, but no matching chainId + accountType := types.ICAAccountType_CONVERTER_TRADE + owner := types.FormatTradeRouteICAOwner(HostChainId, RewardDenom, HostDenom, accountType) + portId, _ := icatypes.NewControllerPortID(owner) + address := accountType.String() + + emptyTradeRoute.TradeAccount.ChainId = "different-chain-id" + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, emptyTradeRoute) + + err := s.App.StakeibcKeeper.StoreTradeRouteIcaAddress(s.Ctx, HostChainId, portId, address) + s.Require().NoError(err, "no error expected when calling store trade route ICA for trade ICA with no chainId") + + s.checkTradeRouteAddressStored(-1) // checks no matches +} diff --git a/x/stakeibc/keeper/icacallbacks_delegate.go b/x/stakeibc/keeper/icacallbacks_delegate.go index 555ebf5241..5ef4d44ac9 100644 --- a/x/stakeibc/keeper/icacallbacks_delegate.go +++ b/x/stakeibc/keeper/icacallbacks_delegate.go @@ -1,7 +1,6 @@ package keeper import ( - "errors" "fmt" "github.com/spf13/cast" @@ -67,12 +66,6 @@ func (k Keeper) DelegateCallback(ctx sdk.Context, packet channeltypes.Packet, ac // Regardless of failure/success/timeout, indicate that this ICA has completed for _, splitDelegation := range delegateCallback.SplitDelegations { if err := k.DecrementValidatorDelegationChangesInProgress(&hostZone, splitDelegation.Validator); err != nil { - // TODO: Revert after v14 upgrade - if errors.Is(err, types.ErrInvalidValidatorDelegationUpdates) { - k.Logger(ctx).Error(utils.LogICACallbackWithHostZone(chainId, ICACallbackID_Delegate, - "Invariant failed - delegation changes in progress fell below 0 for %s", splitDelegation.Validator)) - continue - } return err } } diff --git a/x/stakeibc/keeper/icacallbacks_undelegate.go b/x/stakeibc/keeper/icacallbacks_undelegate.go index 3be93092f7..62b0f75fe2 100644 --- a/x/stakeibc/keeper/icacallbacks_undelegate.go +++ b/x/stakeibc/keeper/icacallbacks_undelegate.go @@ -48,12 +48,6 @@ func (k Keeper) UndelegateCallback(ctx sdk.Context, packet channeltypes.Packet, } for _, splitDelegation := range undelegateCallback.SplitDelegations { if err := k.DecrementValidatorDelegationChangesInProgress(&hostZone, splitDelegation.Validator); err != nil { - // TODO: Revert after v14 upgrade - if errors.Is(err, types.ErrInvalidValidatorDelegationUpdates) { - k.Logger(ctx).Error(utils.LogICACallbackWithHostZone(chainId, ICACallbackID_Undelegate, - "Invariant failed - delegation changes in progress fell below 0 for %s", splitDelegation.Validator)) - continue - } return err } } diff --git a/x/stakeibc/keeper/icqcallbacks.go b/x/stakeibc/keeper/icqcallbacks.go index 23d004edec..e6e6f94acd 100644 --- a/x/stakeibc/keeper/icqcallbacks.go +++ b/x/stakeibc/keeper/icqcallbacks.go @@ -13,6 +13,10 @@ const ( ICQCallbackID_Validator = "validator" ICQCallbackID_Calibrate = "calibrate" ICQCallbackID_CommunityPoolIcaBalance = "communitypoolicabalance" + ICQCallbackID_WithdrawalRewardBalance = "withdrawalrewardbalance" + ICQCallbackID_TradeRewardBalance = "traderewardbalance" + ICQCallbackID_TradeConvertedBalance = "tradeconvertedbalance" + ICQCallbackID_PoolPrice = "poolprice" ) // ICQCallbacks wrapper struct for stakeibc keeper @@ -50,5 +54,9 @@ func (c ICQCallbacks) RegisterICQCallbacks() icqtypes.QueryCallbacks { AddICQCallback(ICQCallbackID_Delegation, ICQCallback(DelegatorSharesCallback)). AddICQCallback(ICQCallbackID_Validator, ICQCallback(ValidatorSharesToTokensRateCallback)). AddICQCallback(ICQCallbackID_Calibrate, ICQCallback(CalibrateDelegationCallback)). - AddICQCallback(ICQCallbackID_CommunityPoolIcaBalance, ICQCallback(CommunityPoolIcaBalanceCallback)) + AddICQCallback(ICQCallbackID_CommunityPoolIcaBalance, ICQCallback(CommunityPoolIcaBalanceCallback)). + AddICQCallback(ICQCallbackID_WithdrawalRewardBalance, ICQCallback(WithdrawalRewardBalanceCallback)). + AddICQCallback(ICQCallbackID_TradeRewardBalance, ICQCallback(TradeRewardBalanceCallback)). + AddICQCallback(ICQCallbackID_TradeConvertedBalance, ICQCallback(TradeConvertedBalanceCallback)). + AddICQCallback(ICQCallbackID_PoolPrice, ICQCallback(PoolPriceCallback)) } diff --git a/x/stakeibc/keeper/icqcallbacks_fee_balance_test.go b/x/stakeibc/keeper/icqcallbacks_fee_balance_test.go index a0ef76437c..a6a4e78196 100644 --- a/x/stakeibc/keeper/icqcallbacks_fee_balance_test.go +++ b/x/stakeibc/keeper/icqcallbacks_fee_balance_test.go @@ -216,5 +216,5 @@ func (s *KeeperTestSuite) TestFeeBalanceCallback_FailedSubmitTx() { err := keeper.FeeBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.validArgs.callbackArgs, tc.validArgs.query) s.Require().ErrorContains(err, "Failed to SubmitTxs") - s.Require().ErrorContains(err, "invalid connection id, connection-X not found") + s.Require().ErrorContains(err, "connection connection-X not found") } diff --git a/x/stakeibc/keeper/icqcallbacks_pool_price.go b/x/stakeibc/keeper/icqcallbacks_pool_price.go new file mode 100644 index 0000000000..5110f042ee --- /dev/null +++ b/x/stakeibc/keeper/icqcallbacks_pool_price.go @@ -0,0 +1,97 @@ +package keeper + +import ( + "fmt" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + + "github.com/Stride-Labs/stride/v16/utils" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// PoolPriceCallback is a callback handler for PoolPrice query. +// The query response returns an Osmosis TwapRecord for the associated pool denom's +// +// The assets in the response are identified by indicies and are sorted alphabetically +// (e.g. if the two denom's are ibc/AXXX, and ibc/BXXX, +// then Asset0Denom is ibc/AXXX and Asset1Denom is ibc/BXXX) +// +// The price fields (P0LastSpotPrice and P1LastSpotPrice) represent the relative +// ratios of tokens in the pool +// +// P0LastSpotPrice gives the ratio of Asset0Denom / Asset1Denom +// P1LastSpotPrice gives the ratio of Asset1Denom / Asset0Denom +// +// When storing down the price, we want to store down the ratio of HostDenom. +// Meaning, if Asset0Denom is the host denom, we want to store P0LastSpotPrice +func PoolPriceCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) error { + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(query.ChainId, ICQCallbackID_PoolPrice, + "Starting pool spot price callback, QueryId: %vs, QueryType: %s, Connection: %s", query.Id, query.QueryType, query.ConnectionId)) + + chainId := query.ChainId // should be the tradeZoneId, used in logging + + // Unmarshal the query response args, should be a TwapRecord type + var twapRecord types.OsmosisTwapRecord + err := twapRecord.Unmarshal(args) + if err != nil { + return errorsmod.Wrap(err, "unable to unmarshal the query response") + } + + // Unmarshal the callback data containing the tradeRoute we are on + var tradeRouteCallback types.TradeRouteCallback + if err := proto.Unmarshal(query.CallbackData, &tradeRouteCallback); err != nil { + return errorsmod.Wrapf(err, "unable to unmarshal trade reward balance callback data") + } + + // Lookup the trade route from the keys in the callback + tradeRoute, found := k.GetTradeRoute(ctx, tradeRouteCallback.RewardDenom, tradeRouteCallback.HostDenom) + if !found { + return types.ErrTradeRouteNotFound.Wrapf("trade route from %s to %s not found", + tradeRouteCallback.RewardDenom, tradeRouteCallback.HostDenom) + } + + // Confirm the denom's from the query response match the denom's in the route + if err := AssertTwapAssetsMatchTradeRoute(twapRecord, tradeRoute); err != nil { + return err + } + + // Get the associate "SpotPrice" from the twap record, based on the asset ordering + // The "SpotPrice" is actually a ratio of the assets in the pool + var price sdk.Dec + if twapRecord.Asset0Denom == tradeRoute.HostDenomOnTradeZone { + price = twapRecord.P0LastSpotPrice + } else { + price = twapRecord.P1LastSpotPrice + } + + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_PoolPrice, + "Query response - price ratio of %s to %s is %s", + tradeRoute.RewardDenomOnTradeZone, tradeRoute.HostDenomOnTradeZone, price)) + + // Update the price and time on the trade route data + tradeRoute.TradeConfig.SwapPrice = price + tradeRoute.TradeConfig.PriceUpdateTimestamp = uint64(ctx.BlockTime().UnixNano()) + k.SetTradeRoute(ctx, tradeRoute) + + return nil +} + +// Helper function to confirm that the two assets in the twap record match the assets in the trade route +// The assets in the twap record are sorted alphabetically, so we have to check both orderings +func AssertTwapAssetsMatchTradeRoute(twapRecord types.OsmosisTwapRecord, tradeRoute types.TradeRoute) error { + hostDenomMatchFirst := twapRecord.Asset0Denom == tradeRoute.HostDenomOnTradeZone + rewardDenomMatchSecond := twapRecord.Asset1Denom == tradeRoute.RewardDenomOnTradeZone + + rewardDenomMatchFirst := twapRecord.Asset0Denom == tradeRoute.RewardDenomOnTradeZone + hostDenomMatchSecond := twapRecord.Asset1Denom == tradeRoute.HostDenomOnTradeZone + + if (hostDenomMatchFirst && rewardDenomMatchSecond) || (rewardDenomMatchFirst && hostDenomMatchSecond) { + return nil + } + + return fmt.Errorf("Assets in query response (%s, %s) do not match denom's from trade route (%s, %s)", + twapRecord.Asset0Denom, twapRecord.Asset1Denom, tradeRoute.HostDenomOnTradeZone, tradeRoute.RewardDenomOnTradeZone) +} diff --git a/x/stakeibc/keeper/icqcallbacks_pool_price_test.go b/x/stakeibc/keeper/icqcallbacks_pool_price_test.go new file mode 100644 index 0000000000..6e03028343 --- /dev/null +++ b/x/stakeibc/keeper/icqcallbacks_pool_price_test.go @@ -0,0 +1,227 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +type PoolPriceQueryCallbackTestCase struct { + TradeRoute types.TradeRoute + Price sdk.Dec + Response ICQCallbackArgs +} + +func (s *KeeperTestSuite) SetupPoolPriceCallbackTestCase(priceOnAsset0 bool) PoolPriceQueryCallbackTestCase { + hostPrice := sdk.MustNewDecFromStr("1.2") + rewardPrice := sdk.MustNewDecFromStr("0.8") + + // Alphabetize the and sort the denom's according to the ordering + rewardDenom := "ibc/reward-denom-on-trade" + hostDenom := "ibc/host-denom-on-trade" + + var twapRecord types.OsmosisTwapRecord + if priceOnAsset0 { + hostDenom = "a-" + hostDenom + rewardDenom = "z-" + rewardDenom + + twapRecord = types.OsmosisTwapRecord{ + Asset0Denom: hostDenom, + Asset1Denom: rewardDenom, + P0LastSpotPrice: hostPrice, + P1LastSpotPrice: rewardPrice, + } + } else { + hostDenom = "z-" + hostDenom + rewardDenom = "a-" + rewardDenom + + twapRecord = types.OsmosisTwapRecord{ + Asset0Denom: rewardDenom, + Asset1Denom: hostDenom, + P0LastSpotPrice: rewardPrice, + P1LastSpotPrice: hostPrice, + } + } + + route := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + + RewardDenomOnTradeZone: rewardDenom, + HostDenomOnTradeZone: hostDenom, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, route) + + // Build query object and serialized query response + callbackDataBz, _ := proto.Marshal(&types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: HostDenom, + }) + query := icqtypes.Query{CallbackData: callbackDataBz} + queryResponse, _ := proto.Marshal(&twapRecord) + + return PoolPriceQueryCallbackTestCase{ + TradeRoute: route, + Price: hostPrice, + Response: ICQCallbackArgs{ + Query: query, + CallbackArgs: queryResponse, + }, + } +} + +func (s *KeeperTestSuite) TestPoolPriceCallback_Successful_HostTokenFirst() { + hostTokenFirst := true + tc := s.SetupPoolPriceCallbackTestCase(hostTokenFirst) + + err := keeper.PoolPriceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + s.Require().NoError(err) + + // Confirm the new price was set on the trade route + route, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, RewardDenom, HostDenom) + s.Require().True(found, "trade route should have been found") + s.Require().Equal(tc.Price.String(), route.TradeConfig.SwapPrice.String(), "pool price") +} + +func (s *KeeperTestSuite) TestPoolPriceCallback_Successful_RewardTokenFirst() { + hostTokenFirst := false + tc := s.SetupPoolPriceCallbackTestCase(hostTokenFirst) + + err := keeper.PoolPriceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + s.Require().NoError(err) + + // Confirm the new price was set on the trade route + route, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, RewardDenom, HostDenom) + s.Require().True(found, "trade route should have been found") + s.Require().Equal(tc.Price.String(), route.TradeConfig.SwapPrice.String(), "pool price") +} + +func (s *KeeperTestSuite) TestPoolPriceCallback_InvalidArgs() { + tc := s.SetupPoolPriceCallbackTestCase(true) // ordering doesn't matter + + // Submit callback with invalid callback args (so that it can't unmarshal into a coin) + invalidArgs := []byte("random bytes") + + err := keeper.PoolPriceCallback(s.App.StakeibcKeeper, s.Ctx, invalidArgs, tc.Response.Query) + s.Require().ErrorContains(err, "unable to unmarshal the query response") +} + +func (s *KeeperTestSuite) TestPoolPriceCallback_FailedToUnmarshalCallback() { + tc := s.SetupPoolPriceCallbackTestCase(true) // ordering doesn't matter + + // Update the callback data so that it can't be successfully unmarshalled + invalidQuery := tc.Response.Query + invalidQuery.CallbackData = []byte("random bytes") + + err := keeper.PoolPriceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, invalidQuery) + s.Require().ErrorContains(err, "unable to unmarshal trade reward balance callback data") +} + +func (s *KeeperTestSuite) TestPoolPriceCallback_TradeRouteNotFound() { + tc := s.SetupPoolPriceCallbackTestCase(true) // ordering doesn't matter + + // Update the callback data so that it keys to a trade route that doesn't exist + invalidCallbackDataBz, _ := proto.Marshal(&types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: "different-host-denom", + }) + invalidQuery := tc.Response.Query + invalidQuery.CallbackData = invalidCallbackDataBz + + err := keeper.PoolPriceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, invalidQuery) + s.Require().ErrorContains(err, "trade route not found") +} + +func (s *KeeperTestSuite) TestPoolPriceCallback_TradeDenomMismatch() { + tc := s.SetupPoolPriceCallbackTestCase(true) // ordering doesn't matter + + // Update the trade route so that the denom's in the route don't match the query response + invalidTradeRoute := tc.TradeRoute + invalidTradeRoute.RewardDenomOnTradeZone = "different-denom" + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, invalidTradeRoute) + + err := keeper.PoolPriceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + s.Require().ErrorContains(err, "Assets in query response") + s.Require().ErrorContains(err, "do not match denom's from trade route") + + // Do it again, but with the other denom + invalidTradeRoute = tc.TradeRoute + invalidTradeRoute.HostDenomOnTradeZone = "different-denom" + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, invalidTradeRoute) + + err = keeper.PoolPriceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + s.Require().ErrorContains(err, "Assets in query response") + s.Require().ErrorContains(err, "do not match denom's from trade route") +} + +func (s *KeeperTestSuite) TestAssertTwapAssetsMatchTradeRoute() { + testCases := []struct { + name string + twapRecord types.OsmosisTwapRecord + tradeRoute types.TradeRoute + expectedMatch bool + }{ + { + name: "successful match - 1", + twapRecord: types.OsmosisTwapRecord{Asset0Denom: "denom-a", Asset1Denom: "denom-b"}, + tradeRoute: types.TradeRoute{RewardDenomOnTradeZone: "denom-a", HostDenomOnTradeZone: "denom-b"}, + expectedMatch: true, + }, + { + name: "successful match - 2", + twapRecord: types.OsmosisTwapRecord{Asset0Denom: "denom-b", Asset1Denom: "denom-a"}, + tradeRoute: types.TradeRoute{RewardDenomOnTradeZone: "denom-b", HostDenomOnTradeZone: "denom-a"}, + expectedMatch: true, + }, + { + name: "successful match - 3", + twapRecord: types.OsmosisTwapRecord{Asset0Denom: "denom-a", Asset1Denom: "denom-b"}, + tradeRoute: types.TradeRoute{RewardDenomOnTradeZone: "denom-b", HostDenomOnTradeZone: "denom-a"}, + expectedMatch: true, + }, + { + name: "successful match - 4", + twapRecord: types.OsmosisTwapRecord{Asset0Denom: "denom-b", Asset1Denom: "denom-a"}, + tradeRoute: types.TradeRoute{RewardDenomOnTradeZone: "denom-a", HostDenomOnTradeZone: "denom-b"}, + expectedMatch: true, + }, + { + name: "mismatch osmo asset 0", + twapRecord: types.OsmosisTwapRecord{Asset0Denom: "denom-z", Asset1Denom: "denom-b"}, + tradeRoute: types.TradeRoute{RewardDenomOnTradeZone: "denom-a", HostDenomOnTradeZone: "denom-b"}, + expectedMatch: false, + }, + { + name: "mismatch osmo asset 1", + twapRecord: types.OsmosisTwapRecord{Asset0Denom: "denom-a", Asset1Denom: "denom-z"}, + tradeRoute: types.TradeRoute{RewardDenomOnTradeZone: "denom-a", HostDenomOnTradeZone: "denom-b"}, + expectedMatch: false, + }, + { + name: "mismatch route reward denom", + twapRecord: types.OsmosisTwapRecord{Asset0Denom: "denom-a", Asset1Denom: "denom-b"}, + tradeRoute: types.TradeRoute{RewardDenomOnTradeZone: "denom-z", HostDenomOnTradeZone: "denom-b"}, + expectedMatch: false, + }, + { + name: "mismatch route host denom", + twapRecord: types.OsmosisTwapRecord{Asset0Denom: "denom-a", Asset1Denom: "denom-b"}, + tradeRoute: types.TradeRoute{RewardDenomOnTradeZone: "denom-a", HostDenomOnTradeZone: "denom-z"}, + expectedMatch: false, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + err := keeper.AssertTwapAssetsMatchTradeRoute(tc.twapRecord, tc.tradeRoute) + if tc.expectedMatch { + s.Require().NoError(err) + } else { + s.Require().Error(err) + } + }) + } +} diff --git a/x/stakeibc/keeper/icqcallbacks_trade_converted_balance.go b/x/stakeibc/keeper/icqcallbacks_trade_converted_balance.go new file mode 100644 index 0000000000..79696d70d6 --- /dev/null +++ b/x/stakeibc/keeper/icqcallbacks_trade_converted_balance.go @@ -0,0 +1,64 @@ +package keeper + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/gogoproto/proto" + + icqkeeper "github.com/Stride-Labs/stride/v16/x/interchainquery/keeper" + + "github.com/Stride-Labs/stride/v16/utils" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// TradeConvertedBalanceCallback is a callback handler for TradeConvertedBalance queries. +// The query response will return the trade account balance for a converted (foreign ibc) denom +// If the balance is non-zero, ICA MsgSends are submitted to transfer the discovered balance back to hostZone +// +// Note: for now, to get proofs in your ICQs, you need to query the entire store on the host zone! e.g. "store/bank/key" +func TradeConvertedBalanceCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) error { + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(query.ChainId, ICQCallbackID_TradeConvertedBalance, + "Starting trade converted balance callback, QueryId: %vs, QueryType: %s, Connection: %s", query.Id, query.QueryType, query.ConnectionId)) + + chainId := query.ChainId // should be the tradeZoneId + + // Unmarshal the query response args to determine the balance + tradeConvertedBalanceAmount, err := icqkeeper.UnmarshalAmountFromBalanceQuery(k.cdc, args) + if err != nil { + return errorsmod.Wrap(err, "unable to determine balance from query response") + } + + // Unmarshal the callback data containing the tradeRoute we are on + var tradeRouteCallback types.TradeRouteCallback + if err := proto.Unmarshal(query.CallbackData, &tradeRouteCallback); err != nil { + return errorsmod.Wrapf(err, "unable to unmarshal trade reward balance callback data") + } + + // Lookup the trade route from the keys in the callback + tradeRoute, found := k.GetTradeRoute(ctx, tradeRouteCallback.RewardDenom, tradeRouteCallback.HostDenom) + if !found { + return types.ErrTradeRouteNotFound.Wrapf("trade route from %s to %s not found", + tradeRouteCallback.RewardDenom, tradeRouteCallback.HostDenom) + } + + // Confirm the balance is greater than zero, or else exit with no further action + if tradeConvertedBalanceAmount.LTE(sdkmath.ZeroInt()) { + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_TradeConvertedBalance, + "Not enough balance of traded tokens yet, balance: %v", tradeConvertedBalanceAmount)) + return nil + } + + // Using ICA commands on the trade address, transfer the found converted tokens from the trade zone to the host zone + if err := k.TransferConvertedTokensTradeToHost(ctx, tradeConvertedBalanceAmount, tradeRoute); err != nil { + return errorsmod.Wrapf(err, "initiating transfer of converted tokens to back to host zone failed") + } + + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_TradeConvertedBalance, + "Sending discovered converted tokens %v %s from tradeZone back to hostZone", + tradeConvertedBalanceAmount, tradeRoute.HostDenomOnTradeZone)) + + return nil +} diff --git a/x/stakeibc/keeper/icqcallbacks_trade_converted_balance_test.go b/x/stakeibc/keeper/icqcallbacks_trade_converted_balance_test.go new file mode 100644 index 0000000000..6d6162209e --- /dev/null +++ b/x/stakeibc/keeper/icqcallbacks_trade_converted_balance_test.go @@ -0,0 +1,137 @@ +package keeper_test + +import ( + "time" + + sdkmath "cosmossdk.io/math" + "github.com/cosmos/gogoproto/proto" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + + epochtypes "github.com/Stride-Labs/stride/v16/x/epochs/types" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func (s *KeeperTestSuite) SetupTradeConvertedBalanceCallbackTestCase() BalanceQueryCallbackTestCase { + // Create the connection between Stride and HostChain with the withdrawal account initialized + tradeAccountOwner := types.FormatTradeRouteICAOwner(HostChainId, RewardDenom, HostDenom, types.ICAAccountType_CONVERTER_TRADE) + tradeChannelId, tradePortId := s.CreateICAChannel(tradeAccountOwner) + + route := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + HostDenomOnTradeZone: "ibc/host_on_trade", + + TradeToHostChannelId: "channel-2", + + HostAccount: types.ICAAccount{ + Address: "withdrawal-address", + }, + TradeAccount: types.ICAAccount{ + ChainId: HostChainId, + Address: "trade-address", + ConnectionId: ibctesting.FirstConnectionID, + Type: types.ICAAccountType_CONVERTER_TRADE, + }, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, route) + + // Create and set the epoch tracker for timeouts + timeoutDuration := time.Second * 30 + s.CreateEpochForICATimeout(epochtypes.STRIDE_EPOCH, timeoutDuration) + + // Build query object and serialized query response + balance := sdkmath.NewInt(1_000_000) + callbackDataBz, _ := proto.Marshal(&types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: HostDenom, + }) + query := icqtypes.Query{CallbackData: callbackDataBz} + queryResponse := s.CreateBalanceQueryResponse(balance.Int64(), route.HostDenomOnTradeZone) + + return BalanceQueryCallbackTestCase{ + TradeRoute: route, + Balance: balance, + Response: ICQCallbackArgs{ + Query: query, + CallbackArgs: queryResponse, + }, + ChannelID: tradeChannelId, + PortID: tradePortId, + } +} + +// Verify that a normal TradeConvertedBalanceCallback does fire off the ICA for transfer +func (s *KeeperTestSuite) TestTradeConvertedBalanceCallback_Successful() { + tc := s.SetupTradeConvertedBalanceCallbackTestCase() + + // Check that the ICA was submitted from within the ICQ callback + s.CheckICATxSubmitted(tc.PortID, tc.ChannelID, func() error { + return keeper.TradeConvertedBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + }) +} + +func (s *KeeperTestSuite) TestTradeConvertedBalanceCallback_ZeroBalance() { + tc := s.SetupTradeConvertedBalanceCallbackTestCase() + + // Replace the query response with a coin that has a zero amount + tc.Response.CallbackArgs = s.CreateBalanceQueryResponse(0, tc.TradeRoute.HostDenomOnHostZone) + + // We also remove the connection ID from the trade route so that, IF an ICA was submitted it would fail + // However, it should never go down this route since the balance is 0 + invalidRoute := tc.TradeRoute + invalidRoute.TradeAccount.ConnectionId = "bad-connection" + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, invalidRoute) + + err := keeper.TradeConvertedBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + s.Require().NoError(err) +} + +func (s *KeeperTestSuite) TestTradeConvertedBalanceCallback_InvalidArgs() { + tc := s.SetupTradeConvertedBalanceCallbackTestCase() + + // Submit callback with invalid callback args (so that it can't unmarshal into a coin) + invalidArgs := []byte("random bytes") + + err := keeper.TradeConvertedBalanceCallback(s.App.StakeibcKeeper, s.Ctx, invalidArgs, tc.Response.Query) + s.Require().ErrorContains(err, "unable to determine balance from query response") +} + +func (s *KeeperTestSuite) TestTradeConvertedBalanceCallback_InvalidCallbackData() { + tc := s.SetupTradeConvertedBalanceCallbackTestCase() + + // Update the callback data so that it can't be successfully unmarshalled + invalidQuery := tc.Response.Query + invalidQuery.CallbackData = []byte("random bytes") + + err := keeper.TradeConvertedBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, invalidQuery) + s.Require().ErrorContains(err, "unable to unmarshal trade reward balance callback data") +} + +func (s *KeeperTestSuite) TestTradeConvertedBalanceCallback_TradeRouteNotFound() { + tc := s.SetupTradeConvertedBalanceCallbackTestCase() + + // Update the callback data so that it keys to a trade route that doesn't exist + invalidCallbackDataBz, _ := proto.Marshal(&types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: "different-host-denom", + }) + invalidQuery := tc.Response.Query + invalidQuery.CallbackData = invalidCallbackDataBz + + err := keeper.TradeConvertedBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, invalidQuery) + s.Require().ErrorContains(err, "trade route not found") +} + +func (s *KeeperTestSuite) TestTradeConvertedBalanceCallback_FailedSubmitTx() { + tc := s.SetupTradeConvertedBalanceCallbackTestCase() + + // Remove connectionId from host ICAAccount on TradeRoute so the ICA tx fails + invalidRoute := tc.TradeRoute + invalidRoute.TradeAccount.ConnectionId = "bad-connection" + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, invalidRoute) + + err := keeper.TradeConvertedBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + s.Require().ErrorContains(err, "Failed to submit ICA tx") +} diff --git a/x/stakeibc/keeper/icqcallbacks_trade_reward_balance.go b/x/stakeibc/keeper/icqcallbacks_trade_reward_balance.go new file mode 100644 index 0000000000..4917b61e47 --- /dev/null +++ b/x/stakeibc/keeper/icqcallbacks_trade_reward_balance.go @@ -0,0 +1,66 @@ +package keeper + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/gogoproto/proto" + + icqkeeper "github.com/Stride-Labs/stride/v16/x/interchainquery/keeper" + + "github.com/Stride-Labs/stride/v16/utils" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// TradeRewardBalanceCallback is a callback handler for TradeRewardBalance queries. +// The query response will return the trade ICA account balance for a specific (foreign ibc) denom +// If the balance is non-zero, ICA MsgSends are submitted to initiate a swap on the tradeZone +// +// Note: for now, to get proofs in your ICQs, you need to query the entire store on the host zone! e.g. "store/bank/key" +func TradeRewardBalanceCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) error { + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(query.ChainId, ICQCallbackID_TradeRewardBalance, + "Starting withdrawal reward balance callback, QueryId: %vs, QueryType: %s, Connection: %s", query.Id, query.QueryType, query.ConnectionId)) + + chainId := query.ChainId // should be the tradeZoneId, used in logging + + // Unmarshal the query response args to determine the balance + tradeRewardBalanceAmount, err := icqkeeper.UnmarshalAmountFromBalanceQuery(k.cdc, args) + if err != nil { + return errorsmod.Wrap(err, "unable to determine balance from query response") + } + + // Confirm the balance is greater than zero, or else exit without further action for now + if tradeRewardBalanceAmount.LTE(sdkmath.ZeroInt()) { + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_TradeRewardBalance, + "Not enough reward tokens found in trade ICA, balance: %+v", tradeRewardBalanceAmount)) + return nil + } + + // Unmarshal the callback data containing the tradeRoute we are on + var tradeRouteCallback types.TradeRouteCallback + if err := proto.Unmarshal(query.CallbackData, &tradeRouteCallback); err != nil { + return errorsmod.Wrapf(err, "unable to unmarshal trade reward balance callback data") + } + + // Lookup the trade route from the keys in the callback + tradeRoute, found := k.GetTradeRoute(ctx, tradeRouteCallback.RewardDenom, tradeRouteCallback.HostDenom) + if !found { + return types.ErrTradeRouteNotFound.Wrapf("trade route from %s to %s not found", + tradeRouteCallback.RewardDenom, tradeRouteCallback.HostDenom) + } + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_TradeRewardBalance, + "Query response - Withdrawal Reward Balance: %v %s", tradeRewardBalanceAmount, tradeRoute.RewardDenomOnTradeZone)) + + // Trade all found reward tokens in the trade ICA to the output denom of their trade pool + if err := k.SwapRewardTokens(ctx, tradeRewardBalanceAmount, tradeRoute); err != nil { + return errorsmod.Wrapf(err, "unable to swap reward tokens") + } + + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_TradeRewardBalance, + "Swapping discovered reward tokens %v %s for %s", + tradeRewardBalanceAmount, tradeRoute.RewardDenomOnTradeZone, tradeRoute.HostDenomOnTradeZone)) + + return nil +} diff --git a/x/stakeibc/keeper/icqcallbacks_trade_reward_balance_test.go b/x/stakeibc/keeper/icqcallbacks_trade_reward_balance_test.go new file mode 100644 index 0000000000..9a261bd7cb --- /dev/null +++ b/x/stakeibc/keeper/icqcallbacks_trade_reward_balance_test.go @@ -0,0 +1,154 @@ +package keeper_test + +import ( + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + + epochtypes "github.com/Stride-Labs/stride/v16/x/epochs/types" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func (s *KeeperTestSuite) SetupTradeRewardBalanceCallbackTestCase() BalanceQueryCallbackTestCase { + // Create the connection between Stride and HostChain with the withdrawal account initialized + tradeAccountOwner := types.FormatTradeRouteICAOwner(HostChainId, RewardDenom, HostDenom, types.ICAAccountType_CONVERTER_TRADE) + tradeChannelId, tradePortId := s.CreateICAChannel(tradeAccountOwner) + + route := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + + RewardDenomOnTradeZone: "ibc/reward_on_trade", + HostDenomOnTradeZone: "ibc/host_on_trade", + + TradeAccount: types.ICAAccount{ + ChainId: HostChainId, + Address: "trade-address", + ConnectionId: ibctesting.FirstConnectionID, + Type: types.ICAAccountType_CONVERTER_TRADE, + }, + + TradeConfig: types.TradeConfig{ + PoolId: 100, + SwapPrice: sdk.OneDec(), + MinSwapAmount: sdk.ZeroInt(), + MaxSwapAmount: sdkmath.NewInt(1000), + MaxAllowedSwapLossRate: sdk.MustNewDecFromStr("0.1"), + }, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, route) + + // Create and set the epoch tracker for timeouts + timeoutDuration := time.Second * 30 + s.CreateEpochForICATimeout(epochtypes.HOUR_EPOCH, timeoutDuration) + + // Build query object and serialized query response + balance := sdkmath.NewInt(1_000_000) + callbackDataBz, _ := proto.Marshal(&types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: HostDenom, + }) + query := icqtypes.Query{CallbackData: callbackDataBz} + queryResponse := s.CreateBalanceQueryResponse(balance.Int64(), route.RewardDenomOnTradeZone) + + return BalanceQueryCallbackTestCase{ + TradeRoute: route, + Balance: balance, + Response: ICQCallbackArgs{ + Query: query, + CallbackArgs: queryResponse, + }, + ChannelID: tradeChannelId, + PortID: tradePortId, + } +} + +// Verify that a normal TradeRewardBalanceCallback does fire off the ICA for transfer +func (s *KeeperTestSuite) TestTradeRewardBalanceCallback_Successful() { + tc := s.SetupTradeRewardBalanceCallbackTestCase() + + // Check that the callback triggered the ICA + s.CheckICATxSubmitted(tc.PortID, tc.ChannelID, func() error { + return keeper.TradeRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + }) +} + +// Verify that if the amount returned by the ICQ response is less than the min_swap_amount, no trade happens +func (s *KeeperTestSuite) TestTradeRewardBalanceCallback_SuccessfulNoSwap() { + tc := s.SetupTradeRewardBalanceCallbackTestCase() + + // Set min swap amount to be greater than the transfer amount + route := tc.TradeRoute + route.TradeConfig.MinSwapAmount = tc.Balance.Add(sdkmath.OneInt()) + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, route) + + // ICA inside of TransferRewardTokensHostToTrade should not actually execute because of min_swap_amount + s.CheckICATxNotSubmitted(tc.PortID, tc.ChannelID, func() error { + return keeper.TradeRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + }) +} + +func (s *KeeperTestSuite) TestTradeRewardBalanceCallback_ZeroBalance() { + tc := s.SetupTradeRewardBalanceCallbackTestCase() + + // Replace the query response with a coin that has a zero amount + tc.Response.CallbackArgs = s.CreateBalanceQueryResponse(0, tc.TradeRoute.HostDenomOnTradeZone) + + // Confirm the ICA was not executed + s.CheckICATxNotSubmitted(tc.PortID, tc.ChannelID, func() error { + return keeper.TradeRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + }) +} + +func (s *KeeperTestSuite) TestTradeRewardBalanceCallback_InvalidArgs() { + tc := s.SetupTradeRewardBalanceCallbackTestCase() + + // Submit callback with invalid callback args (so that it can't unmarshal into a coin) + invalidArgs := []byte("random bytes") + + err := keeper.TradeRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, invalidArgs, tc.Response.Query) + s.Require().ErrorContains(err, "unable to determine balance from query response") +} + +func (s *KeeperTestSuite) TestTradeRewardBalanceCallback_InvalidCallbackData() { + tc := s.SetupTradeRewardBalanceCallbackTestCase() + + // Update the callback data so that it can't be successfully unmarshalled + invalidQuery := tc.Response.Query + invalidQuery.CallbackData = []byte("random bytes") + + err := keeper.TradeRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, invalidQuery) + s.Require().ErrorContains(err, "unable to unmarshal trade reward balance callback data") +} + +func (s *KeeperTestSuite) TestTradeRewardBalanceCallback_TradeRouteNotFound() { + tc := s.SetupTradeRewardBalanceCallbackTestCase() + + // Update the callback data so that it keys to a trade route that doesn't exist + invalidCallbackDataBz, _ := proto.Marshal(&types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: "different-host-denom", + }) + invalidQuery := tc.Response.Query + invalidQuery.CallbackData = invalidCallbackDataBz + + err := keeper.TradeRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, invalidQuery) + s.Require().ErrorContains(err, "trade route not found") +} + +func (s *KeeperTestSuite) TestTradeRewardBalanceCallback_FailedSubmitTx() { + tc := s.SetupTradeRewardBalanceCallbackTestCase() + + // Remove connectionId from host ICAAccount on TradeRoute so the ICA tx fails + invalidRoute := tc.TradeRoute + invalidRoute.TradeAccount.ConnectionId = "bad-connection" + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, invalidRoute) + + err := keeper.TradeRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + s.Require().ErrorContains(err, "Failed to submit ICA tx") +} diff --git a/x/stakeibc/keeper/icqcallbacks_withdrawal_balance_test.go b/x/stakeibc/keeper/icqcallbacks_withdrawal_balance_test.go index c9f9ed96b6..9edf885288 100644 --- a/x/stakeibc/keeper/icqcallbacks_withdrawal_balance_test.go +++ b/x/stakeibc/keeper/icqcallbacks_withdrawal_balance_test.go @@ -238,5 +238,5 @@ func (s *KeeperTestSuite) TestWithdrawalBalanceCallback_FailedSubmitTx() { err := keeper.WithdrawalBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.validArgs.callbackArgs, tc.validArgs.query) s.Require().ErrorContains(err, "Failed to SubmitTxs") - s.Require().ErrorContains(err, "invalid connection id, connection-X not found") + s.Require().ErrorContains(err, "connection connection-X not found") } diff --git a/x/stakeibc/keeper/icqcallbacks_withdrawal_reward_balance.go b/x/stakeibc/keeper/icqcallbacks_withdrawal_reward_balance.go new file mode 100644 index 0000000000..f72dcb36ef --- /dev/null +++ b/x/stakeibc/keeper/icqcallbacks_withdrawal_reward_balance.go @@ -0,0 +1,67 @@ +package keeper + +import ( + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + errorsmod "cosmossdk.io/errors" + "github.com/cosmos/gogoproto/proto" + + icqkeeper "github.com/Stride-Labs/stride/v16/x/interchainquery/keeper" + + "github.com/Stride-Labs/stride/v16/utils" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// WithdrawalRewardBalanceCallback is a callback handler for WithdrawalRewardBalance queries. +// The query response will return the withdrawal account balance for a specific (foreign ibc) denom +// If the balance is non-zero, ICA MsgSends are submitted to transfer the discovered balance to the tradeZone +// +// Note: for now, to get proofs in your ICQs, you need to query the entire store on the host zone! e.g. "store/bank/key" +func WithdrawalRewardBalanceCallback(k Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) error { + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(query.ChainId, ICQCallbackID_WithdrawalRewardBalance, + "Starting withdrawal reward balance callback, QueryId: %vs, QueryType: %s, Connection: %s", query.Id, query.QueryType, query.ConnectionId)) + + chainId := query.ChainId + + // Unmarshal the query response args to determine the balance + withdrawalRewardBalanceAmount, err := icqkeeper.UnmarshalAmountFromBalanceQuery(k.cdc, args) + if err != nil { + return errorsmod.Wrap(err, "unable to determine balance from query response") + } + + // Confirm the balance is greater than zero, or else exit early without further action + if withdrawalRewardBalanceAmount.LTE(sdkmath.ZeroInt()) { + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_WithdrawalRewardBalance, + "Not enough reward tokens yet found in withdrawalICA, balance: %v", withdrawalRewardBalanceAmount)) + return nil + } + + // Unmarshal the callback data containing the tradeRoute we are on + var tradeRouteCallback types.TradeRouteCallback + if err := proto.Unmarshal(query.CallbackData, &tradeRouteCallback); err != nil { + return errorsmod.Wrapf(err, "unable to unmarshal trade reward balance callback data") + } + + // Lookup the trade route from the keys in the callback + tradeRoute, found := k.GetTradeRoute(ctx, tradeRouteCallback.RewardDenom, tradeRouteCallback.HostDenom) + if !found { + return types.ErrTradeRouteNotFound.Wrapf("trade route from %s to %s not found", + tradeRouteCallback.RewardDenom, tradeRouteCallback.HostDenom) + } + + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_WithdrawalRewardBalance, + "Query response - Withdrawal Reward Balance: %v %s", withdrawalRewardBalanceAmount, tradeRoute.RewardDenomOnHostZone)) + + // Using ICA commands on the withdrawal address, transfer the found reward tokens from the host zone to the trade zone + if err := k.TransferRewardTokensHostToTrade(ctx, withdrawalRewardBalanceAmount, tradeRoute); err != nil { + return errorsmod.Wrapf(err, "initiating transfer of reward tokens to trade ICA failed") + } + + k.Logger(ctx).Info(utils.LogICQCallbackWithHostZone(chainId, ICQCallbackID_WithdrawalRewardBalance, + "Sending discovered reward tokens %v %s from hostZone to tradeZone", + withdrawalRewardBalanceAmount, tradeRoute.RewardDenomOnHostZone)) + + return nil +} diff --git a/x/stakeibc/keeper/icqcallbacks_withdrawal_reward_balance_test.go b/x/stakeibc/keeper/icqcallbacks_withdrawal_reward_balance_test.go new file mode 100644 index 0000000000..963e940dd5 --- /dev/null +++ b/x/stakeibc/keeper/icqcallbacks_withdrawal_reward_balance_test.go @@ -0,0 +1,163 @@ +package keeper_test + +import ( + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + + epochtypes "github.com/Stride-Labs/stride/v16/x/epochs/types" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// WithdrawalRewardBalanceCallback will trigger TransferRewardTokensHostToTrade +// Therefore we need to setup traderoute fields used in the entire transfer (with pfm) +func (s *KeeperTestSuite) SetupWithdrawalRewardBalanceCallbackTestCase() BalanceQueryCallbackTestCase { + // Create the connection between Stride and HostChain with the withdrawal account initialized + withdrawalAccountOwner := types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_WITHDRAWAL) + withdrawalChannelId, withdrawalPortId := s.CreateICAChannel(withdrawalAccountOwner) + + route := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + RewardDenomOnHostZone: "ibc/reward_on_host", + + HostToRewardChannelId: "channel-2", + RewardToTradeChannelId: "channel-3", + + HostAccount: types.ICAAccount{ + ChainId: HostChainId, + Address: "withdrawal-address", + ConnectionId: ibctesting.FirstConnectionID, + Type: types.ICAAccountType_WITHDRAWAL, + }, + RewardAccount: types.ICAAccount{ + Address: "reward-address", + }, + TradeAccount: types.ICAAccount{ + Address: "trade-address", + }, + + TradeConfig: types.TradeConfig{ + MinSwapAmount: sdk.ZeroInt(), + SwapPrice: sdk.OneDec(), + }, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, route) + + // Create and set the epoch tracker for timeouts + timeoutDuration := time.Second * 30 + s.CreateEpochForICATimeout(epochtypes.STRIDE_EPOCH, timeoutDuration) + + // Build query object and serialized query response + balance := sdkmath.NewInt(1_000_000) + callbackDataBz, _ := proto.Marshal(&types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: HostDenom, + }) + query := icqtypes.Query{CallbackData: callbackDataBz} + queryResponse := s.CreateBalanceQueryResponse(balance.Int64(), route.RewardDenomOnHostZone) + + return BalanceQueryCallbackTestCase{ + TradeRoute: route, + Balance: balance, + Response: ICQCallbackArgs{ + Query: query, + CallbackArgs: queryResponse, + }, + ChannelID: withdrawalChannelId, + PortID: withdrawalPortId, + } +} + +// Verify that a normal WithdrawalRewardBalanceCallback does fire off the ICA for transfer +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceCallback_Successful() { + tc := s.SetupWithdrawalRewardBalanceCallbackTestCase() + + // ICA inside of TransferRewardTokensHostToTrade should execute but it uses submitTXWithoutCallback + // So no need to confirm ICA callback data was stored and no need to confirm callback args values + + // Confirm ICA was submitted by checking that the sequence number incremented + s.CheckICATxSubmitted(tc.PortID, tc.ChannelID, func() error { + return keeper.WithdrawalRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + }) +} + +// Verify that if the amount returned by the ICQ response is less than the min_swap_amount, no transfer happens +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceCallback_SuccessfulNoTransfer() { + tc := s.SetupWithdrawalRewardBalanceCallbackTestCase() + + // Set min swap amount to be greater than the transfer amount + route := tc.TradeRoute + route.TradeConfig.MinSwapAmount = tc.Balance.Add(sdkmath.OneInt()) + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, route) + + // ICA inside of TransferRewardTokensHostToTrade should not actually execute because of min_swap_amount + s.CheckICATxNotSubmitted(tc.PortID, tc.ChannelID, func() error { + return keeper.WithdrawalRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + }) +} + +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceCallback_ZeroBalance() { + tc := s.SetupWithdrawalRewardBalanceCallbackTestCase() + + // Replace the query response with a coin that has a zero amount + tc.Response.CallbackArgs = s.CreateBalanceQueryResponse(0, tc.TradeRoute.RewardDenomOnHostZone) + + // Confirm the transfer ICA was never sent + s.CheckICATxNotSubmitted(tc.PortID, tc.ChannelID, func() error { + return keeper.WithdrawalRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + }) +} + +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceCallback_InvalidArgs() { + tc := s.SetupWithdrawalRewardBalanceCallbackTestCase() + + // Submit callback with invalid callback args (so that it can't unmarshal into a coin) + invalidArgs := []byte("random bytes") + + err := keeper.WithdrawalRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, invalidArgs, tc.Response.Query) + s.Require().ErrorContains(err, "unable to determine balance from query response") +} + +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceCallback_InvalidCallbackData() { + tc := s.SetupWithdrawalRewardBalanceCallbackTestCase() + + // Update the callback data so that it can't be successfully unmarshalled + invalidQuery := tc.Response.Query + invalidQuery.CallbackData = []byte("random bytes") + + err := keeper.WithdrawalRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, invalidQuery) + s.Require().ErrorContains(err, "unable to unmarshal trade reward balance callback data") +} + +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceCallback_TradeRouteNotFound() { + tc := s.SetupWithdrawalRewardBalanceCallbackTestCase() + + // Update the callback data so that it keys to a trade route that doesn't exist + invalidCallbackDataBz, _ := proto.Marshal(&types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: "different-host-denom", + }) + invalidQuery := tc.Response.Query + invalidQuery.CallbackData = invalidCallbackDataBz + + err := keeper.WithdrawalRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, invalidQuery) + s.Require().ErrorContains(err, "trade route not found") +} + +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceCallback_FailedSubmitTx() { + tc := s.SetupWithdrawalRewardBalanceCallbackTestCase() + + // Remove connectionId from host ICAAccount on TradeRoute so the ICA tx fails + invalidRoute := tc.TradeRoute + invalidRoute.HostAccount.ConnectionId = "bad-connection" + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, invalidRoute) + + err := keeper.WithdrawalRewardBalanceCallback(s.App.StakeibcKeeper, s.Ctx, tc.Response.CallbackArgs, tc.Response.Query) + s.Require().ErrorContains(err, "Failed to submit ICA tx") +} diff --git a/x/stakeibc/keeper/keeper.go b/x/stakeibc/keeper/keeper.go index c0c6e4bfc6..036bf934c2 100644 --- a/x/stakeibc/keeper/keeper.go +++ b/x/stakeibc/keeper/keeper.go @@ -5,27 +5,25 @@ import ( errorsmod "cosmossdk.io/errors" "github.com/cometbft/cometbft/libs/log" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/spf13/cast" - "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" - - icqkeeper "github.com/Stride-Labs/stride/v16/x/interchainquery/keeper" - "github.com/Stride-Labs/stride/v16/x/stakeibc/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" icacontrollerkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/keeper" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" ibctmtypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - - storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/spf13/cast" epochstypes "github.com/Stride-Labs/stride/v16/x/epochs/types" icacallbackskeeper "github.com/Stride-Labs/stride/v16/x/icacallbacks/keeper" + icqkeeper "github.com/Stride-Labs/stride/v16/x/interchainquery/keeper" recordsmodulekeeper "github.com/Stride-Labs/stride/v16/x/records/keeper" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" ) type ( @@ -35,6 +33,7 @@ type ( storeKey storetypes.StoreKey memKey storetypes.StoreKey paramstore paramtypes.Subspace + authority string ICAControllerKeeper icacontrollerkeeper.Keeper IBCKeeper ibckeeper.Keeper bankKeeper bankkeeper.Keeper @@ -55,6 +54,7 @@ func NewKeeper( storeKey, memKey storetypes.StoreKey, ps paramtypes.Subspace, + authority string, accountKeeper types.AccountKeeper, bankKeeper bankkeeper.Keeper, icacontrollerkeeper icacontrollerkeeper.Keeper, @@ -77,6 +77,7 @@ func NewKeeper( storeKey: storeKey, memKey: memKey, paramstore: ps, + authority: authority, AccountKeeper: accountKeeper, bankKeeper: bankKeeper, ICAControllerKeeper: icacontrollerkeeper, @@ -106,24 +107,24 @@ func (k *Keeper) SetHooks(gh types.StakeIBCHooks) *Keeper { return k } -func (k Keeper) GetChainID(ctx sdk.Context, connectionID string) (string, error) { - conn, found := k.IBCKeeper.ConnectionKeeper.GetConnection(ctx, connectionID) +// GetAuthority returns the x/stakeibc module's authority. +func (k Keeper) GetAuthority() string { + return k.authority +} + +// Lookup a chain ID from a connection ID by looking up the client state +func (k Keeper) GetChainIdFromConnectionId(ctx sdk.Context, connectionID string) (string, error) { + connection, found := k.IBCKeeper.ConnectionKeeper.GetConnection(ctx, connectionID) if !found { - errMsg := fmt.Sprintf("invalid connection id, %s not found", connectionID) - k.Logger(ctx).Error(errMsg) - return "", fmt.Errorf(errMsg) + return "", errorsmod.Wrapf(connectiontypes.ErrConnectionNotFound, "connection %s not found", connectionID) } - clientState, found := k.IBCKeeper.ClientKeeper.GetClientState(ctx, conn.ClientId) + clientState, found := k.IBCKeeper.ClientKeeper.GetClientState(ctx, connection.ClientId) if !found { - errMsg := fmt.Sprintf("client id %s not found for connection %s", conn.ClientId, connectionID) - k.Logger(ctx).Error(errMsg) - return "", fmt.Errorf(errMsg) + return "", errorsmod.Wrapf(clienttypes.ErrClientNotFound, "client %s not found", connection.ClientId) } client, ok := clientState.(*ibctmtypes.ClientState) if !ok { - errMsg := fmt.Sprintf("invalid client state for client %s on connection %s", conn.ClientId, connectionID) - k.Logger(ctx).Error(errMsg) - return "", fmt.Errorf(errMsg) + return "", types.ErrClientStateNotTendermint } return client.ChainId, nil @@ -152,16 +153,15 @@ func (k Keeper) GetCounterpartyChainId(ctx sdk.Context, connectionID string) (st return counterpartyClient.ChainId, nil } -func (k Keeper) GetConnectionId(ctx sdk.Context, portId string) (string, error) { +// Searches all interchain accounts and finds the connection ID that corresponds with a given port ID +func (k Keeper) GetConnectionIdFromICAPortId(ctx sdk.Context, portId string) (connectionId string, found bool) { icas := k.ICAControllerKeeper.GetAllInterchainAccounts(ctx) for _, ica := range icas { if ica.PortId == portId { - return ica.ConnectionId, nil + return ica.ConnectionId, true } } - errMsg := fmt.Sprintf("portId %s has no associated connectionId", portId) - k.Logger(ctx).Error(errMsg) - return "", fmt.Errorf(errMsg) + return "", false } // helper to get what share of the curr epoch we're through diff --git a/x/stakeibc/keeper/keeper_test.go b/x/stakeibc/keeper/keeper_test.go index c5088e06a2..b615b9fe62 100644 --- a/x/stakeibc/keeper/keeper_test.go +++ b/x/stakeibc/keeper/keeper_test.go @@ -2,16 +2,22 @@ package keeper_test import ( "testing" + "time" sdk "github.com/cosmos/cosmos-sdk/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/stretchr/testify/suite" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/Stride-Labs/stride/v16/app/apptesting" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" "github.com/Stride-Labs/stride/v16/x/stakeibc/types" ) -const ( +var ( Atom = "uatom" StAtom = "stuatom" IbcAtom = "ibc/uatom" @@ -25,11 +31,26 @@ const ( OsmoPrefix = "osmo" OsmoChainId = "OSMO" - ValAddress = "cosmosvaloper1uk4ze0x4nvh4fk0xm4jdud58eqn4yxhrdt795p" - HostICAAddress = "cosmos1gcx4yeplccq9nk6awzmm0gq8jf7yet80qj70tkwy0mz7pg87nepswn2dj8" - LSMTokenBaseDenom = ValAddress + "/32" + HostDenom = "udenom" + RewardDenom = "ureward" + + ValAddress = "cosmosvaloper1uk4ze0x4nvh4fk0xm4jdud58eqn4yxhrdt795p" + StrideICAAddress = "stride1gcx4yeplccq9nk6awzmm0gq8jf7yet80qj70tkwy0mz7pg87nepsen0l38" + HostICAAddress = "cosmos1gcx4yeplccq9nk6awzmm0gq8jf7yet80qj70tkwy0mz7pg87nepswn2dj8" + LSMTokenBaseDenom = ValAddress + "/32" + + DepositAddress = "deposit" + CommunityPoolStakeHoldingAddress = "staking-holding" + CommunityPoolRedeemHoldingAddress = "redeem-holding" + + Authority = authtypes.NewModuleAddress(govtypes.ModuleName).String() ) +type ICQCallbackArgs struct { + Query icqtypes.Query + CallbackArgs []byte +} + type KeeperTestSuite struct { apptesting.AppTestHelper } @@ -51,6 +72,58 @@ func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } +// Helper function to get a host zone and confirm it was found +func (s *KeeperTestSuite) MustGetHostZone(chainId string) types.HostZone { + hostZone, found := s.App.StakeibcKeeper.GetHostZone(s.Ctx, chainId) + s.Require().True(found, "host zone should have been found") + return hostZone +} + +// Helper function to create an epoch tracker that dictates the timeout +func (s *KeeperTestSuite) CreateEpochForICATimeout(epochType string, timeoutDuration time.Duration) { + epochEndTime := uint64(s.Ctx.BlockTime().Add(timeoutDuration).UnixNano()) + epochTracker := types.EpochTracker{ + EpochIdentifier: epochType, + NextEpochStartTime: epochEndTime, + Duration: uint64(timeoutDuration), + } + s.App.StakeibcKeeper.SetEpochTracker(s.Ctx, epochTracker) +} + +// Validates the query object stored after an ICQ submission, using some default testing +// values (e.g. HostChainId, stakeibc module name, etc.), and returning the query +// NOTE: This assumes there was only one submission and grabs the first query from the store +func (s *KeeperTestSuite) ValidateQuerySubmission( + queryType string, + queryData []byte, + callbackId string, + timeoutDuration time.Duration, + timeoutPolicy icqtypes.TimeoutPolicy, +) icqtypes.Query { + // Check that there's only one query + queries := s.App.InterchainqueryKeeper.AllQueries(s.Ctx) + s.Require().Len(queries, 1, "there should have been 1 query submitted") + query := queries[0] + + // Validate the chainId and connectionId + s.Require().Equal(HostChainId, query.ChainId, "query chain ID") + s.Require().Equal(ibctesting.FirstConnectionID, query.ConnectionId, "query connection ID") + s.Require().Equal(types.ModuleName, query.CallbackModule, "query module") + + // Validate the query type and request data + s.Require().Equal(queryType, query.QueryType, "query type") + s.Require().Equal(string(queryData), string(query.RequestData), "query request data") + s.Require().Equal(callbackId, query.CallbackId, "query callback ID") + + // Validate the query timeout + expectedTimeoutTimestamp := s.Ctx.BlockTime().Add(timeoutDuration).UnixNano() + s.Require().Equal(timeoutDuration, query.TimeoutDuration, "query timeout duration") + s.Require().Equal(expectedTimeoutTimestamp, int64(query.TimeoutTimestamp), "query timeout timestamp") + s.Require().Equal(icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, query.TimeoutPolicy, "query timeout policy") + + return query +} + func (s *KeeperTestSuite) TestIsRedemptionRateWithinSafetyBounds() { params := s.App.StakeibcKeeper.GetParams(s.Ctx) params.DefaultMinRedemptionRateThreshold = 75 diff --git a/x/stakeibc/keeper/lsm.go b/x/stakeibc/keeper/lsm.go index 0fc834c9d9..a4f10206af 100644 --- a/x/stakeibc/keeper/lsm.go +++ b/x/stakeibc/keeper/lsm.go @@ -339,7 +339,7 @@ func (k Keeper) DetokenizeAllLSMDeposits(ctx sdk.Context) { // Submit detokenization ICAs for each active host zone for _, hostZone := range k.GetAllActiveHostZone(ctx) { // Get the host zone's delegation ICA portID - delegationICAOwner := types.FormatICAAccountOwner(hostZone.ChainId, types.ICAAccountType_DELEGATION) + delegationICAOwner := types.FormatHostZoneICAOwner(hostZone.ChainId, types.ICAAccountType_DELEGATION) delegationICAPortID, err := icatypes.NewControllerPortID(delegationICAOwner) if err != nil { k.Logger(ctx).Error(fmt.Sprintf("Unable to get delegation port ID for %s: %s", hostZone.ChainId, err)) diff --git a/x/stakeibc/keeper/lsm_test.go b/x/stakeibc/keeper/lsm_test.go index dafc943fa7..9d1f7a5acb 100644 --- a/x/stakeibc/keeper/lsm_test.go +++ b/x/stakeibc/keeper/lsm_test.go @@ -582,7 +582,7 @@ func (s *KeeperTestSuite) TestTransferAllLSMDeposits() { func (s *KeeperTestSuite) TestDetokenizeLSMDeposit() { // Create the delegation ICA - owner := types.FormatICAAccountOwner(HostChainId, types.ICAAccountType_DELEGATION) + owner := types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_DELEGATION) s.CreateICAChannel(owner) portId, err := icatypes.NewControllerPortID(owner) s.Require().NoError(err, "no error expected when formatting portId") @@ -649,7 +649,7 @@ func (s *KeeperTestSuite) TestDetokenizeLSMDeposit() { func (s *KeeperTestSuite) TestDetokenizeAllLSMDeposits() { // Create an open delegation ICA channel - owner := types.FormatICAAccountOwner(HostChainId, types.ICAAccountType_DELEGATION) + owner := types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_DELEGATION) s.CreateICAChannel(owner) portId, err := icatypes.NewControllerPortID(owner) s.Require().NoError(err, "no error expected when formatting portId") diff --git a/x/stakeibc/keeper/msg_server_claim_accrued_staking_rewards_on_host_test.go b/x/stakeibc/keeper/msg_server_claim_accrued_staking_rewards_on_host_test.go new file mode 100644 index 0000000000..f4aa7ac7da --- /dev/null +++ b/x/stakeibc/keeper/msg_server_claim_accrued_staking_rewards_on_host_test.go @@ -0,0 +1,87 @@ +package keeper_test + +import ( + "fmt" + + "cosmossdk.io/math" + _ "github.com/stretchr/testify/suite" + + epochtypes "github.com/Stride-Labs/stride/v16/x/epochs/types" + stakeibckeeper "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" + types "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// constant number of zero delegations +const numZeroDelegations = 37 + +func (s *KeeperTestSuite) ClaimAccruedStakingRewardsOnHost() { + // Create a delegation ICA channel for the ICA submission + owner := types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_DELEGATION) + channelId, portId := s.CreateICAChannel(owner) + + // Create validators + validators := []*types.Validator{} + numberGTClaimRewardsBatchSize := int(50) + for i := 0; i < numberGTClaimRewardsBatchSize; i++ { + + // set most delegations to 5, some to 0 + valDelegation := math.NewInt(5) + if i > (numberGTClaimRewardsBatchSize - numZeroDelegations) { + valDelegation = math.NewInt(0) + } + validators = append(validators, &types.Validator{ + Address: fmt.Sprintf("val-%d", i), + Delegation: valDelegation, + }) + } + + // Create host zone + hostZone := types.HostZone{ + ChainId: HostChainId, + DelegationIcaAddress: "delegation", + WithdrawalIcaAddress: "withdrawal", + Validators: validators, + } + + // Create epoch tracker for ICA timeout + strideEpoch := types.EpochTracker{ + EpochIdentifier: epochtypes.STRIDE_EPOCH, + NextEpochStartTime: uint64(s.Coordinator.CurrentTime.UnixNano() + 30_000_000_000), // used for timeout + } + s.App.StakeibcKeeper.SetEpochTracker(s.Ctx, strideEpoch) + + // Get start sequence number to confirm ICA was set + startSequence, found := s.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(s.Ctx, portId, channelId) + s.Require().True(found) + + // Call claim accrued rewards to submit ICAs + err := s.App.StakeibcKeeper.ClaimAccruedStakingRewardsOnHost(s.Ctx, hostZone) + s.Require().NoError(err, "no error expected when accruing rewards") + + // Confirm sequence number incremented by the number of txs + // where the number of txs is equal: + // (total_validators - validators_with_zero_delegation) / batch_size + batchSize := (numberGTClaimRewardsBatchSize - numZeroDelegations) / stakeibckeeper.ClaimRewardsICABatchSize + expectedEndSequence := startSequence + uint64(batchSize) + actualEndSequence, found := s.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(s.Ctx, portId, channelId) + s.Require().True(found) + s.Require().Equal(expectedEndSequence, actualEndSequence, "sequence number should have incremented") + + // Attempt to call it with a host zone without a delegation ICA address, it should fail + invalidHostZone := hostZone + invalidHostZone.DelegationIcaAddress = "" + err = s.App.StakeibcKeeper.ClaimAccruedStakingRewardsOnHost(s.Ctx, hostZone) + s.Require().ErrorContains(err, "ICA account not found") + + // Attempt to call it with a host zone without a withdrawal ICA address, it should fail + invalidHostZone = hostZone + invalidHostZone.WithdrawalIcaAddress = "" + err = s.App.StakeibcKeeper.ClaimAccruedStakingRewardsOnHost(s.Ctx, hostZone) + s.Require().ErrorContains(err, "ICA account not found") + + // Attempt to call claim with an invalid connection ID on the host zone so the ica fails + invalidHostZone = hostZone + invalidHostZone.ConnectionId = "" + err = s.App.StakeibcKeeper.ClaimAccruedStakingRewardsOnHost(s.Ctx, hostZone) + s.Require().ErrorContains(err, "Failed to SubmitTxs") +} diff --git a/x/stakeibc/keeper/msg_server_create_trade_route.go b/x/stakeibc/keeper/msg_server_create_trade_route.go new file mode 100644 index 0000000000..18ff51477d --- /dev/null +++ b/x/stakeibc/keeper/msg_server_create_trade_route.go @@ -0,0 +1,210 @@ +package keeper + +import ( + "context" + + sdkmath "cosmossdk.io/math" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" +) + +var ( + DefaultMaxAllowedSwapLossRate = "0.05" + DefaultMaxSwapAmount = sdkmath.NewIntWithDecimal(10, 24) // 10e24 +) + +// Gov tx to register a trade route that swaps reward tokens for a different denom +// +// Example proposal: +// +// { +// "title": "Create a new trade route for host chain X", +// "metadata": "Create a new trade route for host chain X", +// "summary": "Create a new trade route for host chain X", +// "messages":[ +// { +// "@type": "/stride.stakeibc.MsgCreateTradeRoute", +// "authority": "stride10d07y265gmmuvt4z0w9aw880jnsr700jefnezl", +// +// "stride_to_host_connection_id": "connection-0", +// "stride_to_reward_connection_id": "connection-1", +// "stride_to_trade_connection_id": "connection-2", +// +// "host_to_reward_transfer_channel_id": "channel-0", +// "reward_to_trade_transfer_channel_id": "channel-1", +// "trade_to_host_transfer_channel_id": "channel-2", +// +// "reward_denom_on_host": "ibc/rewardTokenXXX", +// "reward_denom_on_reward": "rewardToken", +// "reward_denom_on_trade": "ibc/rewardTokenYYY", +// "host_denom_on_trade": "ibc/hostTokenZZZ", +// "host_denom_on_host": "hostToken", +// +// "pool_id": 1, +// "max_allowed_swap_loss_rate": "0.05" +// "min_swap_amount": "10000000", +// "max_swap_amount": "1000000000" +// } +// ], +// "deposit": "2000000000ustrd" +// } +// +// >>> strided tx gov submit-proposal {proposal_file.json} --from wallet +func (ms msgServer) CreateTradeRoute(goCtx context.Context, msg *types.MsgCreateTradeRoute) (*types.MsgCreateTradeRouteResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if ms.authority != msg.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.authority, msg.Authority) + } + + // Validate trade route does not already exist for this denom + _, found := ms.Keeper.GetTradeRoute(ctx, msg.RewardDenomOnReward, msg.HostDenomOnHost) + if found { + return nil, errorsmod.Wrapf(types.ErrTradeRouteAlreadyExists, + "trade route already exists for rewardDenom %s, hostDenom %s", msg.RewardDenomOnReward, msg.HostDenomOnHost) + } + + // Confirm the host chain exists and the withdrawal address has been initialized + hostZone, err := ms.Keeper.GetActiveHostZone(ctx, msg.HostChainId) + if err != nil { + return nil, err + } + if hostZone.WithdrawalIcaAddress == "" { + return nil, errorsmod.Wrapf(types.ErrICAAccountNotFound, "withdrawal account not initialized on host zone") + } + + // Register the new ICA accounts + tradeRouteId := types.GetTradeRouteId(msg.RewardDenomOnReward, msg.HostDenomOnHost) + hostICA := types.ICAAccount{ + ChainId: msg.HostChainId, + Type: types.ICAAccountType_WITHDRAWAL, + ConnectionId: hostZone.ConnectionId, + Address: hostZone.WithdrawalIcaAddress, + } + + unwindConnectionId := msg.StrideToRewardConnectionId + unwindICAType := types.ICAAccountType_CONVERTER_UNWIND + unwindICA, err := ms.Keeper.RegisterTradeRouteICAAccount(ctx, tradeRouteId, unwindConnectionId, unwindICAType) + if err != nil { + return nil, errorsmod.Wrapf(err, "unable to register the unwind ICA account") + } + + tradeConnectionId := msg.StrideToTradeConnectionId + tradeICAType := types.ICAAccountType_CONVERTER_TRADE + tradeICA, err := ms.Keeper.RegisterTradeRouteICAAccount(ctx, tradeRouteId, tradeConnectionId, tradeICAType) + if err != nil { + return nil, errorsmod.Wrapf(err, "unable to register the trade ICA account") + } + + // If a max allowed swap loss is not provided, use the default + maxAllowedSwapLossRate := msg.MaxAllowedSwapLossRate + if maxAllowedSwapLossRate == "" { + maxAllowedSwapLossRate = DefaultMaxAllowedSwapLossRate + } + maxSwapAmount := msg.MaxSwapAmount + if maxSwapAmount.IsZero() { + maxSwapAmount = DefaultMaxSwapAmount + } + + // Create the trade config to specify parameters needed for the swap + tradeConfig := types.TradeConfig{ + PoolId: msg.PoolId, + SwapPrice: sdk.ZeroDec(), // this should only ever be set by ICQ so initialize to blank + PriceUpdateTimestamp: 0, + + MaxAllowedSwapLossRate: sdk.MustNewDecFromStr(maxAllowedSwapLossRate), + MinSwapAmount: msg.MinSwapAmount, + MaxSwapAmount: maxSwapAmount, + } + + // Finally build and store the main trade route + tradeRoute := types.TradeRoute{ + RewardDenomOnHostZone: msg.RewardDenomOnHost, + RewardDenomOnRewardZone: msg.RewardDenomOnReward, + RewardDenomOnTradeZone: msg.RewardDenomOnTrade, + HostDenomOnTradeZone: msg.HostDenomOnTrade, + HostDenomOnHostZone: msg.HostDenomOnHost, + + HostAccount: hostICA, + RewardAccount: unwindICA, + TradeAccount: tradeICA, + + HostToRewardChannelId: msg.HostToRewardTransferChannelId, + RewardToTradeChannelId: msg.RewardToTradeTransferChannelId, + TradeToHostChannelId: msg.TradeToHostTransferChannelId, + + TradeConfig: tradeConfig, + } + + ms.Keeper.SetTradeRoute(ctx, tradeRoute) + + return &types.MsgCreateTradeRouteResponse{}, nil +} + +// Registers a new TradeRoute ICAAccount, given the type +// Stores down the connection and chainId now, and the address upon callback +func (k Keeper) RegisterTradeRouteICAAccount( + ctx sdk.Context, + tradeRouteId string, + connectionId string, + icaAccountType types.ICAAccountType, +) (account types.ICAAccount, err error) { + // Get the chain ID and counterparty connection-id from the connection ID on Stride + chainId, err := k.GetChainIdFromConnectionId(ctx, connectionId) + if err != nil { + return account, err + } + connection, found := k.IBCKeeper.ConnectionKeeper.GetConnection(ctx, connectionId) + if !found { + return account, errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, connectionId) + } + counterpartyConnectionId := connection.Counterparty.ConnectionId + + // Build the appVersion, owner, and portId needed for registration + appVersion := string(icatypes.ModuleCdc.MustMarshalJSON(&icatypes.Metadata{ + Version: icatypes.Version, + ControllerConnectionId: connectionId, + HostConnectionId: counterpartyConnectionId, + Encoding: icatypes.EncodingProtobuf, + TxType: icatypes.TxTypeSDKMultiMsg, + })) + owner := types.FormatTradeRouteICAOwnerFromRouteId(chainId, tradeRouteId, icaAccountType) + portID, err := icatypes.NewControllerPortID(owner) + if err != nil { + return account, err + } + + // Create the associate ICAAccount object + account = types.ICAAccount{ + ChainId: chainId, + Type: icaAccountType, + ConnectionId: connectionId, + } + + // Check if an ICA account has already been created + // (in the event that this trade route was removed and then added back) + // If so, there's no need to register a new ICA + _, channelFound := k.ICAControllerKeeper.GetOpenActiveChannel(ctx, connectionId, portID) + icaAddress, icaFound := k.ICAControllerKeeper.GetInterchainAccountAddress(ctx, connectionId, portID) + if channelFound && icaFound { + account = types.ICAAccount{ + ChainId: chainId, + Type: icaAccountType, + ConnectionId: connectionId, + Address: icaAddress, + } + return account, nil + } + + // Otherwise, if there's no account already, register a new one + if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, connectionId, owner, appVersion); err != nil { + return account, err + } + + return account, nil +} diff --git a/x/stakeibc/keeper/msg_server_create_trade_route_test.go b/x/stakeibc/keeper/msg_server_create_trade_route_test.go new file mode 100644 index 0000000000..3f28e02921 --- /dev/null +++ b/x/stakeibc/keeper/msg_server_create_trade_route_test.go @@ -0,0 +1,229 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func (s *KeeperTestSuite) SetupTestCreateTradeRoute() (msg types.MsgCreateTradeRoute, expectedTradeRoute types.TradeRoute) { + rewardChainId := "reward-0" + tradeChainId := "trade-0" + + hostConnectionId := "connection-0" + rewardConnectionId := "connection-1" + tradeConnectionId := "connection-2" + + hostToRewardChannelId := "channel-100" + rewardToTradeChannelId := "channel-200" + tradeToHostChannelId := "channel-300" + + rewardDenomOnHost := "ibc/reward-on-host" + rewardDenomOnReward := RewardDenom + rewardDenomOnTrade := "ibc/reward-on-trade" + hostDenomOnTrade := "ibc/host-on-trade" + hostDenomOnHost := HostDenom + + withdrawalAddress := "withdrawal-address" + unwindAddress := "unwind-address" + + poolId := uint64(100) + maxAllowedSwapLossRate := "0.05" + minSwapAmount := sdkmath.NewInt(100) + maxSwapAmount := sdkmath.NewInt(1_000) + + // Mock out connections for the reward an trade chain so that an ICA registration can be submitted + s.MockClientAndConnection(rewardChainId, "07-tendermint-0", rewardConnectionId) + s.MockClientAndConnection(tradeChainId, "07-tendermint-1", tradeConnectionId) + + // Register an exisiting ICA account for the unwind ICA to test that + // existing accounts are re-used + owner := types.FormatTradeRouteICAOwner(rewardChainId, RewardDenom, HostDenom, types.ICAAccountType_CONVERTER_UNWIND) + s.MockICAChannel(rewardConnectionId, "channel-0", owner, unwindAddress) + + // Create a host zone with an exisiting withdrawal address + hostZone := types.HostZone{ + ChainId: HostChainId, + ConnectionId: hostConnectionId, + WithdrawalIcaAddress: withdrawalAddress, + } + s.App.StakeibcKeeper.SetHostZone(s.Ctx, hostZone) + + // Define a valid message given the parameters above + msg = types.MsgCreateTradeRoute{ + Authority: Authority, + HostChainId: HostChainId, + + StrideToRewardConnectionId: rewardConnectionId, + StrideToTradeConnectionId: tradeConnectionId, + + HostToRewardTransferChannelId: hostToRewardChannelId, + RewardToTradeTransferChannelId: rewardToTradeChannelId, + TradeToHostTransferChannelId: tradeToHostChannelId, + + RewardDenomOnHost: rewardDenomOnHost, + RewardDenomOnReward: rewardDenomOnReward, + RewardDenomOnTrade: rewardDenomOnTrade, + HostDenomOnTrade: hostDenomOnTrade, + HostDenomOnHost: hostDenomOnHost, + + PoolId: poolId, + MaxAllowedSwapLossRate: maxAllowedSwapLossRate, + MinSwapAmount: minSwapAmount, + MaxSwapAmount: maxSwapAmount, + } + + // Build out the expected trade route given the above + expectedTradeRoute = types.TradeRoute{ + RewardDenomOnHostZone: rewardDenomOnHost, + RewardDenomOnRewardZone: rewardDenomOnReward, + RewardDenomOnTradeZone: rewardDenomOnTrade, + HostDenomOnTradeZone: hostDenomOnTrade, + HostDenomOnHostZone: hostDenomOnHost, + + HostAccount: types.ICAAccount{ + ChainId: HostChainId, + Type: types.ICAAccountType_WITHDRAWAL, + ConnectionId: hostConnectionId, + Address: withdrawalAddress, + }, + RewardAccount: types.ICAAccount{ + ChainId: rewardChainId, + Type: types.ICAAccountType_CONVERTER_UNWIND, + ConnectionId: rewardConnectionId, + Address: unwindAddress, + }, + TradeAccount: types.ICAAccount{ + ChainId: tradeChainId, + Type: types.ICAAccountType_CONVERTER_TRADE, + ConnectionId: tradeConnectionId, + }, + + HostToRewardChannelId: hostToRewardChannelId, + RewardToTradeChannelId: rewardToTradeChannelId, + TradeToHostChannelId: tradeToHostChannelId, + + TradeConfig: types.TradeConfig{ + PoolId: poolId, + SwapPrice: sdk.ZeroDec(), + PriceUpdateTimestamp: 0, + + MaxAllowedSwapLossRate: sdk.MustNewDecFromStr(maxAllowedSwapLossRate), + MinSwapAmount: minSwapAmount, + MaxSwapAmount: maxSwapAmount, + }, + } + + return msg, expectedTradeRoute +} + +// Helper function to create a trade route and check the created route matched expectations +func (s *KeeperTestSuite) submitCreateTradeRouteAndValidate(msg types.MsgCreateTradeRoute, expectedRoute types.TradeRoute) { + _, err := s.GetMsgServer().CreateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().NoError(err, "no error expected when creating trade route") + + actualRoute, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, msg.RewardDenomOnReward, msg.HostDenomOnHost) + s.Require().True(found, "trade route should have been created") + s.Require().Equal(expectedRoute, actualRoute, "trade route") +} + +// Tests a successful trade route creation +func (s *KeeperTestSuite) TestCreateTradeRoute_Success() { + msg, expectedRoute := s.SetupTestCreateTradeRoute() + s.submitCreateTradeRouteAndValidate(msg, expectedRoute) +} + +// Tests creating a trade route that uses the default pool config values +func (s *KeeperTestSuite) TestCreateTradeRoute_Success_DefaultPoolConfig() { + msg, expectedRoute := s.SetupTestCreateTradeRoute() + + // Update the message and remove some trade config parameters + // so that the defaults are used + msg.MaxSwapAmount = sdk.ZeroInt() + msg.MaxAllowedSwapLossRate = "" + + expectedRoute.TradeConfig.MaxAllowedSwapLossRate = sdk.MustNewDecFromStr(keeper.DefaultMaxAllowedSwapLossRate) + expectedRoute.TradeConfig.MaxSwapAmount = keeper.DefaultMaxSwapAmount + + s.submitCreateTradeRouteAndValidate(msg, expectedRoute) +} + +// Tests trying to create a route from an invalid authority +func (s *KeeperTestSuite) TestCreateTradeRoute_Failure_Authority() { + msg, _ := s.SetupTestCreateTradeRoute() + + msg.Authority = "not-gov-address" + + _, err := s.GetMsgServer().CreateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "invalid authority") +} + +// Tests creating a duplicate trade route +func (s *KeeperTestSuite) TestCreateTradeRoute_Failure_DuplicateTradeRoute() { + msg, _ := s.SetupTestCreateTradeRoute() + + // Store down a trade route so the tx hits a duplicate trade route error + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + }) + + _, err := s.GetMsgServer().CreateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "Trade route already exists") +} + +// Tests creating a trade route when the host zone or withdrawal address does not exist +func (s *KeeperTestSuite) TestCreateTradeRoute_Failure_HostZoneNotRegistered() { + msg, _ := s.SetupTestCreateTradeRoute() + + // Remove the host zone withdrawal address and confirm it fails + invalidHostZone := s.MustGetHostZone(HostChainId) + invalidHostZone.WithdrawalIcaAddress = "" + s.App.StakeibcKeeper.SetHostZone(s.Ctx, invalidHostZone) + + _, err := s.GetMsgServer().CreateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "withdrawal account not initialized on host zone") + + // Remove the host zone completely and check that that also fails + s.App.StakeibcKeeper.RemoveHostZone(s.Ctx, HostChainId) + + _, err = s.GetMsgServer().CreateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "host zone not found") +} + +// Tests creating a trade route where the ICA channels cannot be created +// because the ICA connections do not exist +func (s *KeeperTestSuite) TestCreateTradeRoute_Failure_ConnectionNotFound() { + // Test with non-existent reward connection + msg, _ := s.SetupTestCreateTradeRoute() + msg.StrideToRewardConnectionId = "connection-X" + + // Remove the host zone completely and check that that also fails + _, err := s.GetMsgServer().CreateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "unable to register the unwind ICA account: connection connection-X not found") + + // Setup again, but this time use a non-existent trade connection + msg, _ = s.SetupTestCreateTradeRoute() + msg.StrideToTradeConnectionId = "connection-Y" + + _, err = s.GetMsgServer().CreateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "unable to register the trade ICA account: connection connection-Y not found") +} + +// Tests creating a trade route where the ICA registration step fails +func (s *KeeperTestSuite) TestCreateTradeRoute_Failure_UnableToRegisterICA() { + msg, expectedRoute := s.SetupTestCreateTradeRoute() + + // Disable ICA middleware for the trade channel so the ICA fails + tradeAccount := expectedRoute.TradeAccount + tradeOwner := types.FormatTradeRouteICAOwner(tradeAccount.ChainId, RewardDenom, HostDenom, types.ICAAccountType_CONVERTER_TRADE) + tradePortId, _ := icatypes.NewControllerPortID(tradeOwner) + s.App.ICAControllerKeeper.SetMiddlewareDisabled(s.Ctx, tradePortId, tradeAccount.ConnectionId) + + _, err := s.GetMsgServer().CreateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "unable to register the trade ICA account") +} diff --git a/x/stakeibc/keeper/msg_server_delete_trade_route.go b/x/stakeibc/keeper/msg_server_delete_trade_route.go new file mode 100644 index 0000000000..9a899c6891 --- /dev/null +++ b/x/stakeibc/keeper/msg_server_delete_trade_route.go @@ -0,0 +1,49 @@ +package keeper + +import ( + "context" + + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Gov tx to remove a trade route +// +// Example proposal: +// +// { +// "title": "Remove a new trade route for host chain X", +// "metadata": "Remove a new trade route for host chain X", +// "summary": "Remove a new trade route for host chain X", +// "messages":[ +// { +// "@type": "/stride.stakeibc.MsgDeleteTradeRoute", +// "authority": "stride10d07y265gmmuvt4z0w9aw880jnsr700jefnezl", +// "reward_denom": "rewardToken", +// "host_denom": "hostToken +// } +// ], +// "deposit": "2000000000ustrd" +// } +// +// >>> strided tx gov submit-proposal {proposal_file.json} --from wallet +func (ms msgServer) DeleteTradeRoute(goCtx context.Context, msg *types.MsgDeleteTradeRoute) (*types.MsgDeleteTradeRouteResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if ms.authority != msg.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.authority, msg.Authority) + } + + _, found := ms.Keeper.GetTradeRoute(ctx, msg.RewardDenom, msg.HostDenom) + if !found { + return nil, errorsmod.Wrapf(types.ErrTradeRouteNotFound, + "no trade route for rewardDenom %s and hostDenom %s", msg.RewardDenom, msg.HostDenom) + } + + ms.Keeper.RemoveTradeRoute(ctx, msg.RewardDenom, msg.HostDenom) + + return &types.MsgDeleteTradeRouteResponse{}, nil +} diff --git a/x/stakeibc/keeper/msg_server_delete_trade_route_test.go b/x/stakeibc/keeper/msg_server_delete_trade_route_test.go new file mode 100644 index 0000000000..7b7c5ceccc --- /dev/null +++ b/x/stakeibc/keeper/msg_server_delete_trade_route_test.go @@ -0,0 +1,44 @@ +package keeper_test + +import ( + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (s *KeeperTestSuite) TestDeleteTradeRoute() { + initialRoute := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, initialRoute) + + msg := types.MsgDeleteTradeRoute{ + Authority: Authority, + RewardDenom: RewardDenom, + HostDenom: HostDenom, + } + + // Confirm the route is present before attepmting to delete was deleted + _, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, RewardDenom, HostDenom) + s.Require().True(found, "trade route should have been found before delete message") + + // Delete the trade route + _, err := s.GetMsgServer().DeleteTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().NoError(err, "no error expected when deleting trade route") + + // Confirm it was deleted + _, found = s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, RewardDenom, HostDenom) + s.Require().False(found, "trade route should have been deleted") + + // Attempt to delete it again, it should fail since it doesn't exist + _, err = s.GetMsgServer().DeleteTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().ErrorContains(err, "trade route not found") + + // Attempt to delete with the wrong authority - it should fail + invalidMsg := msg + invalidMsg.Authority = "not-gov-address" + + _, err = s.GetMsgServer().DeleteTradeRoute(sdk.WrapSDKContext(s.Ctx), &invalidMsg) + s.Require().ErrorContains(err, "invalid authority") +} diff --git a/x/stakeibc/keeper/msg_server_register_host_zone.go b/x/stakeibc/keeper/msg_server_register_host_zone.go index 9d25bbf2b9..36d812156e 100644 --- a/x/stakeibc/keeper/msg_server_register_host_zone.go +++ b/x/stakeibc/keeper/msg_server_register_host_zone.go @@ -29,7 +29,7 @@ func (k msgServer) RegisterHostZone(goCtx context.Context, msg *types.MsgRegiste counterpartyConnection := connectionEnd.Counterparty // Get chain id from connection - chainId, err := k.GetChainID(ctx, msg.ConnectionId) + chainId, err := k.GetChainIdFromConnectionId(ctx, msg.ConnectionId) if err != nil { errMsg := fmt.Sprintf("unable to obtain chain id from connection %s, err: %s", msg.ConnectionId, err.Error()) k.Logger(ctx).Error(errMsg) @@ -128,7 +128,7 @@ func (k msgServer) RegisterHostZone(goCtx context.Context, msg *types.MsgRegiste // generate delegate account // NOTE: in the future, if we implement proxy governance, we'll need many more delegate accounts - delegateAccount := types.FormatICAAccountOwner(chainId, types.ICAAccountType_DELEGATION) + delegateAccount := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_DELEGATION) if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, zone.ConnectionId, delegateAccount, appVersion); err != nil { errMsg := fmt.Sprintf("unable to register delegation account, err: %s", err.Error()) k.Logger(ctx).Error(errMsg) @@ -136,7 +136,7 @@ func (k msgServer) RegisterHostZone(goCtx context.Context, msg *types.MsgRegiste } // generate fee account - feeAccount := types.FormatICAAccountOwner(chainId, types.ICAAccountType_FEE) + feeAccount := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_FEE) if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, zone.ConnectionId, feeAccount, appVersion); err != nil { errMsg := fmt.Sprintf("unable to register fee account, err: %s", err.Error()) k.Logger(ctx).Error(errMsg) @@ -144,7 +144,7 @@ func (k msgServer) RegisterHostZone(goCtx context.Context, msg *types.MsgRegiste } // generate withdrawal account - withdrawalAccount := types.FormatICAAccountOwner(chainId, types.ICAAccountType_WITHDRAWAL) + withdrawalAccount := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_WITHDRAWAL) if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, zone.ConnectionId, withdrawalAccount, appVersion); err != nil { errMsg := fmt.Sprintf("unable to register withdrawal account, err: %s", err.Error()) k.Logger(ctx).Error(errMsg) @@ -152,7 +152,7 @@ func (k msgServer) RegisterHostZone(goCtx context.Context, msg *types.MsgRegiste } // generate redemption account - redemptionAccount := types.FormatICAAccountOwner(chainId, types.ICAAccountType_REDEMPTION) + redemptionAccount := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_REDEMPTION) if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, zone.ConnectionId, redemptionAccount, appVersion); err != nil { errMsg := fmt.Sprintf("unable to register redemption account, err: %s", err.Error()) k.Logger(ctx).Error(errMsg) @@ -160,13 +160,13 @@ func (k msgServer) RegisterHostZone(goCtx context.Context, msg *types.MsgRegiste } // create community pool deposit account - communityPoolDepositAccount := types.FormatICAAccountOwner(chainId, types.ICAAccountType_COMMUNITY_POOL_DEPOSIT) + communityPoolDepositAccount := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_COMMUNITY_POOL_DEPOSIT) if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, zone.ConnectionId, communityPoolDepositAccount, appVersion); err != nil { return nil, errorsmod.Wrapf(types.ErrFailedToRegisterHostZone, "failed to register community pool deposit ICA") } // create community pool return account - communityPoolReturnAccount := types.FormatICAAccountOwner(chainId, types.ICAAccountType_COMMUNITY_POOL_RETURN) + communityPoolReturnAccount := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_COMMUNITY_POOL_RETURN) if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, zone.ConnectionId, communityPoolReturnAccount, appVersion); err != nil { return nil, errorsmod.Wrapf(types.ErrFailedToRegisterHostZone, "failed to register community pool return ICA") } diff --git a/x/stakeibc/keeper/msg_server_restore_interchain_account.go b/x/stakeibc/keeper/msg_server_restore_interchain_account.go index 4b981a2ee1..77736a9e30 100644 --- a/x/stakeibc/keeper/msg_server_restore_interchain_account.go +++ b/x/stakeibc/keeper/msg_server_restore_interchain_account.go @@ -6,8 +6,8 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" + connectiontypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types" recordtypes "github.com/Stride-Labs/stride/v16/x/records/types" "github.com/Stride-Labs/stride/v16/x/stakeibc/types" @@ -16,52 +16,43 @@ import ( func (k msgServer) RestoreInterchainAccount(goCtx context.Context, msg *types.MsgRestoreInterchainAccount) (*types.MsgRestoreInterchainAccountResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - // Confirm host zone exists - hostZone, found := k.GetHostZone(ctx, msg.ChainId) - if !found { - k.Logger(ctx).Error(fmt.Sprintf("Host Zone not found: %s", msg.ChainId)) - return nil, types.ErrInvalidHostZone - } - // Get ConnectionEnd (for counterparty connection) - connectionEnd, found := k.IBCKeeper.ConnectionKeeper.GetConnection(ctx, hostZone.ConnectionId) + connectionEnd, found := k.IBCKeeper.ConnectionKeeper.GetConnection(ctx, msg.ConnectionId) if !found { - errMsg := fmt.Sprintf("invalid connection id from host %s, %s not found", msg.ChainId, hostZone.ConnectionId) - k.Logger(ctx).Error(errMsg) - return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, errMsg) + return nil, errorsmod.Wrapf(connectiontypes.ErrConnectionNotFound, "connection %s not found", msg.ConnectionId) } counterpartyConnection := connectionEnd.Counterparty // only allow restoring an account if it already exists - owner := types.FormatICAAccountOwner(msg.ChainId, msg.AccountType) - portID, err := icatypes.NewControllerPortID(owner) + portID, err := icatypes.NewControllerPortID(msg.AccountOwner) if err != nil { - errMsg := fmt.Sprintf("could not create portID for ICA controller account address: %s", owner) - k.Logger(ctx).Error(errMsg) return nil, err } - _, exists := k.ICAControllerKeeper.GetInterchainAccountAddress(ctx, hostZone.ConnectionId, portID) + _, exists := k.ICAControllerKeeper.GetInterchainAccountAddress(ctx, msg.ConnectionId, portID) if !exists { - errMsg := fmt.Sprintf("ICA controller account address not found: %s", owner) - k.Logger(ctx).Error(errMsg) - return nil, errorsmod.Wrapf(types.ErrInvalidInterchainAccountAddress, errMsg) + return nil, errorsmod.Wrapf(types.ErrInvalidInterchainAccountAddress, + "ICA controller account address not found: %s", msg.AccountOwner) } appVersion := string(icatypes.ModuleCdc.MustMarshalJSON(&icatypes.Metadata{ Version: icatypes.Version, - ControllerConnectionId: hostZone.ConnectionId, + ControllerConnectionId: msg.ConnectionId, HostConnectionId: counterpartyConnection.ConnectionId, Encoding: icatypes.EncodingProtobuf, TxType: icatypes.TxTypeSDKMultiMsg, })) - if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, hostZone.ConnectionId, owner, appVersion); err != nil { - k.Logger(ctx).Error(fmt.Sprintf("unable to register %s account : %s", msg.AccountType.String(), err)) - return nil, err + if err := k.ICAControllerKeeper.RegisterInterchainAccount(ctx, msg.ConnectionId, msg.AccountOwner, appVersion); err != nil { + return nil, errorsmod.Wrapf(err, "unable to register account for owner %s", msg.AccountOwner) } // If we're restoring a delegation account, we also have to reset record state - if msg.AccountType == types.ICAAccountType_DELEGATION { + if msg.AccountOwner == types.FormatHostZoneICAOwner(msg.ChainId, types.ICAAccountType_DELEGATION) { + hostZone, found := k.GetHostZone(ctx, msg.ChainId) + if !found { + return nil, types.ErrHostZoneNotFound.Wrapf("delegation ICA supplied, but no associated host zone") + } + // revert DELEGATION_IN_PROGRESS records for the closed ICA channel (so that they can be staked) depositRecords := k.RecordsKeeper.GetAllDepositRecord(ctx) for _, depositRecord := range depositRecords { diff --git a/x/stakeibc/keeper/msg_server_restore_interchain_account_test.go b/x/stakeibc/keeper/msg_server_restore_interchain_account_test.go index 05b4f0a485..44da10bb51 100644 --- a/x/stakeibc/keeper/msg_server_restore_interchain_account_test.go +++ b/x/stakeibc/keeper/msg_server_restore_interchain_account_test.go @@ -165,9 +165,10 @@ func (s *KeeperTestSuite) SetupRestoreInterchainAccount(createDelegationICAChann } defaultMsg := types.MsgRestoreInterchainAccount{ - Creator: "creatoraddress", - ChainId: HostChainId, - AccountType: types.ICAAccountType_DELEGATION, + Creator: "creatoraddress", + ChainId: HostChainId, + ConnectionId: ibctesting.FirstConnectionID, + AccountOwner: types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_DELEGATION), } return RestoreInterchainAccountTestCase{ @@ -279,31 +280,34 @@ func (s *KeeperTestSuite) TestRestoreInterchainAccount_InvalidConnectionId() { tc := s.SetupRestoreInterchainAccount(false) // Update the connectionId on the host zone so that it doesn't exist - hostZone, found := s.App.StakeibcKeeper.GetHostZone(s.Ctx, tc.validMsg.ChainId) - s.Require().True(found) - hostZone.ConnectionId = "fake_connection" - s.App.StakeibcKeeper.SetHostZone(s.Ctx, hostZone) + invalidMsg := tc.validMsg + invalidMsg.ConnectionId = "fake_connection" - _, err := s.GetMsgServer().RestoreInterchainAccount(sdk.WrapSDKContext(s.Ctx), &tc.validMsg) - s.Require().EqualError(err, "invalid connection id from host GAIA, fake_connection not found: invalid request") + _, err := s.GetMsgServer().RestoreInterchainAccount(sdk.WrapSDKContext(s.Ctx), &invalidMsg) + s.Require().ErrorContains(err, "connection fake_connection not found") } func (s *KeeperTestSuite) TestRestoreInterchainAccount_CannotRestoreNonExistentAcct() { tc := s.SetupRestoreInterchainAccount(false) + + // Attempt to restore an account that does not exist msg := tc.validMsg - msg.AccountType = types.ICAAccountType_WITHDRAWAL + msg.AccountOwner = types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_WITHDRAWAL) _, err := s.GetMsgServer().RestoreInterchainAccount(sdk.WrapSDKContext(s.Ctx), &msg) s.Require().ErrorContains(err, "ICA controller account address not found: GAIA.WITHDRAWAL") } -func (s *KeeperTestSuite) TestRestoreInterchainAccount_FailsForIncorrectHostZone() { - tc := s.SetupRestoreInterchainAccount(false) - invalidMsg := tc.validMsg - invalidMsg.ChainId = "incorrectchainid" +func (s *KeeperTestSuite) TestRestoreInterchainAccount_HostZoneNotFound() { + tc := s.SetupRestoreInterchainAccount(true) + s.closeICAChannel(tc.delegationPortID, tc.delegationChannelID) - _, err := s.GetMsgServer().RestoreInterchainAccount(sdk.WrapSDKContext(s.Ctx), &invalidMsg) - s.Require().ErrorContains(err, "host zone not registered") + // Delete the host zone so the lookup fails + // (this check only runs for the delegation channel) + s.App.StakeibcKeeper.RemoveHostZone(s.Ctx, HostChainId) + + _, err := s.GetMsgServer().RestoreInterchainAccount(sdk.WrapSDKContext(s.Ctx), &tc.validMsg) + s.Require().ErrorContains(err, "delegation ICA supplied, but no associated host zone") } func (s *KeeperTestSuite) TestRestoreInterchainAccount_RevertDepositRecords_Failure() { @@ -333,7 +337,7 @@ func (s *KeeperTestSuite) TestRestoreInterchainAccount_NoRecordChange_Success() // Restore the channel msg := tc.validMsg - msg.AccountType = types.ICAAccountType_WITHDRAWAL + msg.AccountOwner = types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_WITHDRAWAL) s.restoreChannelAndVerifySuccess(msg, portID, channelID) // Verify the record status' were NOT reverted diff --git a/x/stakeibc/keeper/msg_server_submit_tx.go b/x/stakeibc/keeper/msg_server_submit_tx.go index 8bb88b83f8..51e02eaf7c 100644 --- a/x/stakeibc/keeper/msg_server_submit_tx.go +++ b/x/stakeibc/keeper/msg_server_submit_tx.go @@ -31,16 +31,21 @@ import ( icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types" ) +const ( + ClaimRewardsICABatchSize = 10 +) + func (k Keeper) DelegateOnHost(ctx sdk.Context, hostZone types.HostZone, amt sdk.Coin, depositRecord recordstypes.DepositRecord) error { + // TODO: Remove this block and use connection-id from host zone // the relevant ICA is the delegate account - owner := types.FormatICAAccountOwner(hostZone.ChainId, types.ICAAccountType_DELEGATION) + owner := types.FormatHostZoneICAOwner(hostZone.ChainId, types.ICAAccountType_DELEGATION) portID, err := icatypes.NewControllerPortID(owner) if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "%s has no associated portId", owner) } - connectionId, err := k.GetConnectionId(ctx, portID) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidChainID, "%s has no associated connection", portID) + connectionId, found := k.GetConnectionIdFromICAPortId(ctx, portID) + if !found { + return errorsmod.Wrapf(types.ErrICAAccountNotFound, "unable to find ICA connection Id for port %s", portID) } // Fetch the relevant ICA @@ -114,15 +119,16 @@ func (k Keeper) DelegateOnHost(ctx sdk.Context, hostZone types.HostZone, amt sdk } func (k Keeper) SetWithdrawalAddressOnHost(ctx sdk.Context, hostZone types.HostZone) error { + // TODO: Remove this block and use connection-id from host zone // The relevant ICA is the delegate account - owner := types.FormatICAAccountOwner(hostZone.ChainId, types.ICAAccountType_DELEGATION) + owner := types.FormatHostZoneICAOwner(hostZone.ChainId, types.ICAAccountType_DELEGATION) portID, err := icatypes.NewControllerPortID(owner) if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "%s has no associated portId", owner) } - connectionId, err := k.GetConnectionId(ctx, portID) - if err != nil { - return errorsmod.Wrapf(sdkerrors.ErrInvalidChainID, "%s has no associated connection", portID) + connectionId, found := k.GetConnectionIdFromICAPortId(ctx, portID) + if !found { + return errorsmod.Wrapf(types.ErrICAAccountNotFound, "unable to find ICA connection Id for port %s", portID) } // Fetch the relevant ICA @@ -153,6 +159,52 @@ func (k Keeper) SetWithdrawalAddressOnHost(ctx sdk.Context, hostZone types.HostZ return nil } +func (k Keeper) ClaimAccruedStakingRewardsOnHost(ctx sdk.Context, hostZone types.HostZone) error { + // Fetch the relevant ICA + if hostZone.DelegationIcaAddress == "" { + return errorsmod.Wrapf(types.ErrICAAccountNotFound, "delegation ICA not found for %s", hostZone.ChainId) + } + if hostZone.WithdrawalIcaAddress == "" { + return errorsmod.Wrapf(types.ErrICAAccountNotFound, "withdrawal ICA not found for %s", hostZone.ChainId) + } + k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "Withdrawal Address: %s, Delegator Address: %s", + hostZone.WithdrawalIcaAddress, hostZone.DelegationIcaAddress)) + + validators := hostZone.Validators + + // Build multi-message transaction to withdraw rewards from each validator + // batching txs into groups of ClaimRewardsICABatchSize messages, to ensure they will fit in the host's blockSize + for start := 0; start < len(validators); start += ClaimRewardsICABatchSize { + end := start + ClaimRewardsICABatchSize + if end > len(validators) { + end = len(validators) + } + batch := validators[start:end] + msgs := []proto.Message{} + // Iterate over the items within the batch + for _, val := range batch { + // skip withdrawing rewards + if val.Delegation.IsZero() { + continue + } + msg := &distributiontypes.MsgWithdrawDelegatorReward{ + DelegatorAddress: hostZone.DelegationIcaAddress, + ValidatorAddress: val.Address, + } + msgs = append(msgs, msg) + } + + if len(msgs) > 0 { + _, err := k.SubmitTxsStrideEpoch(ctx, hostZone.ConnectionId, msgs, types.ICAAccountType_DELEGATION, "", nil) + if err != nil { + return errorsmod.Wrapf(err, "Failed to SubmitTxs for %s, %s, %s", hostZone.ConnectionId, hostZone.ChainId, msgs) + } + } + } + + return nil +} + // Submits an ICQ for the withdrawal account balance func (k Keeper) UpdateWithdrawalBalance(ctx sdk.Context, hostZone types.HostZone) error { k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "Submitting ICQ for withdrawal account balance")) @@ -259,6 +311,7 @@ func (k Keeper) SubmitTxsEpoch( } // SubmitTxs submits an ICA transaction containing multiple messages +// This function only supports messages to ICAs on the host zone func (k Keeper) SubmitTxs( ctx sdk.Context, connectionId string, @@ -268,11 +321,11 @@ func (k Keeper) SubmitTxs( callbackId string, callbackArgs []byte, ) (uint64, error) { - chainId, err := k.GetChainID(ctx, connectionId) + chainId, err := k.GetChainIdFromConnectionId(ctx, connectionId) if err != nil { return 0, err } - owner := types.FormatICAAccountOwner(chainId, icaAccountType) + owner := types.FormatHostZoneICAOwner(chainId, icaAccountType) portID, err := icatypes.NewControllerPortID(owner) if err != nil { return 0, err @@ -327,6 +380,35 @@ func (k Keeper) SubmitTxs( return sequence, nil } +func (k Keeper) SubmitICATxWithoutCallback( + ctx sdk.Context, + connectionId string, + icaAccountOwner string, + msgs []proto.Message, + timeoutTimestamp uint64, +) error { + // Serialize tx messages + txBz, err := icatypes.SerializeCosmosTx(k.cdc, msgs) + if err != nil { + return errorsmod.Wrapf(err, "unable to serialize cosmos transaction") + } + packetData := icatypes.InterchainAccountPacketData{ + Type: icatypes.EXECUTE_TX, + Data: txBz, + } + relativeTimeoutOffset := timeoutTimestamp - uint64(ctx.BlockTime().UnixNano()) + + // Submit ICA, no need to store callback data or register callback function + icaMsgServer := icacontrollerkeeper.NewMsgServerImpl(&k.ICAControllerKeeper) + msgSendTx := icacontrollertypes.NewMsgSendTx(icaAccountOwner, connectionId, relativeTimeoutOffset, packetData) + _, err = icaMsgServer.SendTx(ctx, msgSendTx) + if err != nil { + return errorsmod.Wrapf(err, "unable to send ICA tx") + } + + return nil +} + func (k Keeper) GetLightClientHeightSafely(ctx sdk.Context, connectionID string) (uint64, error) { // get light client's latest height conn, found := k.IBCKeeper.ConnectionKeeper.GetConnection(ctx, connectionID) diff --git a/x/stakeibc/keeper/msg_server_update_trade_route.go b/x/stakeibc/keeper/msg_server_update_trade_route.go new file mode 100644 index 0000000000..9c23fd65cd --- /dev/null +++ b/x/stakeibc/keeper/msg_server_update_trade_route.go @@ -0,0 +1,73 @@ +package keeper + +import ( + "context" + + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Gov tx to update the trade config of a trade route +// +// Example proposal: +// +// { +// "title": "Update a the trade config for host chain X", +// "metadata": "Update a the trade config for host chain X", +// "summary": "Update a the trade config for host chain X", +// "messages":[ +// { +// "@type": "/stride.stakeibc.MsgUpdateTradeRoute", +// "authority": "stride10d07y265gmmuvt4z0w9aw880jnsr700jefnezl", +// +// "pool_id": 1, +// "max_allowed_swap_loss_rate": "0.05", +// "min_swap_amount": "10000000", +// "max_swap_amount": "1000000000" +// } +// ], +// "deposit": "2000000000ustrd" +// } +// +// >>> strided tx gov submit-proposal {proposal_file.json} --from wallet +func (ms msgServer) UpdateTradeRoute(goCtx context.Context, msg *types.MsgUpdateTradeRoute) (*types.MsgUpdateTradeRouteResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if ms.authority != msg.Authority { + return nil, errorsmod.Wrapf(govtypes.ErrInvalidSigner, "invalid authority; expected %s, got %s", ms.authority, msg.Authority) + } + + route, found := ms.Keeper.GetTradeRoute(ctx, msg.RewardDenom, msg.HostDenom) + if !found { + return nil, errorsmod.Wrapf(types.ErrTradeRouteNotFound, + "no trade route for rewardDenom %s and hostDenom %s", msg.RewardDenom, msg.HostDenom) + } + + maxAllowedSwapLossRate := msg.MaxAllowedSwapLossRate + if maxAllowedSwapLossRate == "" { + maxAllowedSwapLossRate = DefaultMaxAllowedSwapLossRate + } + maxSwapAmount := msg.MaxSwapAmount + if maxSwapAmount.IsZero() { + maxSwapAmount = DefaultMaxSwapAmount + } + + updatedConfig := types.TradeConfig{ + PoolId: msg.PoolId, + + SwapPrice: sdk.ZeroDec(), + PriceUpdateTimestamp: 0, + + MaxAllowedSwapLossRate: sdk.MustNewDecFromStr(maxAllowedSwapLossRate), + MinSwapAmount: msg.MinSwapAmount, + MaxSwapAmount: maxSwapAmount, + } + + route.TradeConfig = updatedConfig + ms.Keeper.SetTradeRoute(ctx, route) + + return &types.MsgUpdateTradeRouteResponse{}, nil +} diff --git a/x/stakeibc/keeper/msg_server_update_trade_route_test.go b/x/stakeibc/keeper/msg_server_update_trade_route_test.go new file mode 100644 index 0000000000..75c666023c --- /dev/null +++ b/x/stakeibc/keeper/msg_server_update_trade_route_test.go @@ -0,0 +1,86 @@ +package keeper_test + +import ( + sdkmath "cosmossdk.io/math" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// Helper function to update a trade route and check the updated route matched expectations +func (s *KeeperTestSuite) submitUpdateTradeRouteAndValidate(msg types.MsgUpdateTradeRoute, expectedRoute types.TradeRoute) { + _, err := s.GetMsgServer().UpdateTradeRoute(sdk.WrapSDKContext(s.Ctx), &msg) + s.Require().NoError(err, "no error expected when updating trade route") + + actualRoute, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, RewardDenom, HostDenom) + s.Require().True(found, "trade route should have been updated") + s.Require().Equal(expectedRoute, actualRoute, "trade route") +} + +func (s *KeeperTestSuite) TestUpdateTradeRoute() { + poolId := uint64(100) + maxAllowedSwapLossRate := "0.05" + minSwapAmount := sdkmath.NewInt(100) + maxSwapAmount := sdkmath.NewInt(1_000) + + // Create a trade route with no parameters + initialRoute := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, initialRoute) + + // Define a valid message given the parameters above + msg := types.MsgUpdateTradeRoute{ + Authority: Authority, + + RewardDenom: RewardDenom, + HostDenom: HostDenom, + + PoolId: poolId, + MaxAllowedSwapLossRate: maxAllowedSwapLossRate, + MinSwapAmount: minSwapAmount, + MaxSwapAmount: maxSwapAmount, + } + + // Build out the expected trade route given the above + expectedRoute := initialRoute + expectedRoute.TradeConfig = types.TradeConfig{ + PoolId: poolId, + SwapPrice: sdk.ZeroDec(), + PriceUpdateTimestamp: 0, + + MaxAllowedSwapLossRate: sdk.MustNewDecFromStr(maxAllowedSwapLossRate), + MinSwapAmount: minSwapAmount, + MaxSwapAmount: maxSwapAmount, + } + + // Update the route and confirm the changes persisted + s.submitUpdateTradeRouteAndValidate(msg, expectedRoute) + + // Update it again, this time using default args + defaultMsg := msg + defaultMsg.MaxAllowedSwapLossRate = "" + defaultMsg.MaxSwapAmount = sdkmath.ZeroInt() + + expectedRoute.TradeConfig.MaxAllowedSwapLossRate = sdk.MustNewDecFromStr(keeper.DefaultMaxAllowedSwapLossRate) + expectedRoute.TradeConfig.MaxSwapAmount = keeper.DefaultMaxSwapAmount + + s.submitUpdateTradeRouteAndValidate(defaultMsg, expectedRoute) + + // Test that an error is thrown if the correct authority is not specified + invalidMsg := msg + invalidMsg.Authority = "not-gov-address" + + _, err := s.GetMsgServer().UpdateTradeRoute(sdk.WrapSDKContext(s.Ctx), &invalidMsg) + s.Require().ErrorContains(err, "invalid authority") + + // Test that an error is thrown if the route doesn't exist + invalidMsg = msg + invalidMsg.RewardDenom = "invalid-reward-denom" + + _, err = s.GetMsgServer().UpdateTradeRoute(sdk.WrapSDKContext(s.Ctx), &invalidMsg) + s.Require().ErrorContains(err, "trade route not found") +} diff --git a/x/stakeibc/keeper/reward_converter.go b/x/stakeibc/keeper/reward_converter.go new file mode 100644 index 0000000000..3d4e76898b --- /dev/null +++ b/x/stakeibc/keeper/reward_converter.go @@ -0,0 +1,558 @@ +package keeper + +import ( + "encoding/json" + "fmt" + "time" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" + bankTypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/gogoproto/proto" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + + "github.com/Stride-Labs/stride/v16/utils" + epochstypes "github.com/Stride-Labs/stride/v16/x/epochs/types" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// JSON Memo for PFM transfers +type PacketForwardMetadata struct { + Forward *ForwardMetadata `json:"forward"` +} +type ForwardMetadata struct { + Receiver string `json:"receiver"` + Port string `json:"port"` + Channel string `json:"channel"` + Timeout string `json:"timeout"` + Retries int64 `json:"retries"` +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// The goal of this code is to allow certain reward token types to be automatically traded into other types +// This happens before the rest of the staking, allocation, distribution etc. would continue as normal +// +// Reward tokens are any special denoms which are paid out in the withdrawal address +// Most host zones inflate their tokens and their native token is what appears in the withdrawal ICA +// The following allows for chains to use foreign denoms as revenue, which can be traded to any other denom first +// +// 1. Epochly check the reward denom balance in the withdrawal address +// on callback, send all this reward denom from withdrawl ICA to trade ICA on the trade zone (OSMOSIS) +// 2. Epochly check the reward denom balance in trade ICA +// on callback, trade all reward denom for host denom defined by pool and routes in params +// 3. Epochly check the host denom balance in trade ICA +// on callback, transfer these host denom tokens from trade ICA to withdrawal ICA on original host zone +// +// Normal staking flow continues from there. So the host denom tokens will land on the original host zone +// and the normal staking and distribution flow will continue from there. +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Builds a PFM transfer message to send reward tokens from the host zone, +// through the reward zone (to unwind) and finally to the trade zone +func (k Keeper) BuildHostToTradeTransferMsg( + ctx sdk.Context, + amount sdkmath.Int, + route types.TradeRoute, +) (msg transfertypes.MsgTransfer, err error) { + // Get the epoch tracker to determine the timeouts + strideEpochTracker, found := k.GetEpochTracker(ctx, epochstypes.STRIDE_EPOCH) + if !found { + return msg, errorsmod.Wrapf(types.ErrEpochNotFound, epochstypes.STRIDE_EPOCH) + } + + // Timeout the first transfer halfway through the epoch, and the second transfer at the end of the epoch + // The pfm transfer requires a duration instead of a timestamp for the timeout, so we just use half the epoch length + halfEpochDuration := strideEpochTracker.Duration / 2 + transfer1TimeoutTimestamp := uint64(strideEpochTracker.NextEpochStartTime - halfEpochDuration) // unix nano + transfer2TimeoutDuration := fmt.Sprintf("%ds", halfEpochDuration/1e9) // string in seconds + + startingDenom := route.RewardDenomOnHostZone + sendTokens := sdk.NewCoin(startingDenom, amount) + + withdrawlIcaAddress := route.HostAccount.Address + unwindIcaAddress := route.RewardAccount.Address + tradeIcaAddress := route.TradeAccount.Address + + // Validate ICAs were registered + if withdrawlIcaAddress == "" { + return msg, errorsmod.Wrapf(types.ErrICAAccountNotFound, "no host account found for %s", route.Description()) + } + if unwindIcaAddress == "" { + return msg, errorsmod.Wrapf(types.ErrICAAccountNotFound, "no reward account found for %s", route.Description()) + } + if tradeIcaAddress == "" { + return msg, errorsmod.Wrapf(types.ErrICAAccountNotFound, "no trade account found for %s", route.Description()) + } + + // Build the pfm memo to specify the forwarding logic + // This transfer channel id is a channel on the reward Zone for transfers to the trade zone + // (not to be confused with a transfer channel on Stride or the Host Zone) + memo := PacketForwardMetadata{ + Forward: &ForwardMetadata{ + Receiver: tradeIcaAddress, + Port: transfertypes.PortID, + Channel: route.RewardToTradeChannelId, + Timeout: transfer2TimeoutDuration, + Retries: 0, + }, + } + memoJSON, err := json.Marshal(memo) + if err != nil { + return msg, err + } + + msg = transfertypes.MsgTransfer{ + SourcePort: transfertypes.PortID, + SourceChannel: route.HostToRewardChannelId, // channel on hostZone for transfers to rewardZone + Token: sendTokens, + Sender: withdrawlIcaAddress, + Receiver: unwindIcaAddress, // could be "pfm" or a real address depending on version + TimeoutTimestamp: transfer1TimeoutTimestamp, + Memo: string(memoJSON), + } + + return msg, nil +} + +// ICA tx will kick off transfering the reward tokens from the hostZone withdrawl ICA to the tradeZone trade ICA +// This will be two hops to unwind the ibc denom through the rewardZone using pfm in the transfer memo +func (k Keeper) TransferRewardTokensHostToTrade(ctx sdk.Context, amount sdkmath.Int, route types.TradeRoute) error { + // If the min swap amount was not set it would be ZeroInt, if positive we need to compare to the amount given + // then if the min swap amount is greater than the current amount, do nothing this epoch to avoid small transfers + // Particularly important for the PFM hop if the reward chain has frictional transfer fees (like noble chain) + if route.TradeConfig.MinSwapAmount.GT(amount) { + return nil + } + + // Similarly, if there's no price on the trade route yet, don't initiate the transfer because + // we know the swap will not be submitted + if route.TradeConfig.SwapPrice.IsZero() { + return nil + } + + // Build the PFM transfer message from host to trade zone + msg, err := k.BuildHostToTradeTransferMsg(ctx, amount, route) + if err != nil { + return err + } + msgs := []proto.Message{&msg} + + hostZoneId := route.HostAccount.ChainId + rewardZoneId := route.RewardAccount.ChainId + tradeZoneId := route.TradeAccount.ChainId + k.Logger(ctx).Info(utils.LogWithHostZone(hostZoneId, + "Preparing MsgTransfer of %+v from %s to %s to %s", msg.Token, hostZoneId, rewardZoneId, tradeZoneId)) + + // Send the ICA tx to kick off transfer from hostZone through rewardZone to the tradeZone (no callbacks) + hostAccount := route.HostAccount + withdrawalOwner := types.FormatHostZoneICAOwner(hostAccount.ChainId, hostAccount.Type) + err = k.SubmitICATxWithoutCallback(ctx, hostAccount.ConnectionId, withdrawalOwner, msgs, msg.TimeoutTimestamp) + if err != nil { + return errorsmod.Wrapf(err, "Failed to submit ICA tx, Messages: %+v", msgs) + } + + return nil +} + +// ICA tx to kick off transfering the converted tokens back from tradeZone to the hostZone withdrawal ICA +func (k Keeper) TransferConvertedTokensTradeToHost(ctx sdk.Context, amount sdkmath.Int, route types.TradeRoute) error { + // Timeout for ica tx and the transfer msgs is at end of epoch + strideEpochTracker, found := k.GetEpochTracker(ctx, epochstypes.STRIDE_EPOCH) + if !found { + return errorsmod.Wrapf(types.ErrEpochNotFound, epochstypes.STRIDE_EPOCH) + } + timeout := uint64(strideEpochTracker.NextEpochStartTime) + + convertedDenom := route.HostDenomOnTradeZone + sendTokens := sdk.NewCoin(convertedDenom, amount) + + // Validate ICAs were registered + tradeIcaAddress := route.TradeAccount.Address + withdrawlIcaAddress := route.HostAccount.Address + if withdrawlIcaAddress == "" { + return errorsmod.Wrapf(types.ErrICAAccountNotFound, "no host account found for %s", route.Description()) + } + if tradeIcaAddress == "" { + return errorsmod.Wrapf(types.ErrICAAccountNotFound, "no trade account found for %s", route.Description()) + } + + var msgs []proto.Message + msgs = append(msgs, &transfertypes.MsgTransfer{ + SourcePort: transfertypes.PortID, + SourceChannel: route.TradeToHostChannelId, // channel on tradeZone for transfers to hostZone + Token: sendTokens, + Sender: tradeIcaAddress, + Receiver: withdrawlIcaAddress, + TimeoutTimestamp: timeout, + Memo: "", + }) + + hostZoneId := route.HostAccount.ChainId + tradeZoneId := route.TradeAccount.ChainId + k.Logger(ctx).Info(utils.LogWithHostZone(hostZoneId, + "Preparing MsgTransfer of %+v from %s to %s", sendTokens, tradeZoneId, hostZoneId)) + + // Send the ICA tx to kick off transfer from hostZone through rewardZone to the tradeZone (no callbacks) + tradeAccount := route.TradeAccount + tradeOwner := types.FormatTradeRouteICAOwnerFromRouteId(tradeAccount.ChainId, route.GetRouteId(), tradeAccount.Type) + err := k.SubmitICATxWithoutCallback(ctx, tradeAccount.ConnectionId, tradeOwner, msgs, timeout) + if err != nil { + return errorsmod.Wrapf(err, "Failed to submit ICA tx, Messages: %+v", msgs) + } + + return nil +} + +// Builds the Osmosis swap message to trade reward tokens for host tokens +// Depending on min and max swap amounts set in the route, it is possible not the full amount given will swap +// The minimum amount of tokens that can come out of the trade is calculated using a price from the pool +func (k Keeper) BuildSwapMsg(rewardAmount sdkmath.Int, route types.TradeRoute) (msg types.MsgSwapExactAmountIn, err error) { + // Validate the trade ICA was registered + tradeIcaAddress := route.TradeAccount.Address + if tradeIcaAddress == "" { + return msg, errorsmod.Wrapf(types.ErrICAAccountNotFound, "no trade account found for %s", route.Description()) + } + + // If the max swap amount was not set it would be ZeroInt, if positive we need to compare to the amount given + // then if max swap amount is LTE to amount full swap is possible so amount is fine, otherwise set amount to max + tradeConfig := route.TradeConfig + if tradeConfig.MaxSwapAmount.IsPositive() && rewardAmount.GT(tradeConfig.MaxSwapAmount) { + rewardAmount = tradeConfig.MaxSwapAmount + } + + // See if pool swap price has been set to a valid ratio + // The only time this should not be set is right after the pool is added, + // before an ICQ has been submitted for the price + if tradeConfig.SwapPrice.IsZero() { + return msg, fmt.Errorf("Price not found for pool %d", tradeConfig.PoolId) + } + + // If there is a valid price, use it to set a floor for the acceptable minimum output tokens + // minOut is the minimum number of HostDenom tokens we must receive or the swap will fail + // + // To calculate minOut, we first convert the rewardAmount into units of HostDenom, + // and then we multiply by (1 - MaxAllowedSwapLossRate) + // + // The price on the trade route represents the ratio of host denom to reward denom + // So, to convert from units of RewardTokens to units of HostTokens, + // we multiply the reward amount by the price: + // AmountInHost = AmountInReward * SwapPrice + rewardAmountConverted := sdk.NewDecFromInt(rewardAmount).Mul(tradeConfig.SwapPrice) + minOutPercentage := sdk.OneDec().Sub(tradeConfig.MaxAllowedSwapLossRate) + minOut := rewardAmountConverted.Mul(minOutPercentage).TruncateInt() + + tradeTokens := sdk.NewCoin(route.RewardDenomOnTradeZone, rewardAmount) + + // Prepare Osmosis GAMM module MsgSwapExactAmountIn from the trade account to perform the trade + // If we want to generalize in the future, write swap message generation funcs for each DEX type, + // decide which msg generation function to call based on check of which tradeZone was passed in + routes := []types.SwapAmountInRoute{{ + PoolId: tradeConfig.PoolId, + TokenOutDenom: route.HostDenomOnTradeZone, + }} + msg = types.MsgSwapExactAmountIn{ + Sender: tradeIcaAddress, + Routes: routes, + TokenIn: tradeTokens, + TokenOutMinAmount: minOut, + } + + return msg, nil +} + +// Trade reward tokens in the Trade ICA for the host denom tokens using ICA remote tx on trade zone +// The amount represents the total amount of the reward token in the trade ICA found by the calling ICQ +func (k Keeper) SwapRewardTokens(ctx sdk.Context, rewardAmount sdkmath.Int, route types.TradeRoute) error { + // If the min swap amount was not set it would be ZeroInt, if positive we need to compare to the amount given + // then if the min swap amount is greater than the current amount, do nothing this epoch to avoid small swaps + tradeConfig := route.TradeConfig + if tradeConfig.MinSwapAmount.IsPositive() && tradeConfig.MinSwapAmount.GT(rewardAmount) { + return nil + } + + // Build the Osmosis swap message to convert reward tokens to host tokens + msg, err := k.BuildSwapMsg(rewardAmount, route) + if err != nil { + return err + } + msgs := []proto.Message{&msg} + + tradeAccount := route.TradeAccount + k.Logger(ctx).Info(utils.LogWithHostZone(tradeAccount.ChainId, + "Preparing MsgSwapExactAmountIn of %+v from the trade account", msg.TokenIn)) + + // Timeout the swap at the end of the epoch + strideEpochTracker, found := k.GetEpochTracker(ctx, epochstypes.HOUR_EPOCH) + if !found { + return errorsmod.Wrapf(types.ErrEpochNotFound, epochstypes.HOUR_EPOCH) + } + timeout := uint64(strideEpochTracker.NextEpochStartTime) + + // Send the ICA tx to perform the swap on the tradeZone + tradeOwner := types.FormatTradeRouteICAOwnerFromRouteId(tradeAccount.ChainId, route.GetRouteId(), tradeAccount.Type) + err = k.SubmitICATxWithoutCallback(ctx, tradeAccount.ConnectionId, tradeOwner, msgs, timeout) + if err != nil { + return errorsmod.Wrapf(err, "Failed to submit ICA tx for the swap, Messages: %v", msgs) + } + + return nil +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ICQ calls for remote ICA balances +// There is a single trade zone (hardcoded as Osmosis for now but maybe additional DEXes allowed in the future) +// We have to initialize a single hostZone object for the trade zone once in initialization and +// then it can be used in all these calls +/////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Kick off ICQ for the reward denom balance in the withdrawal address +func (k Keeper) WithdrawalRewardBalanceQuery(ctx sdk.Context, route types.TradeRoute) error { + withdrawalAccount := route.HostAccount + k.Logger(ctx).Info(utils.LogWithHostZone(withdrawalAccount.ChainId, "Submitting ICQ for reward denom in withdrawal account")) + + // Encode the withdrawal account address for the query request + // The query request consists of the withdrawal account address and reward denom + _, withdrawalAddressBz, err := bech32.DecodeAndConvert(withdrawalAccount.Address) + if err != nil { + return errorsmod.Wrapf(err, "invalid withdrawal account address (%s), could not decode", withdrawalAccount.Address) + } + queryData := append(bankTypes.CreateAccountBalancesPrefix(withdrawalAddressBz), []byte(route.RewardDenomOnHostZone)...) + + // Timeout the query halfway through the epoch (since that's when the first transfer + // in the pfm sequence will timeout) + strideEpochTracker, found := k.GetEpochTracker(ctx, epochstypes.STRIDE_EPOCH) + if !found { + return errorsmod.Wrapf(types.ErrEpochNotFound, epochstypes.STRIDE_EPOCH) + } + timeoutDuration := time.Duration(strideEpochTracker.Duration) / 2 + + // We need the trade route keys in the callback to look up the tradeRoute struct + callbackData := types.TradeRouteCallback{ + RewardDenom: route.RewardDenomOnRewardZone, + HostDenom: route.HostDenomOnHostZone, + } + callbackDataBz, err := proto.Marshal(&callbackData) + if err != nil { + return errorsmod.Wrapf(err, "unable to marshal TradeRoute callback data") + } + + // Submit the ICQ for the withdrawal account balance + query := icqtypes.Query{ + ChainId: withdrawalAccount.ChainId, + ConnectionId: withdrawalAccount.ConnectionId, + QueryType: icqtypes.BANK_STORE_QUERY_WITH_PROOF, + RequestData: queryData, + CallbackModule: types.ModuleName, + CallbackId: ICQCallbackID_WithdrawalRewardBalance, + CallbackData: callbackDataBz, + TimeoutDuration: timeoutDuration, + TimeoutPolicy: icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, + } + if err := k.InterchainQueryKeeper.SubmitICQRequest(ctx, query, false); err != nil { + return err + } + + return nil +} + +// Kick off ICQ for how many reward tokens are in the trade ICA associated with this host zone +func (k Keeper) TradeRewardBalanceQuery(ctx sdk.Context, route types.TradeRoute) error { + tradeAccount := route.TradeAccount + k.Logger(ctx).Info(utils.LogWithHostZone(tradeAccount.ChainId, "Submitting ICQ for reward denom in trade ICA account")) + + // Encode the trade account address for the query request + // The query request consists of the trade account address and reward denom + // keep in mind this ICA address actually exists on trade zone but is associated with trades performed for host zone + _, tradeAddressBz, err := bech32.DecodeAndConvert(tradeAccount.Address) + if err != nil { + return errorsmod.Wrapf(err, "invalid trade account address (%s), could not decode", tradeAccount.Address) + } + queryData := append(bankTypes.CreateAccountBalancesPrefix(tradeAddressBz), []byte(route.RewardDenomOnTradeZone)...) + + // Timeout query at end of epoch + hourEpochTracker, found := k.GetEpochTracker(ctx, epochstypes.HOUR_EPOCH) + if !found { + return errorsmod.Wrapf(types.ErrEpochNotFound, epochstypes.HOUR_EPOCH) + } + timeout := time.Unix(0, int64(hourEpochTracker.NextEpochStartTime)) + timeoutDuration := timeout.Sub(ctx.BlockTime()) + + // We need the trade route keys in the callback to look up the tradeRoute struct + callbackData := types.TradeRouteCallback{ + RewardDenom: route.RewardDenomOnRewardZone, + HostDenom: route.HostDenomOnHostZone, + } + callbackDataBz, err := proto.Marshal(&callbackData) + if err != nil { + return errorsmod.Wrapf(err, "unable to marshal TradeRewardBalanceQuery callback data") + } + + // Submit the ICQ for the withdrawal account balance + query := icqtypes.Query{ + ChainId: tradeAccount.ChainId, + ConnectionId: tradeAccount.ConnectionId, // query needs to go to the trade zone, not the host zone + QueryType: icqtypes.BANK_STORE_QUERY_WITH_PROOF, + RequestData: queryData, + CallbackModule: types.ModuleName, + CallbackId: ICQCallbackID_TradeRewardBalance, + CallbackData: callbackDataBz, + TimeoutDuration: timeoutDuration, + TimeoutPolicy: icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, + } + if err := k.InterchainQueryKeeper.SubmitICQRequest(ctx, query, false); err != nil { + return err + } + + return nil +} + +// Kick off ICQ for how many converted tokens are in the trade ICA associated with this host zone +func (k Keeper) TradeConvertedBalanceQuery(ctx sdk.Context, route types.TradeRoute) error { + tradeAccount := route.TradeAccount + k.Logger(ctx).Info(utils.LogWithHostZone(tradeAccount.ChainId, "Submitting ICQ for converted denom in trade ICA account")) + + // Encode the trade account address for the query request + // The query request consists of the trade account address and converted denom + // keep in mind this ICA address actually exists on trade zone but is associated with trades performed for host zone + _, tradeAddressBz, err := bech32.DecodeAndConvert(tradeAccount.Address) + if err != nil { + return errorsmod.Wrapf(err, "invalid trade account address (%s), could not decode", tradeAccount.Address) + } + queryData := append(bankTypes.CreateAccountBalancesPrefix(tradeAddressBz), []byte(route.HostDenomOnTradeZone)...) + + // Timeout query at end of epoch + strideEpochTracker, found := k.GetEpochTracker(ctx, epochstypes.STRIDE_EPOCH) + if !found { + return errorsmod.Wrapf(types.ErrEpochNotFound, epochstypes.STRIDE_EPOCH) + } + timeout := time.Unix(0, int64(strideEpochTracker.NextEpochStartTime)) + timeoutDuration := timeout.Sub(ctx.BlockTime()) + + // We need the trade route keys in the callback to look up the tradeRoute struct + callbackData := types.TradeRouteCallback{ + RewardDenom: route.RewardDenomOnRewardZone, + HostDenom: route.HostDenomOnHostZone, + } + callbackDataBz, err := proto.Marshal(&callbackData) + if err != nil { + return errorsmod.Wrapf(err, "unable to marshal trade route as callback data") + } + + // Submit the ICQ for the withdrawal account balance + query := icqtypes.Query{ + ChainId: tradeAccount.ChainId, + ConnectionId: tradeAccount.ConnectionId, // query needs to go to the trade zone, not the host zone + QueryType: icqtypes.BANK_STORE_QUERY_WITH_PROOF, + RequestData: queryData, + CallbackModule: types.ModuleName, + CallbackId: ICQCallbackID_TradeConvertedBalance, + CallbackData: callbackDataBz, + TimeoutDuration: timeoutDuration, + TimeoutPolicy: icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, + } + if err := k.InterchainQueryKeeper.SubmitICQRequest(ctx, query, false); err != nil { + return err + } + + return nil +} + +// Kick off ICQ for the spot price on the pool given the input and output denoms implied by the given TradeRoute +// the callback for this query is responsible for updating the returned spot price on the keeper data +func (k Keeper) PoolPriceQuery(ctx sdk.Context, route types.TradeRoute) error { + tradeAccount := route.TradeAccount + k.Logger(ctx).Info(utils.LogWithHostZone(tradeAccount.ChainId, "Submitting ICQ for spot price in this pool")) + + // Build query request data which consists of the TWAP store key built from each denom + queryData := icqtypes.FormatOsmosisMostRecentTWAPKey( + route.TradeConfig.PoolId, + route.RewardDenomOnTradeZone, + route.HostDenomOnTradeZone, + ) + + // Timeout query at end of epoch + hourEpochTracker, found := k.GetEpochTracker(ctx, epochstypes.HOUR_EPOCH) + if !found { + return errorsmod.Wrapf(types.ErrEpochNotFound, epochstypes.HOUR_EPOCH) + } + timeout := time.Unix(0, int64(hourEpochTracker.NextEpochStartTime)) + timeoutDuration := timeout.Sub(ctx.BlockTime()) + + // We need the trade route keys in the callback to look up the tradeRoute struct + callbackData := types.TradeRouteCallback{ + RewardDenom: route.RewardDenomOnRewardZone, + HostDenom: route.HostDenomOnHostZone, + } + callbackDataBz, err := proto.Marshal(&callbackData) + if err != nil { + return errorsmod.Wrapf(err, "unable to marshal TradeRewardBalanceQuery callback data") + } + + // Submit the ICQ for the trade pool spot price query + query := icqtypes.Query{ + ChainId: tradeAccount.ChainId, + ConnectionId: tradeAccount.ConnectionId, // query needs to go to the trade zone, not the host zone + QueryType: icqtypes.TWAP_STORE_QUERY_WITH_PROOF, + RequestData: queryData, + CallbackModule: types.ModuleName, + CallbackId: ICQCallbackID_PoolPrice, + CallbackData: callbackDataBz, + TimeoutDuration: timeoutDuration, + TimeoutPolicy: icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, + } + if err := k.InterchainQueryKeeper.SubmitICQRequest(ctx, query, false); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Error querying pool spot price, error: %s", err.Error())) + return err + } + + return nil +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// The current design assumes foreign reward tokens start and end in the hostZone withdrawal address +// Step 1: transfer reward tokens to trade chain +// Step 2: perform the swap with as many reward tokens as possible +// Step 3: return the swapped tokens to the withdrawal ICA on hostZone +// Independently there is an ICQ to get the swap price and update it in the keeper state +// +// Because the swaps have limits on how many tokens can be used to avoid slippage, +// the swaps and price checks happen on a faster (hourly) cadence than the transfers (stride epochly) +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Helper function to be run stride epochly, kicks off queries on specific denoms on route +func (k Keeper) TransferAllRewardTokens(ctx sdk.Context) { + for _, route := range k.GetAllTradeRoutes(ctx) { + // Step 1: ICQ reward balance on hostZone, transfer funds with unwinding to trade chain + if err := k.WithdrawalRewardBalanceQuery(ctx, route); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to submit query for reward balance in withdrawal ICA: %s", err)) + } + // Step 3: ICQ converted tokens in trade ICA, transfer funds back to hostZone withdrawal ICA + if err := k.TradeConvertedBalanceQuery(ctx, route); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to submit query for converted balance in trade ICA: %s", err)) + } + } +} + +// Helper function to be run hourly, kicks off query which will kick off actual swaps to happen +func (k Keeper) SwapAllRewardTokens(ctx sdk.Context) { + for _, route := range k.GetAllTradeRoutes(ctx) { + // Step 2: ICQ reward balance in trade ICA, swap tokens according to limiting rules + if err := k.TradeRewardBalanceQuery(ctx, route); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to submit query for reward balance in trade ICA: %s", err)) + } + } +} + +// Helper function to be run hourly, kicks off query to get and update the swap price in keeper data +func (k Keeper) UpdateAllSwapPrices(ctx sdk.Context) { + for _, route := range k.GetAllTradeRoutes(ctx) { + // ICQ swap price for the specific pair on this route and update keeper on callback + if err := k.PoolPriceQuery(ctx, route); err != nil { + k.Logger(ctx).Error(fmt.Sprintf("Unable to submit query for pool spot price: %s", err)) + } + } +} diff --git a/x/stakeibc/keeper/reward_converter_test.go b/x/stakeibc/keeper/reward_converter_test.go new file mode 100644 index 0000000000..c05534154d --- /dev/null +++ b/x/stakeibc/keeper/reward_converter_test.go @@ -0,0 +1,854 @@ +package keeper_test + +import ( + "fmt" + "time" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/gogoproto/proto" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + ibctesting "github.com/cosmos/ibc-go/v7/testing" + + epochtypes "github.com/Stride-Labs/stride/v16/x/epochs/types" + icqtypes "github.com/Stride-Labs/stride/v16/x/interchainquery/types" + "github.com/Stride-Labs/stride/v16/x/stakeibc/keeper" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// Useful across all balance query icqcallback tests +type BalanceQueryCallbackTestCase struct { + TradeRoute types.TradeRoute + Response ICQCallbackArgs + Balance sdkmath.Int + ChannelID string + PortID string +} + +type TransferRewardHostToTradeTestCase struct { + TradeRoute types.TradeRoute + TransferAmount sdkmath.Int + ExpectedTransferMsg transfertypes.MsgTransfer + ChannelID string + PortID string +} + +// -------------------------------------------------------------- +// Transfer Host to Trade +// -------------------------------------------------------------- + +func (s *KeeperTestSuite) SetupTransferRewardTokensHostToTradeTestCase() TransferRewardHostToTradeTestCase { + // Create an ICA channel for the transfer submission + owner := types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_WITHDRAWAL) + channelId, portId := s.CreateICAChannel(owner) + + // Define components of transfer message + hostToRewardChannelId := "channel-0" + rewardToTradeChannelId := "channel-1" + + rewardDenomOnHostZone := "ibc/reward_on_host" + rewardDenomOnRewardZone := RewardDenom + + withdrawalAddress := "withdrawal_address" + unwindAddress := "unwind_address" + tradeAddress := "trade_address" + + transferAmount := sdk.NewInt(1000) + transferToken := sdk.NewCoin(rewardDenomOnHostZone, transferAmount) + minSwapAmount := sdk.NewInt(500) + + currentTime := s.Ctx.BlockTime() + epochLength := time.Second * 10 // 10 seconds + transfer1TimeoutTimestamp := currentTime.Add(time.Second * 5) // 5 seconds from now (halfway through) + transfer2TimeoutDuration := "5s" + + // Create a trade route with the relevant addresses and transfer channels + route := types.TradeRoute{ + HostToRewardChannelId: hostToRewardChannelId, + RewardToTradeChannelId: rewardToTradeChannelId, + + RewardDenomOnHostZone: rewardDenomOnHostZone, + RewardDenomOnRewardZone: rewardDenomOnRewardZone, + HostDenomOnHostZone: HostDenom, + + HostAccount: types.ICAAccount{ + ChainId: HostChainId, + Address: withdrawalAddress, + ConnectionId: ibctesting.FirstConnectionID, + Type: types.ICAAccountType_WITHDRAWAL, + }, + RewardAccount: types.ICAAccount{ + Address: unwindAddress, + }, + TradeAccount: types.ICAAccount{ + Address: tradeAddress, + }, + + TradeConfig: types.TradeConfig{ + SwapPrice: sdk.OneDec(), + MinSwapAmount: minSwapAmount, + }, + } + + // Create an epoch tracker to dictate the timeout + s.CreateEpochForICATimeout(epochtypes.STRIDE_EPOCH, epochLength) + + // Define the expected transfer message using all the above + memoJSON := fmt.Sprintf(`{"forward":{"receiver":"%s","port":"transfer","channel":"%s","timeout":"%s","retries":0}}`, + tradeAddress, rewardToTradeChannelId, transfer2TimeoutDuration) + + expectedMsg := transfertypes.MsgTransfer{ + SourcePort: transfertypes.PortID, + SourceChannel: hostToRewardChannelId, + Token: transferToken, + Sender: withdrawalAddress, + Receiver: unwindAddress, + TimeoutTimestamp: uint64(transfer1TimeoutTimestamp.UnixNano()), + Memo: memoJSON, + } + + return TransferRewardHostToTradeTestCase{ + TradeRoute: route, + TransferAmount: transferAmount, + ExpectedTransferMsg: expectedMsg, + ChannelID: channelId, + PortID: portId, + } +} + +func (s *KeeperTestSuite) TestBuildHostToTradeTransferMsg_Success() { + tc := s.SetupTransferRewardTokensHostToTradeTestCase() + + // Confirm the generated message matches expectations + actualMsg, err := s.App.StakeibcKeeper.BuildHostToTradeTransferMsg(s.Ctx, tc.TransferAmount, tc.TradeRoute) + s.Require().NoError(err, "no error expected when building transfer message") + s.Require().Equal(tc.ExpectedTransferMsg, actualMsg, "transfer message should have matched") +} + +func (s *KeeperTestSuite) TestBuildHostToTradeTransferMsg_InvalidICAAddress() { + tc := s.SetupTransferRewardTokensHostToTradeTestCase() + + // Check unregisted ICA addresses cause failures + invalidRoute := tc.TradeRoute + invalidRoute.HostAccount.Address = "" + _, err := s.App.StakeibcKeeper.BuildHostToTradeTransferMsg(s.Ctx, tc.TransferAmount, invalidRoute) + s.Require().ErrorContains(err, "no host account found") + + invalidRoute = tc.TradeRoute + invalidRoute.RewardAccount.Address = "" + _, err = s.App.StakeibcKeeper.BuildHostToTradeTransferMsg(s.Ctx, tc.TransferAmount, invalidRoute) + s.Require().ErrorContains(err, "no reward account found") + + invalidRoute = tc.TradeRoute + invalidRoute.TradeAccount.Address = "" + _, err = s.App.StakeibcKeeper.BuildHostToTradeTransferMsg(s.Ctx, tc.TransferAmount, invalidRoute) + s.Require().ErrorContains(err, "no trade account found") +} + +func (s *KeeperTestSuite) TestBuildHostToTradeTransferMsg_EpochNotFound() { + tc := s.SetupTransferRewardTokensHostToTradeTestCase() + + // Delete the epoch tracker and confirm the message cannot be built + s.App.StakeibcKeeper.RemoveEpochTracker(s.Ctx, epochtypes.STRIDE_EPOCH) + + _, err := s.App.StakeibcKeeper.BuildHostToTradeTransferMsg(s.Ctx, tc.TransferAmount, tc.TradeRoute) + s.Require().ErrorContains(err, "epoch not found") +} + +func (s *KeeperTestSuite) TestTransferRewardTokensHostToTrade_Success() { + tc := s.SetupTransferRewardTokensHostToTradeTestCase() + + // Check that the transfer ICA is submitted when the function is called + s.CheckICATxSubmitted(tc.PortID, tc.ChannelID, func() error { + return s.App.StakeibcKeeper.TransferRewardTokensHostToTrade(s.Ctx, tc.TransferAmount, tc.TradeRoute) + }) +} + +func (s *KeeperTestSuite) TestTransferRewardTokensHostToTrade_TransferAmountBelowMin() { + tc := s.SetupTransferRewardTokensHostToTradeTestCase() + + // Attempt to call the function with an transfer amount below the min, + // it should not submit an ICA + invalidTransferAmount := tc.TradeRoute.TradeConfig.MinSwapAmount.Sub(sdkmath.OneInt()) + s.CheckICATxNotSubmitted(tc.PortID, tc.ChannelID, func() error { + return s.App.StakeibcKeeper.TransferRewardTokensHostToTrade(s.Ctx, invalidTransferAmount, tc.TradeRoute) + }) +} + +func (s *KeeperTestSuite) TestTransferRewardTokensHostToTrade_NoPoolPrice() { + tc := s.SetupTransferRewardTokensHostToTradeTestCase() + + // Attempt to call the function with a route that does not have a pool price + // If should not initiate the transfer (since the swap would be unable to execute) + invalidRoute := tc.TradeRoute + invalidRoute.TradeConfig.SwapPrice = sdk.ZeroDec() + + s.CheckICATxNotSubmitted(tc.PortID, tc.ChannelID, func() error { + return s.App.StakeibcKeeper.TransferRewardTokensHostToTrade(s.Ctx, tc.TransferAmount, invalidRoute) + }) +} + +func (s *KeeperTestSuite) TestTransferRewardTokensHostToTrade_FailedToSubmitICA() { + tc := s.SetupTransferRewardTokensHostToTradeTestCase() + + // Remove the connection ID and confirm the ICA submission fails + invalidRoute := tc.TradeRoute + invalidRoute.HostAccount.ConnectionId = "" + + err := s.App.StakeibcKeeper.TransferRewardTokensHostToTrade(s.Ctx, tc.TransferAmount, invalidRoute) + s.Require().ErrorContains(err, "Failed to submit ICA tx") +} + +func (s *KeeperTestSuite) TestTransferRewardTokensHostToTrade_EpochNotFound() { + tc := s.SetupTransferRewardTokensHostToTradeTestCase() + + // Delete the epoch tracker and confirm the transfer cannot be initiated + s.App.StakeibcKeeper.RemoveEpochTracker(s.Ctx, epochtypes.STRIDE_EPOCH) + + err := s.App.StakeibcKeeper.TransferRewardTokensHostToTrade(s.Ctx, tc.TransferAmount, tc.TradeRoute) + s.Require().ErrorContains(err, "epoch not found") +} + +// -------------------------------------------------------------- +// Transfer Trade to Trade +// -------------------------------------------------------------- + +func (s *KeeperTestSuite) TestTransferConvertedTokensTradeToHost() { + transferAmount := sdkmath.NewInt(1000) + + // Register a trade ICA account for the transfer + owner := types.FormatTradeRouteICAOwner(HostChainId, RewardDenom, HostDenom, types.ICAAccountType_CONVERTER_TRADE) + channelId, portId := s.CreateICAChannel(owner) + + // Create trade route with fields needed for transfer + route := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + + HostDenomOnTradeZone: "ibc/host-on-trade", + TradeToHostChannelId: "channel-1", + HostAccount: types.ICAAccount{ + Address: "host_address", + }, + TradeAccount: types.ICAAccount{ + ChainId: HostChainId, + Address: "trade_address", + ConnectionId: ibctesting.FirstConnectionID, + Type: types.ICAAccountType_CONVERTER_TRADE, + }, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, route) + + // Create epoch tracker to dictate timeout + s.CreateEpochForICATimeout(epochtypes.STRIDE_EPOCH, time.Second*10) + + // Confirm the sequence number was incremented after a successful send + startSequence := s.MustGetNextSequenceNumber(portId, channelId) + + err := s.App.StakeibcKeeper.TransferConvertedTokensTradeToHost(s.Ctx, transferAmount, route) + s.Require().NoError(err, "no error expected when transfering tokens") + + endSequence := s.MustGetNextSequenceNumber(portId, channelId) + s.Require().Equal(startSequence+1, endSequence, "sequence number should have incremented from transfer") + + // Attempt to send without a valid ICA address - it should fail + invalidRoute := route + invalidRoute.HostAccount.Address = "" + err = s.App.StakeibcKeeper.TransferConvertedTokensTradeToHost(s.Ctx, transferAmount, invalidRoute) + s.Require().ErrorContains(err, "no host account found") + + invalidRoute = route + invalidRoute.TradeAccount.Address = "" + err = s.App.StakeibcKeeper.TransferConvertedTokensTradeToHost(s.Ctx, transferAmount, invalidRoute) + s.Require().ErrorContains(err, "no trade account found") +} + +// -------------------------------------------------------------- +// Reward Token Swap +// -------------------------------------------------------------- + +func (s *KeeperTestSuite) TestBuildSwapMsg() { + poolId := uint64(100) + tradeAddress := "trade_address" + + rewardDenom := "ibc/reward_on_trade" + hostDenom := "ibc/host_on_trade" + + baseTradeRoute := types.TradeRoute{ + RewardDenomOnTradeZone: rewardDenom, + HostDenomOnTradeZone: hostDenom, + + TradeAccount: types.ICAAccount{ + Address: tradeAddress, + }, + + TradeConfig: types.TradeConfig{ + PoolId: poolId, + }, + } + + testCases := []struct { + name string + price sdk.Dec + maxAllowedSwapLoss sdk.Dec + minSwapAmount sdkmath.Int + maxSwapAmount sdkmath.Int + rewardAmount sdkmath.Int + expectedTradeAmount sdkmath.Int + expectedMinOut sdkmath.Int + expectedError string + }{ + { + // Reward Amount: 100, Min: 0, Max: 200 => Trade Amount: 100 + // Price: 1, Slippage: 5% => Min Out: 95 + name: "swap 1", + price: sdk.MustNewDecFromStr("1.0"), + maxAllowedSwapLoss: sdk.MustNewDecFromStr("0.05"), + + maxSwapAmount: sdkmath.NewInt(200), + rewardAmount: sdkmath.NewInt(100), + expectedTradeAmount: sdkmath.NewInt(100), + + expectedMinOut: sdkmath.NewInt(95), + }, + { + // Reward Amount: 100, Min: 0, Max: 200 => Trade Amount: 100 + // Price: 0.70, Slippage: 10% => Min Out: 100 * 0.70 * 0.9 = 63 + name: "swap 2", + price: sdk.MustNewDecFromStr("0.70"), + maxAllowedSwapLoss: sdk.MustNewDecFromStr("0.10"), + + maxSwapAmount: sdkmath.NewInt(200), + rewardAmount: sdkmath.NewInt(100), + expectedTradeAmount: sdkmath.NewInt(100), + + expectedMinOut: sdkmath.NewInt(63), + }, + { + // Reward Amount: 100, Min: 0, Max: 200 => Trade Amount: 100 + // Price: 1.80, Slippage: 15% => Min Out: 100 * 1.8 * 0.85 = 153 + name: "swap 3", + price: sdk.MustNewDecFromStr("1.8"), + maxAllowedSwapLoss: sdk.MustNewDecFromStr("0.15"), + + maxSwapAmount: sdkmath.NewInt(200), + rewardAmount: sdkmath.NewInt(100), + expectedTradeAmount: sdkmath.NewInt(100), + + expectedMinOut: sdkmath.NewInt(153), + }, + { + // Reward Amount: 200, Min: 0, Max: 100 => Trade Amount: 100 + // Price: 1, Slippage: 5% => Min Out: 95 + name: "capped by max swap amount", + price: sdk.MustNewDecFromStr("1.0"), + maxAllowedSwapLoss: sdk.MustNewDecFromStr("0.05"), + + maxSwapAmount: sdkmath.NewInt(100), + rewardAmount: sdkmath.NewInt(200), + expectedTradeAmount: sdkmath.NewInt(100), + + expectedMinOut: sdkmath.NewInt(95), + }, + { + // Reward Amount: 100, Min: 0, Max: 200 => Trade Amount: 100 + // Price: 1, Slippage: 5.001% => Min Out: 94.999 => truncated to 94 + name: "int truncation in min out caused by decimal max swap allowed", + price: sdk.MustNewDecFromStr("1.0"), + maxAllowedSwapLoss: sdk.MustNewDecFromStr("0.05001"), + + maxSwapAmount: sdkmath.NewInt(200), + rewardAmount: sdkmath.NewInt(100), + expectedTradeAmount: sdkmath.NewInt(100), + + expectedMinOut: sdkmath.NewInt(94), + }, + { + // Reward Amount: 100, Min: 0, Max: 200 => Trade Amount: 100 + // Price: 0.9998, Slippage: 10% => Min Out: 89.991 => truncated to 89 + name: "int truncation in min out caused by decimal price", + price: sdk.MustNewDecFromStr("0.9998"), + maxAllowedSwapLoss: sdk.MustNewDecFromStr("0.10"), + + maxSwapAmount: sdkmath.NewInt(200), + rewardAmount: sdkmath.NewInt(100), + expectedTradeAmount: sdkmath.NewInt(100), + + expectedMinOut: sdkmath.NewInt(89), + }, + { + // Reward Amount: 89234, Min: 0, Max: 23424 => Trade Amount: 23424 + // Price: 15.234323, Slippage: 9.234329% + // => Min Out: 23424 * 15.234323 * 0.90765671 = 323896.19 => truncates to 323896 + name: "int truncation from random numbers", + price: sdk.MustNewDecFromStr("15.234323"), + maxAllowedSwapLoss: sdk.MustNewDecFromStr("0.09234329"), + + maxSwapAmount: sdkmath.NewInt(23424), + rewardAmount: sdkmath.NewInt(89234), + expectedTradeAmount: sdkmath.NewInt(23424), + + expectedMinOut: sdkmath.NewInt(323896), + }, + { + // Missing price + name: "missing price error", + price: sdk.ZeroDec(), + maxAllowedSwapLoss: sdk.MustNewDecFromStr("0"), + + maxSwapAmount: sdkmath.NewInt(0), + rewardAmount: sdkmath.NewInt(0), + expectedTradeAmount: sdkmath.NewInt(0), + expectedMinOut: sdkmath.NewInt(0), + + expectedError: "Price not found for pool", + }, + } + + for _, tc := range testCases { + route := baseTradeRoute + + route.TradeConfig.SwapPrice = tc.price + route.TradeConfig.MinSwapAmount = tc.minSwapAmount + route.TradeConfig.MaxSwapAmount = tc.maxSwapAmount + route.TradeConfig.MaxAllowedSwapLossRate = tc.maxAllowedSwapLoss + + msg, err := s.App.StakeibcKeeper.BuildSwapMsg(tc.rewardAmount, route) + + if tc.expectedError != "" { + s.Require().ErrorContains(err, tc.expectedError, "%s - error expected", tc.name) + continue + } + s.Require().Equal(tradeAddress, msg.Sender, "%s - sender", tc.name) + s.Require().Equal(poolId, msg.Routes[0].PoolId, "%s - pool id", tc.name) + + s.Require().Equal(hostDenom, msg.Routes[0].TokenOutDenom, "%s - token out denom", tc.name) + s.Require().Equal(rewardDenom, msg.TokenIn.Denom, "%s - token in denom", tc.name) + + s.Require().Equal(tc.expectedTradeAmount.Int64(), msg.TokenIn.Amount.Int64(), "%s - token in amount", tc.name) + s.Require().Equal(tc.expectedMinOut.Int64(), msg.TokenOutMinAmount.Int64(), "%s - min token out", tc.name) + } + + // Test with a missing ICA address + invalidRoute := baseTradeRoute + invalidRoute.TradeAccount.Address = "" + _, err := s.App.StakeibcKeeper.BuildSwapMsg(sdk.NewInt(1), invalidRoute) + s.Require().ErrorContains(err, "no trade account found") +} + +func (s *KeeperTestSuite) TestSwapRewardTokens() { + // Create an ICA channel for the transfer submission + owner := types.FormatTradeRouteICAOwner(HostChainId, RewardDenom, HostDenom, types.ICAAccountType_CONVERTER_TRADE) + channelId, portId := s.CreateICAChannel(owner) + + minSwapAmount := sdkmath.NewInt(10) + rewardAmount := sdkmath.NewInt(100) + + route := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + + RewardDenomOnTradeZone: "ibc/reward_on_trade", + HostDenomOnTradeZone: "ibc/host_on_trade", + + TradeAccount: types.ICAAccount{ + ChainId: HostChainId, + Address: "trade_address", + ConnectionId: ibctesting.FirstConnectionID, + Type: types.ICAAccountType_CONVERTER_TRADE, + }, + + TradeConfig: types.TradeConfig{ + PoolId: 100, + SwapPrice: sdk.OneDec(), + MinSwapAmount: minSwapAmount, + MaxSwapAmount: sdkmath.NewInt(1000), + MaxAllowedSwapLossRate: sdk.MustNewDecFromStr("0.1"), + }, + } + + // Create an epoch tracker to dictate the timeout + s.CreateEpochForICATimeout(epochtypes.HOUR_EPOCH, time.Minute) // arbitrary timeout time + + // Execute the swap and confirm the sequence number increments + startSequence := s.MustGetNextSequenceNumber(portId, channelId) + + err := s.App.StakeibcKeeper.SwapRewardTokens(s.Ctx, rewardAmount, route) + s.Require().NoError(err, "no error expected when submitting swap") + + sequenceAfterSwap := s.MustGetNextSequenceNumber(portId, channelId) + s.Require().Equal(startSequence+1, sequenceAfterSwap, "sequence number should have incremented") + + // Attempt to call the function again with an swap amount below the min, + // it should not submit an ICA + invalidSwapAmount := minSwapAmount.Sub(sdkmath.OneInt()) + err = s.App.StakeibcKeeper.SwapRewardTokens(s.Ctx, invalidSwapAmount, route) + s.Require().NoError(err, "no error expected when submitting transfer with amount below minimum") + + endSequence := s.MustGetNextSequenceNumber(portId, channelId) + s.Require().Equal(sequenceAfterSwap, endSequence, "sequence number should NOT have incremented") + + // Remove the connection ID so the ICA fails + invalidRoute := route + invalidRoute.TradeAccount.ConnectionId = "" + err = s.App.StakeibcKeeper.SwapRewardTokens(s.Ctx, rewardAmount, invalidRoute) + s.Require().ErrorContains(err, "Failed to submit ICA tx") + + // Delete the epoch tracker and confirm the swap fails + s.App.StakeibcKeeper.RemoveEpochTracker(s.Ctx, epochtypes.HOUR_EPOCH) + err = s.App.StakeibcKeeper.SwapRewardTokens(s.Ctx, rewardAmount, route) + s.Require().ErrorContains(err, "epoch not found") +} + +// -------------------------------------------------------------- +// Trade Route ICQ Test Helpers +// -------------------------------------------------------------- + +// Helper function to validate the address and denom from the query request data +func (s *KeeperTestSuite) validateAddressAndDenomInRequest(data []byte, expectedAddress, expectedDenom string) { + actualAddress, actualDenom := s.ExtractAddressAndDenomFromBankPrefix(data) + s.Require().Equal(expectedAddress, actualAddress, "query account address") + s.Require().Equal(expectedDenom, actualDenom, "query denom") +} + +// Helper function to validate the trade route query callback data +func (s *KeeperTestSuite) validateTradeRouteQueryCallback(actualCallbackDataBz []byte) { + expectedCallbackData := types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: HostDenom, + } + + var actualCallbackData types.TradeRouteCallback + err := proto.Unmarshal(actualCallbackDataBz, &actualCallbackData) + s.Require().NoError(err) + s.Require().Equal(expectedCallbackData, actualCallbackData, "query callback data") +} + +// -------------------------------------------------------------- +// Withdrawal Account - Reward Balance Query +// -------------------------------------------------------------- + +// Create the traderoute for these tests, only need the withdrawal address and the +// reward_denom_on_host since this will be what is used in the query, no other setup +func (s *KeeperTestSuite) SetupWithdrawalRewardBalanceQueryTestCase() (route types.TradeRoute, expectedTimeout time.Duration) { + // Create a transfer channel so the connection exists for the query submission + s.CreateTransferChannel(HostChainId) + + // Create and set the trade route + tradeRoute := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + RewardDenomOnHostZone: "ibc/reward_on_host", + HostAccount: types.ICAAccount{ + ChainId: HostChainId, + ConnectionId: ibctesting.FirstConnectionID, + Address: StrideICAAddress, // must be a valid bech32, easiest to use stride prefix for validation + }, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, tradeRoute) + + // Create and set the epoch tracker for timeouts (the timeout is halfway through the epoch) + epochDuration := time.Second * 30 + expectedTimeout = epochDuration / 2 + s.CreateEpochForICATimeout(epochtypes.STRIDE_EPOCH, epochDuration) + + return tradeRoute, expectedTimeout +} + +// Tests a successful WithdrawalRewardBalanceQuery +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceQuery_Successful() { + route, timeoutDuration := s.SetupWithdrawalRewardBalanceQueryTestCase() + + err := s.App.StakeibcKeeper.WithdrawalRewardBalanceQuery(s.Ctx, route) + s.Require().NoError(err, "no error expected when querying balance") + + // Validate fields from ICQ submission + expectedRequestData := s.GetBankStoreKeyPrefix(StrideICAAddress, route.RewardDenomOnHostZone) + + query := s.ValidateQuerySubmission( + icqtypes.BANK_STORE_QUERY_WITH_PROOF, + expectedRequestData, + keeper.ICQCallbackID_WithdrawalRewardBalance, + timeoutDuration, + icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, + ) + + s.validateAddressAndDenomInRequest(query.RequestData, route.HostAccount.Address, route.RewardDenomOnHostZone) + s.validateTradeRouteQueryCallback(query.CallbackData) +} + +// Tests a WithdrawalRewardBalanceQuery that fails due to an invalid account address +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceQuery_Failure_InvalidAccountAddress() { + tradeRoute, _ := s.SetupWithdrawalRewardBalanceQueryTestCase() + + // Change the withdrawal ICA account address to be invalid + tradeRoute.HostAccount.Address = "invalid_address" + + err := s.App.StakeibcKeeper.WithdrawalRewardBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "invalid withdrawal account address") +} + +// Tests a WithdrawalRewardBalanceQuery that fails due to a missing epoch tracker +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceQuery_Failure_MissingEpoch() { + tradeRoute, _ := s.SetupWithdrawalRewardBalanceQueryTestCase() + + // Remove the stride epoch so the test fails + s.App.StakeibcKeeper.RemoveEpochTracker(s.Ctx, epochtypes.STRIDE_EPOCH) + + err := s.App.StakeibcKeeper.WithdrawalRewardBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "stride_epoch: epoch not found") +} + +// Tests a WithdrawalRewardBalanceQuery that fails to submit the query due to bad connection +func (s *KeeperTestSuite) TestWithdrawalRewardBalanceQuery_FailedQuerySubmission() { + tradeRoute, _ := s.SetupWithdrawalRewardBalanceQueryTestCase() + + // Change the withdrawal ICA connection id to be invalid + tradeRoute.HostAccount.ConnectionId = "invalid_connection" + + err := s.App.StakeibcKeeper.WithdrawalRewardBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "invalid connection-id (invalid_connection)") +} + +// -------------------------------------------------------------- +// Trade Account - Reward Balance Query +// -------------------------------------------------------------- + +// Create the traderoute for these tests, only need the trade address and the +// reward_denom_on_trade since this will be what is used in the query, no other setup +func (s *KeeperTestSuite) SetupTradeRewardBalanceQueryTestCase() (route types.TradeRoute, expectedTimeout time.Duration) { + // Create a transfer channel so the connection exists for the query submission + s.CreateTransferChannel(HostChainId) + + // Create and set the trade route + tradeRoute := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + RewardDenomOnTradeZone: "ibc/reward_on_trade", + TradeAccount: types.ICAAccount{ + ChainId: HostChainId, + ConnectionId: ibctesting.FirstConnectionID, + Address: StrideICAAddress, // must be a valid bech32, easiest to use stride prefix for validation + }, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, tradeRoute) + + // Create and set the epoch tracker for timeouts + timeoutDuration := time.Second * 30 + s.CreateEpochForICATimeout(epochtypes.HOUR_EPOCH, timeoutDuration) + + return tradeRoute, timeoutDuration +} + +// Tests a successful TradeRewardBalanceQuery +func (s *KeeperTestSuite) TestTradeRewardBalanceQuery_Successful() { + route, timeoutDuration := s.SetupTradeRewardBalanceQueryTestCase() + + err := s.App.StakeibcKeeper.TradeRewardBalanceQuery(s.Ctx, route) + s.Require().NoError(err, "no error expected when querying balance") + + // Validate fields from ICQ submission + expectedRequestData := s.GetBankStoreKeyPrefix(StrideICAAddress, route.RewardDenomOnTradeZone) + + query := s.ValidateQuerySubmission( + icqtypes.BANK_STORE_QUERY_WITH_PROOF, + expectedRequestData, + keeper.ICQCallbackID_TradeRewardBalance, + timeoutDuration, + icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, + ) + + s.validateAddressAndDenomInRequest(query.RequestData, route.TradeAccount.Address, route.RewardDenomOnTradeZone) + s.validateTradeRouteQueryCallback(query.CallbackData) +} + +// Tests a TradeRewardBalanceQuery that fails due to an invalid account address +func (s *KeeperTestSuite) TestTradeRewardBalanceQuery_Failure_InvalidAccountAddress() { + tradeRoute, _ := s.SetupTradeRewardBalanceQueryTestCase() + + // Change the trade ICA account address to be invalid + tradeRoute.TradeAccount.Address = "invalid_address" + + err := s.App.StakeibcKeeper.TradeRewardBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "invalid trade account address") +} + +// Tests a TradeRewardBalanceQuery that fails due to a missing epoch tracker +func (s *KeeperTestSuite) TestTradeRewardBalanceQuery_Failure_MissingEpoch() { + tradeRoute, _ := s.SetupTradeRewardBalanceQueryTestCase() + + // Remove the stride epoch so the test fails + s.App.StakeibcKeeper.RemoveEpochTracker(s.Ctx, epochtypes.HOUR_EPOCH) + + err := s.App.StakeibcKeeper.TradeRewardBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "hour: epoch not found") +} + +// Tests a TradeRewardBalanceQuery that fails to submit the query due to bad connection +func (s *KeeperTestSuite) TestTradeRewardBalanceQuery_FailedQuerySubmission() { + tradeRoute, _ := s.SetupTradeRewardBalanceQueryTestCase() + + // Change the trade ICA connection id to be invalid + tradeRoute.TradeAccount.ConnectionId = "invalid_connection" + + err := s.App.StakeibcKeeper.TradeRewardBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "invalid connection-id (invalid_connection)") +} + +// -------------------------------------------------------------- +// Trade Account - Converted Balance Query +// -------------------------------------------------------------- + +// Create the traderoute for these tests, only need the trade address and the +// host_denom_on_trade since this will be what is used in the query, no other setup +func (s *KeeperTestSuite) SetupTradeConvertedBalanceQueryTestCase() (route types.TradeRoute, expectedTimeout time.Duration) { + // Create a transfer channel so the connection exists for the query submission + s.CreateTransferChannel(HostChainId) + + // Create and set the trade route + tradeRoute := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + HostDenomOnTradeZone: "ibc/host_on_trade", + TradeAccount: types.ICAAccount{ + ChainId: HostChainId, + ConnectionId: ibctesting.FirstConnectionID, + Address: StrideICAAddress, // must be a valid bech32, easiest to use stride prefix for validation + }, + } + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, tradeRoute) + + // Create and set the epoch tracker for timeouts + timeoutDuration := time.Second * 30 + s.CreateEpochForICATimeout(epochtypes.STRIDE_EPOCH, timeoutDuration) + + return tradeRoute, timeoutDuration +} + +// Tests a successful TradeConvertedBalanceQuery +func (s *KeeperTestSuite) TestTradeConvertedBalanceQuery_Successful() { + route, timeoutDuration := s.SetupTradeConvertedBalanceQueryTestCase() + + err := s.App.StakeibcKeeper.TradeConvertedBalanceQuery(s.Ctx, route) + s.Require().NoError(err, "no error expected when querying balance") + + // Validate fields from ICQ submission + expectedRequestData := s.GetBankStoreKeyPrefix(StrideICAAddress, route.HostDenomOnTradeZone) + + query := s.ValidateQuerySubmission( + icqtypes.BANK_STORE_QUERY_WITH_PROOF, + expectedRequestData, + keeper.ICQCallbackID_TradeConvertedBalance, + timeoutDuration, + icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, + ) + + s.validateAddressAndDenomInRequest(query.RequestData, route.TradeAccount.Address, route.HostDenomOnTradeZone) + s.validateTradeRouteQueryCallback(query.CallbackData) +} + +// Tests a TradeConvertedBalanceQuery that fails due to an invalid account address +func (s *KeeperTestSuite) TestTradeConvertedBalanceQuery_Failure_InvalidAccountAddress() { + tradeRoute, _ := s.SetupTradeConvertedBalanceQueryTestCase() + + // Change the trade ICA account address to be invalid + tradeRoute.TradeAccount.Address = "invalid_address" + + err := s.App.StakeibcKeeper.TradeConvertedBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "invalid trade account address") +} + +// Tests a TradeConvertedBalanceQuery that fails due to a missing epoch tracker +func (s *KeeperTestSuite) TestTradeConvertedBalanceQuery_Failure_MissingEpoch() { + tradeRoute, _ := s.SetupTradeConvertedBalanceQueryTestCase() + + // Remove the stride epoch so the test fails + s.App.StakeibcKeeper.RemoveEpochTracker(s.Ctx, epochtypes.STRIDE_EPOCH) + + err := s.App.StakeibcKeeper.TradeConvertedBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "stride_epoch: epoch not found") +} + +// Tests a TradeConvertedBalanceQuery that fails to submit the query due to bad connection +func (s *KeeperTestSuite) TestTradeConvertedBalanceQuery_FailedQuerySubmission() { + tradeRoute, _ := s.SetupTradeConvertedBalanceQueryTestCase() + + // Change the trade ICA connection id to be invalid + tradeRoute.TradeAccount.ConnectionId = "invalid_connection" + + err := s.App.StakeibcKeeper.TradeConvertedBalanceQuery(s.Ctx, tradeRoute) + s.Require().ErrorContains(err, "invalid connection-id (invalid_connection)") +} + +// -------------------------------------------------------------- +// Pool Price Query +// -------------------------------------------------------------- + +func (s *KeeperTestSuite) TestPoolPriceQuery() { + // Create a transfer channel so the connection exists for the query submission + s.CreateTransferChannel(HostChainId) + + // Create an epoch tracker to dictate the query timeout + timeoutDuration := time.Minute * 10 + s.CreateEpochForICATimeout(epochtypes.HOUR_EPOCH, timeoutDuration) + + // Define the trade route + poolId := uint64(100) + tradeRewardDenom := "ibc/reward-denom-on-trade" + tradeHostDenom := "ibc/reward-denom-on-host" + + route := types.TradeRoute{ + RewardDenomOnRewardZone: RewardDenom, + HostDenomOnHostZone: HostDenom, + RewardDenomOnTradeZone: tradeRewardDenom, + HostDenomOnTradeZone: tradeHostDenom, + + TradeAccount: types.ICAAccount{ + ChainId: HostChainId, + ConnectionId: ibctesting.FirstConnectionID, + }, + TradeConfig: types.TradeConfig{ + PoolId: poolId, + }, + } + + expectedCallbackData := types.TradeRouteCallback{ + RewardDenom: RewardDenom, + HostDenom: HostDenom, + } + + // Submit the pool price ICQ + err := s.App.StakeibcKeeper.PoolPriceQuery(s.Ctx, route) + s.Require().NoError(err, "no error expected when submitting pool price query") + + // Confirm the query request key is the same regardless of which order the denom's are specified + expectedRequestData := icqtypes.FormatOsmosisMostRecentTWAPKey(poolId, tradeRewardDenom, tradeHostDenom) + expectedRequestDataSwapped := icqtypes.FormatOsmosisMostRecentTWAPKey(poolId, tradeHostDenom, tradeRewardDenom) + s.Require().Equal(expectedRequestData, expectedRequestDataSwapped, "osmosis twap denoms should be sorted") + + // Validate the fields of the query + query := s.ValidateQuerySubmission( + icqtypes.TWAP_STORE_QUERY_WITH_PROOF, + expectedRequestData, + keeper.ICQCallbackID_PoolPrice, + timeoutDuration, + icqtypes.TimeoutPolicy_REJECT_QUERY_RESPONSE, + ) + + // Validate the query callback data + var actualCallbackData types.TradeRouteCallback + err = proto.Unmarshal(query.CallbackData, &actualCallbackData) + s.Require().NoError(err) + s.Require().Equal(expectedCallbackData, actualCallbackData, "query callback data") + + // Remove the connection ID from the trade account and confirm the query submission fails + invalidRoute := route + invalidRoute.TradeAccount.ConnectionId = "" + err = s.App.StakeibcKeeper.PoolPriceQuery(s.Ctx, invalidRoute) + s.Require().ErrorContains(err, "invalid interchain query request") + + // Remove the epoch tracker so the function fails to get a timeout + s.App.StakeibcKeeper.RemoveEpochTracker(s.Ctx, epochtypes.HOUR_EPOCH) + err = s.App.StakeibcKeeper.PoolPriceQuery(s.Ctx, route) + s.Require().ErrorContains(err, "hour: epoch not found") +} diff --git a/x/stakeibc/keeper/trade_route.go b/x/stakeibc/keeper/trade_route.go new file mode 100644 index 0000000000..181e6eeea3 --- /dev/null +++ b/x/stakeibc/keeper/trade_route.go @@ -0,0 +1,53 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +// SetTradeRoute set a specific tradeRoute in the store +func (k Keeper) SetTradeRoute(ctx sdk.Context, tradeRoute types.TradeRoute) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TradeRouteKeyPrefix)) + key := tradeRoute.GetKey() + b := k.cdc.MustMarshal(&tradeRoute) + store.Set(key, b) +} + +// GetTradeRoute returns a tradeRoute from its start and end denoms +// The start and end denom's are in their native format (e.g. uusdc and udydx) +func (k Keeper) GetTradeRoute(ctx sdk.Context, rewardDenom string, hostDenom string) (val types.TradeRoute, found bool) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TradeRouteKeyPrefix)) + key := types.TradeRouteKeyFromDenoms(rewardDenom, hostDenom) + b := store.Get(key) + if len(b) == 0 { + return val, false + } + k.cdc.MustUnmarshal(b, &val) + return val, true +} + +// RemoveTradeRoute removes a tradeRoute from the store +// The start and end denom's are in their native format (e.g. uusdc and udydx) +func (k Keeper) RemoveTradeRoute(ctx sdk.Context, rewardDenom string, hostDenom string) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TradeRouteKeyPrefix)) + key := types.TradeRouteKeyFromDenoms(rewardDenom, hostDenom) + store.Delete(key) +} + +// GetAllTradeRoute returns all tradeRoutes +func (k Keeper) GetAllTradeRoutes(ctx sdk.Context) (list []types.TradeRoute) { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.TradeRouteKeyPrefix)) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + var val types.TradeRoute + k.cdc.MustUnmarshal(iterator.Value(), &val) + list = append(list, val) + } + + return +} diff --git a/x/stakeibc/keeper/trade_route_test.go b/x/stakeibc/keeper/trade_route_test.go new file mode 100644 index 0000000000..b7e85a3fe3 --- /dev/null +++ b/x/stakeibc/keeper/trade_route_test.go @@ -0,0 +1,98 @@ +package keeper_test + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func (s *KeeperTestSuite) CreateTradeRoutes() (routes []types.TradeRoute) { + for i := 1; i <= 5; i++ { + hostChain := fmt.Sprintf("chain-H%d", i) + rewardChain := fmt.Sprintf("chain-R%d", i) + tradeChain := fmt.Sprintf("chain-T%d", i) + + hostICA := types.ICAAccount{ + ChainId: hostChain, + Type: types.ICAAccountType_WITHDRAWAL, + ConnectionId: fmt.Sprintf("connection-0%d", i), + Address: "host_ica_address", + } + rewardICA := types.ICAAccount{ + ChainId: rewardChain, + Type: types.ICAAccountType_CONVERTER_UNWIND, + ConnectionId: fmt.Sprintf("connection-1%d", i), + Address: "reward_ica_address", + } + tradeICA := types.ICAAccount{ + ChainId: tradeChain, + Type: types.ICAAccountType_CONVERTER_TRADE, + ConnectionId: fmt.Sprintf("connection-2%d", i), + Address: "trade_ica_address", + } + + tradeConfig := types.TradeConfig{ + PoolId: uint64(i * 100), + SwapPrice: sdk.OneDec(), + MaxAllowedSwapLossRate: sdk.MustNewDecFromStr("0.05"), + + MinSwapAmount: sdk.ZeroInt(), + MaxSwapAmount: sdk.NewInt(1_000_000_000), + } + + hostDenom := fmt.Sprintf("host-denom-%d", i) + rewardDenom := fmt.Sprintf("reward-denom-%d", i) + + route := types.TradeRoute{ + RewardDenomOnHostZone: "ibc-" + rewardDenom + "-on-" + hostChain, + RewardDenomOnRewardZone: rewardDenom, + RewardDenomOnTradeZone: "ibc-" + rewardDenom + "-on-" + tradeChain, + HostDenomOnTradeZone: "ibc-" + hostDenom + "-on-" + tradeChain, + HostDenomOnHostZone: hostDenom, + + HostAccount: hostICA, + RewardAccount: rewardICA, + TradeAccount: tradeICA, + + HostToRewardChannelId: fmt.Sprintf("channel-0%d", i), + RewardToTradeChannelId: fmt.Sprintf("channel-1%d", i), + TradeToHostChannelId: fmt.Sprintf("channel-2%d", i), + + TradeConfig: tradeConfig, + } + routes = append(routes, route) + + s.App.StakeibcKeeper.SetTradeRoute(s.Ctx, route) + } + + return routes +} + +func (s *KeeperTestSuite) TestGetTradeRoute() { + routes := s.CreateTradeRoutes() + for i, route := range routes { + rewardDenom := route.RewardDenomOnRewardZone + hostDenom := route.HostDenomOnHostZone + + actualRoute, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, rewardDenom, hostDenom) + s.Require().True(found, "route should have been found") + s.Require().Equal(routes[i], actualRoute, "route doesn't match") + } +} + +func (s *KeeperTestSuite) TestRemoveTradeRoute() { + routes := s.CreateTradeRoutes() + for _, route := range routes { + s.App.StakeibcKeeper.RemoveTradeRoute(s.Ctx, route.RewardDenomOnRewardZone, route.HostDenomOnHostZone) + _, found := s.App.StakeibcKeeper.GetTradeRoute(s.Ctx, route.RewardDenomOnRewardZone, route.HostDenomOnHostZone) + s.Require().False(found, "route should not have been found") + } +} + +func (s *KeeperTestSuite) TestGetAllTradeRoutes() { + expectedRoutes := s.CreateTradeRoutes() + actualRoutes := s.App.StakeibcKeeper.GetAllTradeRoutes(s.Ctx) + s.Require().ElementsMatch(expectedRoutes, actualRoutes) +} diff --git a/x/stakeibc/keeper/transfer_test.go b/x/stakeibc/keeper/transfer_test.go index c6f5309223..01b8080bd9 100644 --- a/x/stakeibc/keeper/transfer_test.go +++ b/x/stakeibc/keeper/transfer_test.go @@ -24,7 +24,7 @@ type TransferCommunityPoolDepositToHoldingTestCase struct { } func (s *KeeperTestSuite) SetupTransferCommunityPoolDepositToHolding() TransferCommunityPoolDepositToHoldingTestCase { - owner := types.FormatICAAccountOwner(chainId, types.ICAAccountType_COMMUNITY_POOL_DEPOSIT) + owner := types.FormatHostZoneICAOwner(chainId, types.ICAAccountType_COMMUNITY_POOL_DEPOSIT) channelId, portId := s.CreateICAChannel(owner) holdingAddress := s.TestAccs[0].String() @@ -93,11 +93,11 @@ func (s *KeeperTestSuite) TestTransferCommunityPoolDepositToHolding_MissingDepos func (s *KeeperTestSuite) TestTransferCommunityPoolDepositToHolding_ConnectionSendFail() { tc := s.SetupTransferCommunityPoolDepositToHolding() - tc.hostZone.ConnectionId = "MissingChannel" + tc.hostZone.ConnectionId = "MissingConnection" // Verify that the ICA msg was successfully sent off err := s.App.StakeibcKeeper.TransferCommunityPoolDepositToHolding(s.Ctx, tc.hostZone, tc.coin) - s.Require().ErrorContains(err, "invalid connection id") + s.Require().ErrorContains(err, "connection MissingConnection not found") } type TransferHoldingToCommunityPoolReturnTestCase struct { diff --git a/x/stakeibc/keeper/unbonding_records_get_host_zone_unbondings_msgs_test.go b/x/stakeibc/keeper/unbonding_records_get_host_zone_unbondings_msgs_test.go index 5e45969403..1545468e07 100644 --- a/x/stakeibc/keeper/unbonding_records_get_host_zone_unbondings_msgs_test.go +++ b/x/stakeibc/keeper/unbonding_records_get_host_zone_unbondings_msgs_test.go @@ -35,7 +35,7 @@ func (s *KeeperTestSuite) SetupTestUnbondFromHostZone( unbondAmount sdkmath.Int, validators []*types.Validator, ) UnbondingTestCase { - delegationAccountOwner := types.FormatICAAccountOwner(HostChainId, types.ICAAccountType_DELEGATION) + delegationAccountOwner := types.FormatHostZoneICAOwner(HostChainId, types.ICAAccountType_DELEGATION) delegationChannelID, delegationPortID := s.CreateICAChannel(delegationAccountOwner) // Sanity checks: diff --git a/x/stakeibc/keeper/undelegate_host_test.go b/x/stakeibc/keeper/undelegate_host_test.go index e90dda9a70..4c82a84a3b 100644 --- a/x/stakeibc/keeper/undelegate_host_test.go +++ b/x/stakeibc/keeper/undelegate_host_test.go @@ -22,7 +22,7 @@ func (s *KeeperTestSuite) SetupTestUndelegateHost( unbondAmount sdkmath.Int, validators []*types.Validator, ) UnbondingTestCase { - delegationAccountOwner := types.FormatICAAccountOwner(UndelegateHostZoneChainId, types.ICAAccountType_DELEGATION) + delegationAccountOwner := types.FormatHostZoneICAOwner(UndelegateHostZoneChainId, types.ICAAccountType_DELEGATION) delegationChannelID, delegationPortID := s.CreateICAChannel(delegationAccountOwner) // Sanity checks: diff --git a/x/stakeibc/types/callbacks.pb.go b/x/stakeibc/types/callbacks.pb.go index df6f758ae8..18652683b0 100644 --- a/x/stakeibc/types/callbacks.pb.go +++ b/x/stakeibc/types/callbacks.pb.go @@ -743,6 +743,58 @@ func (m *CommunityPoolBalanceQueryCallback) GetDenom() string { return "" } +type TradeRouteCallback struct { + RewardDenom string `protobuf:"bytes,1,opt,name=reward_denom,json=rewardDenom,proto3" json:"reward_denom,omitempty"` + HostDenom string `protobuf:"bytes,2,opt,name=host_denom,json=hostDenom,proto3" json:"host_denom,omitempty"` +} + +func (m *TradeRouteCallback) Reset() { *m = TradeRouteCallback{} } +func (m *TradeRouteCallback) String() string { return proto.CompactTextString(m) } +func (*TradeRouteCallback) ProtoMessage() {} +func (*TradeRouteCallback) Descriptor() ([]byte, []int) { + return fileDescriptor_f41c99b09b96a5ac, []int{14} +} +func (m *TradeRouteCallback) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TradeRouteCallback) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TradeRouteCallback.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TradeRouteCallback) XXX_Merge(src proto.Message) { + xxx_messageInfo_TradeRouteCallback.Merge(m, src) +} +func (m *TradeRouteCallback) XXX_Size() int { + return m.Size() +} +func (m *TradeRouteCallback) XXX_DiscardUnknown() { + xxx_messageInfo_TradeRouteCallback.DiscardUnknown(m) +} + +var xxx_messageInfo_TradeRouteCallback proto.InternalMessageInfo + +func (m *TradeRouteCallback) GetRewardDenom() string { + if m != nil { + return m.RewardDenom + } + return "" +} + +func (m *TradeRouteCallback) GetHostDenom() string { + if m != nil { + return m.HostDenom + } + return "" +} + func init() { proto.RegisterType((*SplitDelegation)(nil), "stride.stakeibc.SplitDelegation") proto.RegisterType((*DelegateCallback)(nil), "stride.stakeibc.DelegateCallback") @@ -758,70 +810,73 @@ func init() { proto.RegisterType((*ValidatorSharesToTokensQueryCallback)(nil), "stride.stakeibc.ValidatorSharesToTokensQueryCallback") proto.RegisterType((*DelegatorSharesQueryCallback)(nil), "stride.stakeibc.DelegatorSharesQueryCallback") proto.RegisterType((*CommunityPoolBalanceQueryCallback)(nil), "stride.stakeibc.CommunityPoolBalanceQueryCallback") + proto.RegisterType((*TradeRouteCallback)(nil), "stride.stakeibc.TradeRouteCallback") } func init() { proto.RegisterFile("stride/stakeibc/callbacks.proto", fileDescriptor_f41c99b09b96a5ac) } var fileDescriptor_f41c99b09b96a5ac = []byte{ - // 913 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcd, 0x6e, 0xdc, 0x36, - 0x17, 0xb5, 0x3c, 0xf9, 0x62, 0xfb, 0x7a, 0xfc, 0x27, 0x04, 0xf9, 0xc6, 0x83, 0xc1, 0x8c, 0xad, - 0x14, 0x6d, 0x50, 0x20, 0x12, 0xec, 0x02, 0x41, 0x7f, 0x36, 0xb1, 0xc7, 0x28, 0x32, 0xc0, 0xb8, - 0x68, 0x35, 0x76, 0x17, 0xd9, 0x08, 0x94, 0x48, 0xcc, 0x10, 0x96, 0xc8, 0x89, 0x48, 0x39, 0x75, - 0x9e, 0xa0, 0xcb, 0x6c, 0xfb, 0x08, 0xed, 0xa6, 0x4f, 0xd0, 0x4d, 0x57, 0x59, 0x66, 0x59, 0x74, - 0x91, 0x16, 0xf6, 0x8b, 0x14, 0xa4, 0xa8, 0x9f, 0x19, 0xa7, 0x41, 0xed, 0x76, 0x25, 0xe9, 0xf2, - 0x90, 0xf7, 0x9e, 0x73, 0x78, 0x49, 0x41, 0x4f, 0xc8, 0x94, 0x62, 0xe2, 0x09, 0x89, 0xce, 0x08, - 0x0d, 0x23, 0x2f, 0x42, 0x71, 0x1c, 0xa2, 0xe8, 0x4c, 0xb8, 0xd3, 0x94, 0x4b, 0x6e, 0x6f, 0xe4, - 0x00, 0xb7, 0x00, 0xb4, 0xef, 0x8d, 0xf9, 0x98, 0xeb, 0x31, 0x4f, 0xbd, 0xe5, 0xb0, 0x76, 0x37, - 0xe2, 0x22, 0xe1, 0xc2, 0x0b, 0x91, 0x20, 0xde, 0xf9, 0x5e, 0x48, 0x24, 0xda, 0xf3, 0x22, 0x4e, - 0x99, 0x19, 0xef, 0x98, 0x3c, 0x29, 0x89, 0x78, 0x8a, 0x45, 0xf1, 0x34, 0xa3, 0xd7, 0xaa, 0x98, - 0x70, 0x21, 0x83, 0x97, 0x9c, 0x91, 0xbf, 0x03, 0x9c, 0xa3, 0x98, 0x62, 0x24, 0x79, 0x6a, 0x00, - 0xbb, 0xf3, 0x00, 0x1a, 0xa1, 0x00, 0x45, 0x11, 0xcf, 0x98, 0xcc, 0x21, 0xce, 0x0b, 0xd8, 0x18, - 0x4d, 0x63, 0x2a, 0x8f, 0x48, 0x4c, 0xc6, 0x48, 0x52, 0xce, 0xec, 0x0e, 0xac, 0x94, 0x0b, 0xb5, - 0xac, 0x1d, 0xeb, 0xe1, 0x8a, 0x5f, 0x05, 0xec, 0x2f, 0xe1, 0x2e, 0x4a, 0xd4, 0x02, 0xad, 0x45, - 0x35, 0x74, 0xe8, 0xbe, 0x7e, 0xdb, 0x5b, 0xf8, 0xfd, 0x6d, 0xef, 0xc3, 0x31, 0x95, 0x93, 0x2c, - 0x74, 0x23, 0x9e, 0x78, 0x86, 0x76, 0xfe, 0x78, 0x24, 0xf0, 0x99, 0x27, 0x2f, 0xa6, 0x44, 0xb8, - 0x03, 0x26, 0x7d, 0x33, 0xdb, 0xf9, 0xd9, 0x82, 0x4d, 0x93, 0x94, 0xf4, 0x8d, 0xbc, 0xf6, 0x0e, - 0x34, 0x4b, 0x92, 0x01, 0xc5, 0x26, 0x3b, 0xa8, 0xd8, 0x33, 0xce, 0xc8, 0x00, 0xdb, 0x1f, 0xc3, - 0x16, 0x26, 0x53, 0x2e, 0xa8, 0x0c, 0x72, 0xb5, 0x14, 0x4c, 0x55, 0x72, 0xc7, 0xdf, 0x30, 0x03, - 0xbe, 0x8e, 0x0f, 0xb0, 0x7d, 0x0c, 0x5b, 0x42, 0x71, 0x0b, 0x70, 0x49, 0x4e, 0xb4, 0x1a, 0x3b, - 0x8d, 0x87, 0xab, 0xfb, 0x3b, 0xee, 0x9c, 0x83, 0xee, 0x9c, 0x0a, 0xfe, 0xa6, 0x98, 0x0d, 0x08, - 0xe7, 0x7b, 0x0b, 0xd6, 0xfa, 0x31, 0xa2, 0x49, 0x59, 0xee, 0x67, 0xb0, 0x9d, 0x09, 0x92, 0x06, - 0x29, 0xc1, 0x24, 0x99, 0x2a, 0x54, 0xad, 0xa8, 0xbc, 0xf6, 0xfb, 0x0a, 0xe0, 0x97, 0xe3, 0x65, - 0x6d, 0xdb, 0xb0, 0x1c, 0x4d, 0x10, 0x65, 0x45, 0xf9, 0x2b, 0xfe, 0x92, 0xfe, 0x1e, 0x60, 0x7b, - 0x17, 0x9a, 0x64, 0xca, 0xa3, 0x49, 0xc0, 0xb2, 0x24, 0x24, 0x69, 0xab, 0xa1, 0xd9, 0xad, 0xea, - 0xd8, 0x57, 0x3a, 0xe4, 0xfc, 0x68, 0xc1, 0xa6, 0x4f, 0x28, 0x3b, 0x27, 0x42, 0x96, 0xd5, 0x08, - 0xd8, 0x48, 0x4d, 0x2c, 0x30, 0x16, 0xa9, 0x1a, 0x56, 0xf7, 0xb7, 0xdd, 0xdc, 0x09, 0x57, 0xed, - 0x43, 0xd7, 0xec, 0x43, 0xb7, 0xcf, 0x29, 0x3b, 0xf4, 0x94, 0x7b, 0x3f, 0xfd, 0xd1, 0xfb, 0xe8, - 0x1f, 0xb8, 0xa7, 0x26, 0xf8, 0xeb, 0x45, 0x8a, 0x03, 0x9d, 0xe1, 0x9a, 0x63, 0x8d, 0x79, 0xc7, - 0x9c, 0x5f, 0x2d, 0xb0, 0x4f, 0x19, 0xbe, 0xb9, 0xd5, 0xef, 0xb4, 0x6f, 0xf1, 0xb6, 0xf6, 0xd9, - 0x5f, 0x40, 0x3b, 0x97, 0x35, 0x63, 0x21, 0x67, 0x98, 0xb2, 0x71, 0x65, 0x56, 0xbe, 0x2d, 0xee, - 0xf8, 0xff, 0xd7, 0x88, 0xd3, 0x02, 0x50, 0xb8, 0x25, 0x94, 0xe0, 0xf7, 0x2b, 0x12, 0x4f, 0x79, - 0x4d, 0xf6, 0x27, 0xd0, 0x40, 0x49, 0x2e, 0xf5, 0xcd, 0xbb, 0x41, 0x4d, 0xfd, 0x8f, 0x89, 0x3a, - 0x02, 0xec, 0x6a, 0xc3, 0xdd, 0x40, 0xef, 0xf7, 0x0b, 0xb4, 0xf8, 0x7e, 0x81, 0x7e, 0xb0, 0x60, - 0xd5, 0x27, 0x21, 0x8a, 0x11, 0x8b, 0x28, 0x1b, 0xdb, 0x0f, 0x60, 0x4d, 0xa4, 0x51, 0x30, 0x7f, - 0x90, 0x34, 0x45, 0x1a, 0x7d, 0x5b, 0x9e, 0x25, 0x0f, 0x60, 0x0d, 0x0b, 0x59, 0x03, 0xe5, 0x9d, - 0xd0, 0xc4, 0x42, 0x56, 0x20, 0xa3, 0x6f, 0xe3, 0xd6, 0xfa, 0x3a, 0x2f, 0x60, 0xab, 0x28, 0xed, - 0x26, 0xfb, 0xef, 0x09, 0x34, 0xd3, 0x8a, 0x51, 0xe1, 0x48, 0xe7, 0x9a, 0x23, 0x35, 0xda, 0xfe, - 0xcc, 0x0c, 0xe7, 0x14, 0x5a, 0x47, 0x44, 0xf2, 0x33, 0xc2, 0xe8, 0x4b, 0x32, 0x9a, 0xa0, 0x94, - 0x88, 0xda, 0xd9, 0xb1, 0x64, 0xce, 0x2b, 0xd3, 0xa5, 0xbd, 0x62, 0xe1, 0xe2, 0x16, 0x18, 0x8e, - 0x8e, 0x4f, 0xd4, 0xdc, 0x23, 0x73, 0xac, 0x15, 0x78, 0xe7, 0x17, 0x0b, 0xd6, 0x87, 0xa3, 0xe3, - 0x21, 0x7d, 0x9e, 0x51, 0x3c, 0x52, 0x65, 0xfc, 0x8b, 0xd5, 0xec, 0xc7, 0xb0, 0x52, 0x0a, 0xa1, - 0x0d, 0x50, 0x07, 0xc6, 0x3c, 0xc7, 0xa7, 0x46, 0x16, 0x7f, 0xb9, 0x10, 0xc8, 0xfe, 0xb4, 0x7e, - 0x4d, 0x34, 0xf4, 0xbc, 0xf6, 0xb5, 0x79, 0xa5, 0x8d, 0xb5, 0x2b, 0xc4, 0x79, 0x0e, 0x1f, 0x94, - 0xf1, 0x5c, 0x95, 0x13, 0xae, 0x6b, 0x13, 0xdf, 0x64, 0x24, 0xbd, 0x28, 0x25, 0x1a, 0xc0, 0x66, - 0x2c, 0x92, 0x20, 0xd6, 0x3c, 0x03, 0xbd, 0xe6, 0x3c, 0xbb, 0x32, 0xd1, 0xac, 0x1e, 0xfe, 0x7a, - 0x2c, 0x92, 0xda, 0xb7, 0xf3, 0xca, 0x82, 0x8e, 0xe9, 0x91, 0x22, 0xe7, 0x6c, 0xae, 0x29, 0x74, - 0x28, 0xa3, 0x92, 0xa2, 0xb8, 0xda, 0x8e, 0xb5, 0x7e, 0xbc, 0x65, 0x7b, 0xb7, 0xcd, 0x9a, 0x25, - 0xdd, 0xaa, 0x4f, 0x9d, 0x0c, 0x76, 0xfb, 0x3c, 0x49, 0x32, 0x46, 0xe5, 0xc5, 0xd7, 0x9c, 0xc7, - 0x87, 0xf9, 0x06, 0x9d, 0x2d, 0xeb, 0x73, 0x58, 0x56, 0x77, 0xb6, 0x5a, 0x51, 0x97, 0xb0, 0xfe, - 0x0e, 0xea, 0x83, 0xfe, 0xc1, 0x41, 0x7e, 0xa7, 0x9f, 0x5c, 0x4c, 0x89, 0xbf, 0x44, 0x23, 0xa4, - 0x5e, 0xec, 0x7b, 0xf0, 0x3f, 0x4c, 0x18, 0x4f, 0x4c, 0x57, 0xe5, 0x1f, 0x87, 0xc3, 0xd7, 0x97, - 0x5d, 0xeb, 0xcd, 0x65, 0xd7, 0xfa, 0xf3, 0xb2, 0x6b, 0xbd, 0xba, 0xea, 0x2e, 0xbc, 0xb9, 0xea, - 0x2e, 0xfc, 0x76, 0xd5, 0x5d, 0x78, 0xb6, 0x5f, 0x23, 0x35, 0xd2, 0x39, 0x1e, 0x0d, 0x51, 0x28, - 0x3c, 0xf3, 0x13, 0x71, 0xbe, 0xf7, 0xd8, 0xfb, 0xae, 0xfa, 0x95, 0xd0, 0x24, 0xc3, 0xbb, 0xfa, - 0x2f, 0xe2, 0x93, 0xbf, 0x02, 0x00, 0x00, 0xff, 0xff, 0x60, 0x7b, 0xe9, 0xf9, 0x32, 0x09, 0x00, - 0x00, + // 953 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xcf, 0x6e, 0xdb, 0xc6, + 0x13, 0x36, 0xad, 0xfc, 0x62, 0x7b, 0x24, 0xff, 0x23, 0x82, 0xfc, 0x64, 0x41, 0x95, 0x6c, 0xa6, + 0x68, 0x83, 0x02, 0x21, 0x61, 0x17, 0x08, 0xfa, 0xe7, 0x12, 0x5b, 0x46, 0x11, 0x01, 0x72, 0xd1, + 0x52, 0x76, 0x0e, 0xb9, 0x10, 0x4b, 0xee, 0x42, 0x5a, 0x98, 0xdc, 0x55, 0xb8, 0x4b, 0xbb, 0xce, + 0x13, 0xf4, 0x98, 0x6b, 0x1f, 0xa1, 0xbd, 0xf4, 0x09, 0x7a, 0xe9, 0x29, 0xc7, 0x1c, 0x8b, 0x1e, + 0xd2, 0xc2, 0x7e, 0x91, 0x62, 0x97, 0x4b, 0x8a, 0x92, 0xd3, 0xa0, 0x76, 0x7b, 0x22, 0x39, 0x3b, + 0x3b, 0xf3, 0xcd, 0xf7, 0xcd, 0xec, 0x12, 0xba, 0x42, 0xa6, 0x14, 0x13, 0x4f, 0x48, 0x74, 0x4a, + 0x68, 0x18, 0x79, 0x11, 0x8a, 0xe3, 0x10, 0x45, 0xa7, 0xc2, 0x9d, 0xa4, 0x5c, 0x72, 0x7b, 0x3d, + 0x77, 0x70, 0x0b, 0x87, 0xd6, 0xbd, 0x11, 0x1f, 0x71, 0xbd, 0xe6, 0xa9, 0xb7, 0xdc, 0xad, 0xd5, + 0x89, 0xb8, 0x48, 0xb8, 0xf0, 0x42, 0x24, 0x88, 0x77, 0xb6, 0x1b, 0x12, 0x89, 0x76, 0xbd, 0x88, + 0x53, 0x66, 0xd6, 0xdb, 0x26, 0x4f, 0x4a, 0x22, 0x9e, 0x62, 0x51, 0x3c, 0xcd, 0xea, 0x35, 0x14, + 0x63, 0x2e, 0x64, 0xf0, 0x92, 0x33, 0xf2, 0x77, 0x0e, 0x67, 0x28, 0xa6, 0x18, 0x49, 0x9e, 0x1a, + 0x87, 0x9d, 0x79, 0x07, 0x1a, 0xa1, 0x00, 0x45, 0x11, 0xcf, 0x98, 0xcc, 0x5d, 0x9c, 0x73, 0x58, + 0x1f, 0x4e, 0x62, 0x2a, 0x0f, 0x49, 0x4c, 0x46, 0x48, 0x52, 0xce, 0xec, 0x36, 0xac, 0x94, 0x81, + 0x9a, 0xd6, 0xb6, 0xf5, 0x70, 0xc5, 0x9f, 0x1a, 0xec, 0xaf, 0xe0, 0x2e, 0x4a, 0x54, 0x80, 0xe6, + 0xa2, 0x5a, 0x3a, 0x70, 0x5f, 0xbf, 0xed, 0x2e, 0xfc, 0xfe, 0xb6, 0xfb, 0xd1, 0x88, 0xca, 0x71, + 0x16, 0xba, 0x11, 0x4f, 0x3c, 0x53, 0x76, 0xfe, 0x78, 0x24, 0xf0, 0xa9, 0x27, 0x2f, 0x26, 0x44, + 0xb8, 0x7d, 0x26, 0x7d, 0xb3, 0xdb, 0xf9, 0xd9, 0x82, 0x0d, 0x93, 0x94, 0xf4, 0x0c, 0xbd, 0xf6, + 0x36, 0x34, 0xca, 0x22, 0x03, 0x8a, 0x4d, 0x76, 0x50, 0xb6, 0xe7, 0x9c, 0x91, 0x3e, 0xb6, 0x3f, + 0x81, 0x4d, 0x4c, 0x26, 0x5c, 0x50, 0x19, 0xe4, 0x6c, 0x29, 0x37, 0x85, 0xe4, 0x8e, 0xbf, 0x6e, + 0x16, 0x7c, 0x6d, 0xef, 0x63, 0xfb, 0x08, 0x36, 0x85, 0xaa, 0x2d, 0xc0, 0x65, 0x71, 0xa2, 0x59, + 0xdb, 0xae, 0x3d, 0xac, 0xef, 0x6d, 0xbb, 0x73, 0x0a, 0xba, 0x73, 0x2c, 0xf8, 0x1b, 0x62, 0xd6, + 0x20, 0x9c, 0xef, 0x2d, 0x58, 0xed, 0xc5, 0x88, 0x26, 0x25, 0xdc, 0xcf, 0x61, 0x2b, 0x13, 0x24, + 0x0d, 0x52, 0x82, 0x49, 0x32, 0x51, 0x5e, 0x15, 0x50, 0x39, 0xf6, 0xfb, 0xca, 0xc1, 0x2f, 0xd7, + 0x4b, 0x6c, 0x5b, 0xb0, 0x1c, 0x8d, 0x11, 0x65, 0x05, 0xfc, 0x15, 0x7f, 0x49, 0x7f, 0xf7, 0xb1, + 0xbd, 0x03, 0x0d, 0x32, 0xe1, 0xd1, 0x38, 0x60, 0x59, 0x12, 0x92, 0xb4, 0x59, 0xd3, 0xd5, 0xd5, + 0xb5, 0xed, 0x6b, 0x6d, 0x72, 0x7e, 0xb4, 0x60, 0xc3, 0x27, 0x94, 0x9d, 0x11, 0x21, 0x4b, 0x34, + 0x02, 0xd6, 0x53, 0x63, 0x0b, 0x8c, 0x44, 0x0a, 0x43, 0x7d, 0x6f, 0xcb, 0xcd, 0x95, 0x70, 0x55, + 0x1f, 0xba, 0xa6, 0x0f, 0xdd, 0x1e, 0xa7, 0xec, 0xc0, 0x53, 0xea, 0xfd, 0xf4, 0x47, 0xf7, 0xe3, + 0x7f, 0xa0, 0x9e, 0xda, 0xe0, 0xaf, 0x15, 0x29, 0xf6, 0x75, 0x86, 0x6b, 0x8a, 0xd5, 0xe6, 0x15, + 0x73, 0x7e, 0xb5, 0xc0, 0x3e, 0x61, 0xf8, 0xe6, 0x52, 0xbf, 0x53, 0xbe, 0xc5, 0xdb, 0xca, 0x67, + 0x7f, 0x09, 0xad, 0x9c, 0xd6, 0x8c, 0x85, 0x9c, 0x61, 0xca, 0x46, 0x53, 0xb1, 0xf2, 0xb6, 0xb8, + 0xe3, 0xff, 0x5f, 0x7b, 0x9c, 0x14, 0x0e, 0x85, 0x5a, 0x42, 0x11, 0x7e, 0x7f, 0x5a, 0xc4, 0x53, + 0x5e, 0xa1, 0xfd, 0x09, 0xd4, 0x50, 0x92, 0x53, 0x7d, 0xf3, 0x69, 0x50, 0x5b, 0xff, 0xe3, 0x42, + 0x1d, 0x01, 0xf6, 0xb4, 0xe1, 0x6e, 0xc0, 0xf7, 0xfb, 0x09, 0x5a, 0x7c, 0x3f, 0x41, 0x3f, 0x58, + 0x50, 0xf7, 0x49, 0x88, 0x62, 0xc4, 0x22, 0xca, 0x46, 0xf6, 0x03, 0x58, 0x15, 0x69, 0x14, 0xcc, + 0x1f, 0x24, 0x0d, 0x91, 0x46, 0xcf, 0xca, 0xb3, 0xe4, 0x01, 0xac, 0x62, 0x21, 0x2b, 0x4e, 0xf9, + 0x24, 0x34, 0xb0, 0x90, 0x53, 0x27, 0xc3, 0x6f, 0xed, 0xd6, 0xfc, 0x3a, 0xe7, 0xb0, 0x59, 0x40, + 0xbb, 0x49, 0xff, 0x3d, 0x81, 0x46, 0x3a, 0xad, 0xa8, 0x50, 0xa4, 0x7d, 0x4d, 0x91, 0x4a, 0xd9, + 0xfe, 0xcc, 0x0e, 0xe7, 0x04, 0x9a, 0x87, 0x44, 0xf2, 0x53, 0xc2, 0xe8, 0x4b, 0x32, 0x1c, 0xa3, + 0x94, 0x88, 0xca, 0xd9, 0xb1, 0x64, 0xce, 0x2b, 0x33, 0xa5, 0xdd, 0x22, 0x70, 0x71, 0x0b, 0x0c, + 0x86, 0x47, 0xc7, 0x6a, 0xef, 0xa1, 0x39, 0xd6, 0x0a, 0x7f, 0xe7, 0x17, 0x0b, 0xd6, 0x06, 0xc3, + 0xa3, 0x01, 0x7d, 0x91, 0x51, 0x3c, 0x54, 0x30, 0xfe, 0x45, 0x34, 0xfb, 0x31, 0xac, 0x94, 0x44, + 0x68, 0x01, 0xd4, 0x81, 0x31, 0x5f, 0xe3, 0x53, 0x43, 0x8b, 0xbf, 0x5c, 0x10, 0x64, 0x7f, 0x56, + 0xbd, 0x26, 0x6a, 0x7a, 0x5f, 0xeb, 0xda, 0xbe, 0x52, 0xc6, 0xca, 0x15, 0xe2, 0xbc, 0x80, 0x0f, + 0x4b, 0x7b, 0xce, 0xca, 0x31, 0xd7, 0xd8, 0xc4, 0xb7, 0x19, 0x49, 0x2f, 0x4a, 0x8a, 0xfa, 0xb0, + 0x11, 0x8b, 0x24, 0x88, 0x75, 0x9d, 0x81, 0x8e, 0x39, 0x5f, 0x5d, 0x99, 0x68, 0x96, 0x0f, 0x7f, + 0x2d, 0x16, 0x49, 0xe5, 0xdb, 0x79, 0x65, 0x41, 0xdb, 0xcc, 0x48, 0x91, 0x73, 0x36, 0xd7, 0x04, + 0xda, 0x94, 0x51, 0x49, 0x51, 0x3c, 0x6d, 0xc7, 0xca, 0x3c, 0xde, 0x72, 0xbc, 0x5b, 0x26, 0x66, + 0x59, 0xee, 0x74, 0x4e, 0x9d, 0x0c, 0x76, 0x7a, 0x3c, 0x49, 0x32, 0x46, 0xe5, 0xc5, 0x37, 0x9c, + 0xc7, 0x07, 0x79, 0x83, 0xce, 0xc2, 0xfa, 0x02, 0x96, 0xd5, 0x9d, 0xad, 0x22, 0x6a, 0x08, 0x6b, + 0xef, 0x28, 0xbd, 0xdf, 0xdb, 0xdf, 0xcf, 0xef, 0xf4, 0xe3, 0x8b, 0x09, 0xf1, 0x97, 0x68, 0x84, + 0xd4, 0x8b, 0x7d, 0x0f, 0xfe, 0x87, 0x09, 0xe3, 0x89, 0x99, 0xaa, 0xfc, 0xc3, 0x79, 0x06, 0xf6, + 0x71, 0x8a, 0x30, 0xf1, 0x79, 0x56, 0x39, 0x8d, 0x77, 0x54, 0xaf, 0x9f, 0xa3, 0x14, 0x07, 0xf9, + 0x96, 0x7c, 0x1a, 0xea, 0xb9, 0xed, 0x50, 0x99, 0xec, 0x0f, 0x40, 0x0f, 0x47, 0x50, 0x8d, 0xa9, + 0x3b, 0x47, 0x2f, 0x1f, 0x0c, 0x5e, 0x5f, 0x76, 0xac, 0x37, 0x97, 0x1d, 0xeb, 0xcf, 0xcb, 0x8e, + 0xf5, 0xea, 0xaa, 0xb3, 0xf0, 0xe6, 0xaa, 0xb3, 0xf0, 0xdb, 0x55, 0x67, 0xe1, 0xf9, 0x5e, 0x85, + 0xac, 0xa1, 0xc6, 0xfe, 0x68, 0x80, 0x42, 0xe1, 0x99, 0x9f, 0x93, 0xb3, 0xdd, 0xc7, 0xde, 0x77, + 0xd3, 0x5f, 0x14, 0x4d, 0x5e, 0x78, 0x57, 0xff, 0x9d, 0x7c, 0xfa, 0x57, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x88, 0x27, 0x41, 0x11, 0x8a, 0x09, 0x00, 0x00, } func (m *SplitDelegation) Marshal() (dAtA []byte, err error) { @@ -1440,6 +1495,43 @@ func (m *CommunityPoolBalanceQueryCallback) MarshalToSizedBuffer(dAtA []byte) (i return len(dAtA) - i, nil } +func (m *TradeRouteCallback) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TradeRouteCallback) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TradeRouteCallback) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.HostDenom) > 0 { + i -= len(m.HostDenom) + copy(dAtA[i:], m.HostDenom) + i = encodeVarintCallbacks(dAtA, i, uint64(len(m.HostDenom))) + i-- + dAtA[i] = 0x12 + } + if len(m.RewardDenom) > 0 { + i -= len(m.RewardDenom) + copy(dAtA[i:], m.RewardDenom) + i = encodeVarintCallbacks(dAtA, i, uint64(len(m.RewardDenom))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintCallbacks(dAtA []byte, offset int, v uint64) int { offset -= sovCallbacks(v) base := offset @@ -1698,6 +1790,23 @@ func (m *CommunityPoolBalanceQueryCallback) Size() (n int) { return n } +func (m *TradeRouteCallback) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RewardDenom) + if l > 0 { + n += 1 + l + sovCallbacks(uint64(l)) + } + l = len(m.HostDenom) + if l > 0 { + n += 1 + l + sovCallbacks(uint64(l)) + } + return n +} + func sovCallbacks(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -3450,6 +3559,120 @@ func (m *CommunityPoolBalanceQueryCallback) Unmarshal(dAtA []byte) error { } return nil } +func (m *TradeRouteCallback) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCallbacks + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TradeRouteCallback: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TradeRouteCallback: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCallbacks + } + 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 ErrInvalidLengthCallbacks + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCallbacks + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCallbacks + } + 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 ErrInvalidLengthCallbacks + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCallbacks + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCallbacks(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCallbacks + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipCallbacks(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/stakeibc/types/errors.go b/x/stakeibc/types/errors.go index 81f26ed769..76c75791a0 100644 --- a/x/stakeibc/types/errors.go +++ b/x/stakeibc/types/errors.go @@ -60,4 +60,8 @@ var ( ErrHostZoneNotHalted = errorsmod.Register(ModuleName, 1553, "host zone is not halted") ErrFailedToLiquidStake = errorsmod.Register(ModuleName, 1554, "Failed to liquid stake") ErrUnableToRedeemStake = errorsmod.Register(ModuleName, 1555, "Failed to redeem stake") + ErrInvalidDenom = errorsmod.Register(ModuleName, 1556, "Invalid denom") + ErrTradeRouteAlreadyExists = errorsmod.Register(ModuleName, 1557, "Trade route already exists") + ErrClientStateNotTendermint = errorsmod.Register(ModuleName, 1558, "Client state not tendermint") + ErrTradeRouteNotFound = errorsmod.Register(ModuleName, 1559, "trade route not found") ) diff --git a/x/stakeibc/types/ica_account.go b/x/stakeibc/types/ica_account.go index 4a14ccb2d8..f3d7e57539 100644 --- a/x/stakeibc/types/ica_account.go +++ b/x/stakeibc/types/ica_account.go @@ -1,5 +1,21 @@ package types -func FormatICAAccountOwner(chainId string, accountType ICAAccountType) (result string) { +import fmt "fmt" + +// Helper function to build the host zone ICA owner in the form "{chainId}.{ICA_TYPE}" +func FormatHostZoneICAOwner(chainId string, accountType ICAAccountType) (result string) { return chainId + "." + accountType.String() } + +// Helper function to build the ICA owner for a trade route ICA +// in the form "{chainId}.{rewardDenom}-{hostDenom}.{ICA_TYPE}" +func FormatTradeRouteICAOwner(chainId, rewardDenom, hostDenom string, icaAccountType ICAAccountType) string { + tradeRouteId := GetTradeRouteId(rewardDenom, hostDenom) + return FormatTradeRouteICAOwnerFromRouteId(chainId, tradeRouteId, icaAccountType) +} + +// Helper function to build the ICA owner for a trade route ICA +// in the form "{chainId}.{tradeRouteId}.{ICA_TYPE}" +func FormatTradeRouteICAOwnerFromRouteId(chainId, tradeRouteId string, icaAccountType ICAAccountType) string { + return fmt.Sprintf("%s.%s.%s", chainId, tradeRouteId, icaAccountType.String()) +} diff --git a/x/stakeibc/types/ica_account.pb.go b/x/stakeibc/types/ica_account.pb.go index de393fe94f..656e7167da 100644 --- a/x/stakeibc/types/ica_account.pb.go +++ b/x/stakeibc/types/ica_account.pb.go @@ -6,7 +6,9 @@ package types import ( fmt "fmt" proto "github.com/cosmos/gogoproto/proto" + io "io" math "math" + math_bits "math/bits" ) // Reference imports to suppress errors if they are not otherwise used. @@ -29,6 +31,8 @@ const ( ICAAccountType_REDEMPTION ICAAccountType = 3 ICAAccountType_COMMUNITY_POOL_DEPOSIT ICAAccountType = 4 ICAAccountType_COMMUNITY_POOL_RETURN ICAAccountType = 5 + ICAAccountType_CONVERTER_UNWIND ICAAccountType = 6 + ICAAccountType_CONVERTER_TRADE ICAAccountType = 7 ) var ICAAccountType_name = map[int32]string{ @@ -38,6 +42,8 @@ var ICAAccountType_name = map[int32]string{ 3: "REDEMPTION", 4: "COMMUNITY_POOL_DEPOSIT", 5: "COMMUNITY_POOL_RETURN", + 6: "CONVERTER_UNWIND", + 7: "CONVERTER_TRADE", } var ICAAccountType_value = map[string]int32{ @@ -47,6 +53,8 @@ var ICAAccountType_value = map[string]int32{ "REDEMPTION": 3, "COMMUNITY_POOL_DEPOSIT": 4, "COMMUNITY_POOL_RETURN": 5, + "CONVERTER_UNWIND": 6, + "CONVERTER_TRADE": 7, } func (x ICAAccountType) String() string { @@ -57,28 +65,444 @@ func (ICAAccountType) EnumDescriptor() ([]byte, []int) { return fileDescriptor_2976ae6e7f6ce824, []int{0} } +type ICAAccount struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + Type ICAAccountType `protobuf:"varint,2,opt,name=type,proto3,enum=stride.stakeibc.ICAAccountType" json:"type,omitempty"` + ConnectionId string `protobuf:"bytes,3,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` + Address string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` +} + +func (m *ICAAccount) Reset() { *m = ICAAccount{} } +func (m *ICAAccount) String() string { return proto.CompactTextString(m) } +func (*ICAAccount) ProtoMessage() {} +func (*ICAAccount) Descriptor() ([]byte, []int) { + return fileDescriptor_2976ae6e7f6ce824, []int{0} +} +func (m *ICAAccount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ICAAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ICAAccount.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ICAAccount) XXX_Merge(src proto.Message) { + xxx_messageInfo_ICAAccount.Merge(m, src) +} +func (m *ICAAccount) XXX_Size() int { + return m.Size() +} +func (m *ICAAccount) XXX_DiscardUnknown() { + xxx_messageInfo_ICAAccount.DiscardUnknown(m) +} + +var xxx_messageInfo_ICAAccount proto.InternalMessageInfo + +func (m *ICAAccount) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *ICAAccount) GetType() ICAAccountType { + if m != nil { + return m.Type + } + return ICAAccountType_DELEGATION +} + +func (m *ICAAccount) GetConnectionId() string { + if m != nil { + return m.ConnectionId + } + return "" +} + +func (m *ICAAccount) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + func init() { proto.RegisterEnum("stride.stakeibc.ICAAccountType", ICAAccountType_name, ICAAccountType_value) + proto.RegisterType((*ICAAccount)(nil), "stride.stakeibc.ICAAccount") } func init() { proto.RegisterFile("stride/stakeibc/ica_account.proto", fileDescriptor_2976ae6e7f6ce824) } var fileDescriptor_2976ae6e7f6ce824 = []byte{ - // 242 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x2c, 0x2e, 0x29, 0xca, - 0x4c, 0x49, 0xd5, 0x2f, 0x2e, 0x49, 0xcc, 0x4e, 0xcd, 0x4c, 0x4a, 0xd6, 0xcf, 0x4c, 0x4e, 0x8c, - 0x4f, 0x4c, 0x4e, 0xce, 0x2f, 0xcd, 0x2b, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x87, - 0x28, 0xd1, 0x83, 0x29, 0xd1, 0x6a, 0x60, 0xe4, 0xe2, 0xf3, 0x74, 0x76, 0x74, 0x84, 0xa8, 0x0a, - 0xa9, 0x2c, 0x48, 0x15, 0xe2, 0xe3, 0xe2, 0x72, 0x71, 0xf5, 0x71, 0x75, 0x77, 0x0c, 0xf1, 0xf4, - 0xf7, 0x13, 0x60, 0x10, 0x62, 0xe7, 0x62, 0x76, 0x73, 0x75, 0x15, 0x60, 0x04, 0x49, 0x84, 0x7b, - 0x86, 0x78, 0xb8, 0x04, 0x39, 0x86, 0x3b, 0xfa, 0x08, 0x30, 0x81, 0xf8, 0x41, 0xae, 0x2e, 0xae, - 0xbe, 0x01, 0x60, 0x85, 0xcc, 0x42, 0x52, 0x5c, 0x62, 0xce, 0xfe, 0xbe, 0xbe, 0xa1, 0x7e, 0x9e, - 0x21, 0x91, 0xf1, 0x01, 0xfe, 0xfe, 0x3e, 0xf1, 0x2e, 0xae, 0x01, 0xfe, 0xc1, 0x9e, 0x21, 0x02, - 0x2c, 0x42, 0x92, 0x5c, 0xa2, 0x68, 0x72, 0x41, 0xae, 0x21, 0xa1, 0x41, 0x7e, 0x02, 0xac, 0x4e, - 0x3e, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, - 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, 0x94, 0x9e, 0x59, 0x92, - 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x1f, 0x0c, 0x76, 0xb8, 0xae, 0x4f, 0x62, 0x52, 0xb1, - 0x3e, 0xd4, 0x9f, 0x65, 0x86, 0x66, 0xfa, 0x15, 0x08, 0xdf, 0x96, 0x54, 0x16, 0xa4, 0x16, 0x27, - 0xb1, 0x81, 0x3d, 0x6a, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xb5, 0xd8, 0xf0, 0x0d, 0x01, - 0x00, 0x00, + // 366 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x91, 0xcf, 0x4e, 0xea, 0x40, + 0x14, 0xc6, 0x3b, 0xc0, 0xa5, 0xf7, 0x4e, 0xee, 0x85, 0xc9, 0xdc, 0x3f, 0x29, 0x77, 0x51, 0x51, + 0x37, 0xc4, 0xc4, 0x36, 0x42, 0xe2, 0xbe, 0xd2, 0x51, 0x27, 0x29, 0x2d, 0x19, 0x06, 0x89, 0x6e, + 0x9a, 0x76, 0xda, 0x48, 0x63, 0x6c, 0x09, 0x2d, 0x46, 0xde, 0xc2, 0xbd, 0x8f, 0xe0, 0x8b, 0xb8, + 0x64, 0xe9, 0xd2, 0xc0, 0x8b, 0x18, 0x0a, 0xa6, 0x91, 0xe5, 0x77, 0xce, 0x2f, 0xbf, 0x93, 0x9c, + 0x0f, 0xee, 0xa7, 0xd9, 0x34, 0x0a, 0x42, 0x3d, 0xcd, 0xbc, 0xbb, 0x30, 0xf2, 0x85, 0x1e, 0x09, + 0xcf, 0xf5, 0x84, 0x48, 0x66, 0x71, 0xa6, 0x4d, 0xa6, 0x49, 0x96, 0xe0, 0xfa, 0x06, 0xd1, 0x3e, + 0x91, 0x83, 0x67, 0x00, 0x21, 0xed, 0x1a, 0xc6, 0x86, 0xc2, 0x0d, 0xf8, 0x5d, 0x8c, 0xbd, 0x28, + 0x76, 0xa3, 0x40, 0x01, 0x4d, 0xd0, 0xfa, 0xc1, 0xe4, 0x3c, 0xd3, 0x00, 0x77, 0x60, 0x25, 0x9b, + 0x4f, 0x42, 0xa5, 0xd4, 0x04, 0xad, 0x5a, 0x7b, 0x4f, 0xdb, 0x31, 0x69, 0x85, 0x85, 0xcf, 0x27, + 0x21, 0xcb, 0x61, 0x7c, 0x08, 0x7f, 0x89, 0x24, 0x8e, 0x43, 0x91, 0x45, 0x49, 0x2e, 0x2d, 0xe7, + 0xd2, 0x9f, 0xc5, 0x90, 0x06, 0x58, 0x81, 0xb2, 0x17, 0x04, 0xd3, 0x30, 0x4d, 0x95, 0xca, 0xe6, + 0xe6, 0x36, 0x1e, 0xbd, 0x00, 0x58, 0xfb, 0xea, 0xc5, 0x35, 0x08, 0x4d, 0x62, 0x91, 0x0b, 0x83, + 0x53, 0xc7, 0x46, 0x12, 0x96, 0x61, 0xf9, 0x9c, 0x10, 0x04, 0xd6, 0x8b, 0x11, 0xe5, 0x97, 0x26, + 0x33, 0x46, 0x86, 0x85, 0x4a, 0xeb, 0xcc, 0x88, 0x49, 0x7a, 0xfd, 0x1c, 0x2c, 0xe3, 0xff, 0xf0, + 0x5f, 0xd7, 0xe9, 0xf5, 0x86, 0x36, 0xe5, 0xd7, 0x6e, 0xdf, 0x71, 0x2c, 0xd7, 0x24, 0x7d, 0x67, + 0x40, 0x39, 0xaa, 0xe0, 0x06, 0xfc, 0xbb, 0xb3, 0x63, 0x84, 0x0f, 0x99, 0x8d, 0xbe, 0xe1, 0x3f, + 0x10, 0x75, 0x1d, 0xfb, 0x8a, 0x30, 0x4e, 0x98, 0x3b, 0xb4, 0x47, 0xd4, 0x36, 0x51, 0x15, 0xff, + 0x86, 0xf5, 0x62, 0xca, 0x99, 0x61, 0x12, 0x24, 0x9f, 0x59, 0xaf, 0x4b, 0x15, 0x2c, 0x96, 0x2a, + 0x78, 0x5f, 0xaa, 0xe0, 0x69, 0xa5, 0x4a, 0x8b, 0x95, 0x2a, 0xbd, 0xad, 0x54, 0xe9, 0xa6, 0x7d, + 0x1b, 0x65, 0xe3, 0x99, 0xaf, 0x89, 0xe4, 0x5e, 0x1f, 0xe4, 0x7f, 0x3b, 0xb6, 0x3c, 0x3f, 0xd5, + 0xb7, 0x85, 0x3d, 0x9c, 0x9c, 0xea, 0x8f, 0x45, 0x6d, 0xeb, 0xcf, 0xa5, 0x7e, 0x35, 0x6f, 0xac, + 0xf3, 0x11, 0x00, 0x00, 0xff, 0xff, 0x44, 0x80, 0x94, 0xbd, 0xd6, 0x01, 0x00, 0x00, +} + +func (m *ICAAccount) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ICAAccount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ICAAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintIcaAccount(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0x22 + } + if len(m.ConnectionId) > 0 { + i -= len(m.ConnectionId) + copy(dAtA[i:], m.ConnectionId) + i = encodeVarintIcaAccount(dAtA, i, uint64(len(m.ConnectionId))) + i-- + dAtA[i] = 0x1a + } + if m.Type != 0 { + i = encodeVarintIcaAccount(dAtA, i, uint64(m.Type)) + i-- + dAtA[i] = 0x10 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintIcaAccount(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintIcaAccount(dAtA []byte, offset int, v uint64) int { + offset -= sovIcaAccount(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base } +func (m *ICAAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovIcaAccount(uint64(l)) + } + if m.Type != 0 { + n += 1 + sovIcaAccount(uint64(m.Type)) + } + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovIcaAccount(uint64(l)) + } + l = len(m.Address) + if l > 0 { + n += 1 + l + sovIcaAccount(uint64(l)) + } + return n +} + +func sovIcaAccount(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozIcaAccount(x uint64) (n int) { + return sovIcaAccount(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ICAAccount) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIcaAccount + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ICAAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ICAAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIcaAccount + } + 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 ErrInvalidLengthIcaAccount + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIcaAccount + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) + } + m.Type = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIcaAccount + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Type |= ICAAccountType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIcaAccount + } + 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 ErrInvalidLengthIcaAccount + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIcaAccount + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowIcaAccount + } + 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 ErrInvalidLengthIcaAccount + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthIcaAccount + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipIcaAccount(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthIcaAccount + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipIcaAccount(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowIcaAccount + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowIcaAccount + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowIcaAccount + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthIcaAccount + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupIcaAccount + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthIcaAccount + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthIcaAccount = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowIcaAccount = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupIcaAccount = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/stakeibc/types/ica_account_test.go b/x/stakeibc/types/ica_account_test.go new file mode 100644 index 0000000000..5a2965297a --- /dev/null +++ b/x/stakeibc/types/ica_account_test.go @@ -0,0 +1,81 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func TestFormatHostZoneICAOwner(t *testing.T) { + chainId := "chain-0" + + testCases := []struct { + accountType types.ICAAccountType + owner string + }{ + { + accountType: types.ICAAccountType_DELEGATION, + owner: "chain-0.DELEGATION", + }, + { + accountType: types.ICAAccountType_WITHDRAWAL, + owner: "chain-0.WITHDRAWAL", + }, + { + accountType: types.ICAAccountType_REDEMPTION, + owner: "chain-0.REDEMPTION", + }, + { + accountType: types.ICAAccountType_FEE, + owner: "chain-0.FEE", + }, + { + accountType: types.ICAAccountType_COMMUNITY_POOL_DEPOSIT, + owner: "chain-0.COMMUNITY_POOL_DEPOSIT", + }, + { + accountType: types.ICAAccountType_COMMUNITY_POOL_RETURN, + owner: "chain-0.COMMUNITY_POOL_RETURN", + }, + } + + for _, tc := range testCases { + t.Run(tc.accountType.String(), func(t *testing.T) { + actual := types.FormatHostZoneICAOwner(chainId, tc.accountType) + require.Equal(t, tc.owner, actual) + }) + } +} + +func TestFormatTradeRouteICAOwner(t *testing.T) { + chainId := "chain-0" + rewardDenom := "ureward" + hostDenom := "uhost" + + testCases := []struct { + accountType types.ICAAccountType + owner string + }{ + { + accountType: types.ICAAccountType_CONVERTER_UNWIND, + owner: "chain-0.ureward-uhost.CONVERTER_UNWIND", + }, + { + accountType: types.ICAAccountType_CONVERTER_TRADE, + owner: "chain-0.ureward-uhost.CONVERTER_TRADE", + }, + } + + for _, tc := range testCases { + t.Run(tc.accountType.String(), func(t *testing.T) { + actual := types.FormatTradeRouteICAOwner(chainId, rewardDenom, hostDenom, tc.accountType) + require.Equal(t, actual, tc.owner, "format trade route ICA owner") + + tradeRouteId := "ureward-uhost" + actual = types.FormatTradeRouteICAOwnerFromRouteId(chainId, tradeRouteId, tc.accountType) + require.Equal(t, actual, tc.owner, "format trade route ICA owner by account") + }) + } +} diff --git a/x/stakeibc/types/keys.go b/x/stakeibc/types/keys.go index df65fc1cda..36f8defe95 100644 --- a/x/stakeibc/types/keys.go +++ b/x/stakeibc/types/keys.go @@ -47,10 +47,18 @@ func EpochTrackerKey(epochIdentifier string) []byte { return key } +// Definition for the store key format based on tradeRoute start and end denoms +func TradeRouteKeyFromDenoms(rewardDenom, hostDenom string) (key []byte) { + return []byte(rewardDenom + "-" + hostDenom) +} + const ( // Host zone keys prefix the HostZone structs HostZoneKey = "HostZone-value-" // EpochTrackerKeyPrefix is the prefix to retrieve all EpochTracker EpochTrackerKeyPrefix = "EpochTracker/value/" + + // TradeRoute keys prefix to retrieve all TradeZones + TradeRouteKeyPrefix = "TradeRoute-value-" ) diff --git a/x/stakeibc/types/message_create_trade_route.go b/x/stakeibc/types/message_create_trade_route.go new file mode 100644 index 0000000000..b7a77ecf68 --- /dev/null +++ b/x/stakeibc/types/message_create_trade_route.go @@ -0,0 +1,139 @@ +package types + +import ( + "regexp" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" +) + +const TypeMsgCreateTradeRoute = "create_trade_route" + +const ( + ConnectionIdRegex = `^connection-\d+$` + ChannelIdRegex = `^channel-\d+$` + IBCPrefix = "ibc/" +) + +var ( + _ sdk.Msg = &MsgCreateTradeRoute{} + _ legacytx.LegacyMsg = &MsgCreateTradeRoute{} +) + +func (msg *MsgCreateTradeRoute) Type() string { + return TypeMsgCreateTradeRoute +} + +func (msg *MsgCreateTradeRoute) Route() string { + return RouterKey +} + +func (msg *MsgCreateTradeRoute) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgCreateTradeRoute) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Authority) + return []sdk.AccAddress{addr} +} + +func (msg *MsgCreateTradeRoute) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return errorsmod.Wrap(err, "invalid authority address") + } + + if msg.HostChainId == "" { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "host chain ID cannot be empty") + } + + if err := ValidateConnectionId(msg.StrideToRewardConnectionId); err != nil { + return errorsmod.Wrap(err, "invalid stride to reward connection ID") + } + if err := ValidateConnectionId(msg.StrideToTradeConnectionId); err != nil { + return errorsmod.Wrap(err, "invalid stride to trade connection ID") + } + + if err := ValidateChannelId(msg.HostToRewardTransferChannelId); err != nil { + return errorsmod.Wrap(err, "invalid host to reward channel ID") + } + if err := ValidateChannelId(msg.RewardToTradeTransferChannelId); err != nil { + return errorsmod.Wrap(err, "invalid reward to trade channel ID") + } + if err := ValidateChannelId(msg.TradeToHostTransferChannelId); err != nil { + return errorsmod.Wrap(err, "invalid trade to host channel ID") + } + + if err := ValidateDenom(msg.RewardDenomOnHost, true); err != nil { + return errorsmod.Wrap(err, "invalid reward denom on host") + } + if err := ValidateDenom(msg.RewardDenomOnReward, false); err != nil { + return errorsmod.Wrap(err, "invalid reward denom on reward") + } + if err := ValidateDenom(msg.RewardDenomOnTrade, true); err != nil { + return errorsmod.Wrap(err, "invalid reward denom on trade") + } + if err := ValidateDenom(msg.HostDenomOnTrade, true); err != nil { + return errorsmod.Wrap(err, "invalid host denom on trade") + } + if err := ValidateDenom(msg.HostDenomOnHost, false); err != nil { + return errorsmod.Wrap(err, "invalid host denom on host") + } + + if msg.PoolId < 1 { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid pool id") + } + if msg.MaxSwapAmount.GT(sdkmath.ZeroInt()) && msg.MinSwapAmount.GT(msg.MaxSwapAmount) { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "min swap amount cannot be greater than max swap amount") + } + + maxAllowedSwapLossRate, err := sdk.NewDecFromStr(msg.MaxAllowedSwapLossRate) + if err != nil { + return errorsmod.Wrapf(err, "unable to cast max allowed swap loss rate to a decimal") + } + if maxAllowedSwapLossRate.LT(sdk.ZeroDec()) || maxAllowedSwapLossRate.GT(sdk.OneDec()) { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "max allowed swap loss rate must be between 0 and 1") + } + + return nil +} + +// Helper function to validate a connection Id +func ValidateConnectionId(connectionId string) error { + matched, err := regexp.MatchString(ConnectionIdRegex, connectionId) + if err != nil { + return errorsmod.Wrapf(err, "unable to verify connnection-id (%s)", connectionId) + } + if !matched { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid connection-id (%s), must be of the format 'connection-{N}'", connectionId) + } + return nil +} + +// Helper function to validate a channel Id +func ValidateChannelId(channelId string) error { + matched, err := regexp.MatchString(ChannelIdRegex, channelId) + if err != nil { + return errorsmod.Wrapf(err, "unable to verify channel-id (%s)", channelId) + } + if !matched { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "invalid channel-id (%s), must be of the format 'channel-{N}'", channelId) + } + return nil +} + +// Helper function to validate a denom +func ValidateDenom(denom string, ibc bool) error { + if denom == "" { + return errorsmod.Wrap(ErrInvalidDenom, "denom is empty") + } + if ibc && !strings.HasPrefix(denom, IBCPrefix) { + return errorsmod.Wrapf(ErrInvalidDenom, "denom (%s) should have ibc prefix", denom) + } + return nil +} diff --git a/x/stakeibc/types/message_create_trade_route_test.go b/x/stakeibc/types/message_create_trade_route_test.go new file mode 100644 index 0000000000..6e7d142991 --- /dev/null +++ b/x/stakeibc/types/message_create_trade_route_test.go @@ -0,0 +1,169 @@ +package types_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" + + "github.com/Stride-Labs/stride/v16/app/apptesting" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func TestMsgCreateTradeRoute(t *testing.T) { + apptesting.SetupConfig() + + authority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + validChainId := "chain-1" + validConnectionId1 := "connection-1" + validConnectionId2 := "connection-17" + validTransferChannelId1 := "channel-2" + validTransferChannelId2 := "channel-202" + validTransferChannelId3 := "channel-40" + + validNativeDenom := "denom" + validIBCDenom := "ibc/denom" + + validPoolId := uint64(1) + validMaxAllowedSwapLossRate := "0.05" + validMinSwapAmount := sdkmath.NewInt(100) + validMaxSwapAmount := sdkmath.NewInt(10000) + + validMessage := types.MsgCreateTradeRoute{ + Authority: authority, + + HostChainId: validChainId, + StrideToRewardConnectionId: validConnectionId1, + StrideToTradeConnectionId: validConnectionId2, + + HostToRewardTransferChannelId: validTransferChannelId1, + RewardToTradeTransferChannelId: validTransferChannelId2, + TradeToHostTransferChannelId: validTransferChannelId3, + + RewardDenomOnHost: validIBCDenom, + RewardDenomOnReward: validNativeDenom, + RewardDenomOnTrade: validIBCDenom, + HostDenomOnTrade: validIBCDenom, + HostDenomOnHost: validNativeDenom, + + PoolId: validPoolId, + MaxAllowedSwapLossRate: validMaxAllowedSwapLossRate, + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + } + + // Validate successful message + require.NoError(t, validMessage.ValidateBasic(), "valid message") + require.Equal(t, validMessage.Route(), types.RouterKey) + require.Equal(t, validMessage.Type(), "create_trade_route") + + signers := validMessage.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), authority) + + // Remove authority - confirm invalid + invalidMessage := validMessage + invalidMessage.Authority = "" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid authority address") + + // Set invalid chain ID - confirm invalid + invalidMessage = validMessage + invalidMessage.HostChainId = "" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "host chain ID cannot be empty") + + // Set invalid connection IDs - confirm invalid + invalidMessage = validMessage + invalidMessage.StrideToRewardConnectionId = "" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid stride to reward connection ID") + + invalidMessage = validMessage + invalidMessage.StrideToTradeConnectionId = "connection-X" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid stride to trade connection ID") + + // Set invalid channel IDs - confirm invalid + invalidMessage = validMessage + invalidMessage.HostToRewardTransferChannelId = "" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid host to reward channel ID") + + invalidMessage = validMessage + invalidMessage.RewardToTradeTransferChannelId = "channel-" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid reward to trade channel ID") + + invalidMessage = validMessage + invalidMessage.TradeToHostTransferChannelId = "channel-X" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid trade to host channel ID") + + // Set invalid denom's - confirm invalid + invalidMessage = validMessage + invalidMessage.RewardDenomOnHost = "not-ibc-denom" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid reward denom on host") + + invalidMessage = validMessage + invalidMessage.RewardDenomOnReward = "" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid reward denom on reward") + + invalidMessage = validMessage + invalidMessage.RewardDenomOnTrade = "not-ibc-denom" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid reward denom on trade") + + invalidMessage = validMessage + invalidMessage.HostDenomOnTrade = "not-ibc-denom" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid host denom on trade") + + invalidMessage = validMessage + invalidMessage.HostDenomOnHost = "" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid host denom on host") + + // Set invalid pool configurations - confirm invalid + invalidMessage = validMessage + invalidMessage.PoolId = 0 + require.ErrorContains(t, invalidMessage.ValidateBasic(), "invalid pool id") + + invalidMessage = validMessage + invalidMessage.MinSwapAmount = sdkmath.NewInt(10) + invalidMessage.MaxSwapAmount = sdkmath.NewInt(9) + require.ErrorContains(t, invalidMessage.ValidateBasic(), "min swap amount cannot be greater than max swap amount") + + invalidMessage = validMessage + invalidMessage.MaxAllowedSwapLossRate = "" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "unable to cast max allowed swap loss rate to a decimal") + + invalidMessage = validMessage + invalidMessage.MaxAllowedSwapLossRate = "-0.01" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "max allowed swap loss rate must be between 0 and 1") + + invalidMessage = validMessage + invalidMessage.MaxAllowedSwapLossRate = "1.01" + require.ErrorContains(t, invalidMessage.ValidateBasic(), "max allowed swap loss rate must be between 0 and 1") +} + +func TestValidateConnectionId(t *testing.T) { + require.NoError(t, types.ValidateConnectionId("connection-0")) + require.NoError(t, types.ValidateConnectionId("connection-10")) + require.NoError(t, types.ValidateConnectionId("connection-1203")) + + require.ErrorContains(t, types.ValidateConnectionId("connection-X"), "invalid connection-id (connection-X)") + require.ErrorContains(t, types.ValidateConnectionId(""), "invalid connection-id ()") +} + +func TestValidateChannelId(t *testing.T) { + require.NoError(t, types.ValidateChannelId("channel-0")) + require.NoError(t, types.ValidateChannelId("channel-10")) + require.NoError(t, types.ValidateChannelId("channel-1203")) + + require.ErrorContains(t, types.ValidateChannelId("channel-X"), "invalid channel-id (channel-X)") + require.ErrorContains(t, types.ValidateChannelId(""), "invalid channel-id ()") +} + +func TestValidateDenom(t *testing.T) { + require.NoError(t, types.ValidateDenom("denom", false)) + require.NoError(t, types.ValidateDenom("ibc/denom", false)) + require.NoError(t, types.ValidateDenom("ibc/denom", true)) + + require.ErrorContains(t, types.ValidateDenom("", false), "denom is empty") + require.ErrorContains(t, types.ValidateDenom("", true), "denom is empty") + require.ErrorContains(t, types.ValidateDenom("denom", true), "denom (denom) should have ibc prefix") +} diff --git a/x/stakeibc/types/message_delete_trade_route.go b/x/stakeibc/types/message_delete_trade_route.go new file mode 100644 index 0000000000..1dda70b895 --- /dev/null +++ b/x/stakeibc/types/message_delete_trade_route.go @@ -0,0 +1,49 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + + errorsmod "cosmossdk.io/errors" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const TypeMsgDeleteTradeRoute = "delete_trade_route" + +var ( + _ sdk.Msg = &MsgDeleteTradeRoute{} + _ legacytx.LegacyMsg = &MsgDeleteTradeRoute{} +) + +func (msg *MsgDeleteTradeRoute) Type() string { + return TypeMsgDeleteTradeRoute +} + +func (msg *MsgDeleteTradeRoute) Route() string { + return RouterKey +} + +func (msg *MsgDeleteTradeRoute) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgDeleteTradeRoute) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Authority) + return []sdk.AccAddress{addr} +} + +func (msg *MsgDeleteTradeRoute) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return errorsmod.Wrap(err, "invalid authority address") + } + + if msg.HostDenom == "" { + return errorsmod.Wrapf(sdkerrors.ErrNotFound, "missing host denom") + } + if msg.RewardDenom == "" { + return errorsmod.Wrapf(sdkerrors.ErrNotFound, "missing reward denom") + } + + return nil +} diff --git a/x/stakeibc/types/message_delete_trade_route_test.go b/x/stakeibc/types/message_delete_trade_route_test.go new file mode 100644 index 0000000000..725336eb8d --- /dev/null +++ b/x/stakeibc/types/message_delete_trade_route_test.go @@ -0,0 +1,78 @@ +package types_test + +import ( + "testing" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" + + "github.com/Stride-Labs/stride/v16/app/apptesting" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func TestMsgDeleteTradeRoute(t *testing.T) { + apptesting.SetupConfig() + + authority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + validDenom := "denom" + + tests := []struct { + name string + msg types.MsgDeleteTradeRoute + err string + }{ + { + name: "successful message", + msg: types.MsgDeleteTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: validDenom, + }, + }, + { + name: "invalid authority message", + msg: types.MsgDeleteTradeRoute{ + Authority: "", + HostDenom: validDenom, + RewardDenom: validDenom, + }, + err: "invalid authority address", + }, + { + name: "invalid host denom", + msg: types.MsgDeleteTradeRoute{ + Authority: authority, + HostDenom: "", + RewardDenom: validDenom, + }, + err: "missing host denom", + }, + { + name: "invalid reward denom", + msg: types.MsgDeleteTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: "", + }, + err: "missing reward denom", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + require.Equal(t, test.msg.Route(), types.RouterKey) + require.Equal(t, test.msg.Type(), "delete_trade_route") + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), authority) + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} diff --git a/x/stakeibc/types/message_restore_interchain_account.go b/x/stakeibc/types/message_restore_interchain_account.go index 344dd04aa8..b2ae7d1230 100644 --- a/x/stakeibc/types/message_restore_interchain_account.go +++ b/x/stakeibc/types/message_restore_interchain_account.go @@ -1,20 +1,23 @@ package types import ( + "strings" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -const TypeMsgRestoreInterchainAccount = "register_interchain_account" +const TypeMsgRestoreInterchainAccount = "restore_interchain_account" var _ sdk.Msg = &MsgRestoreInterchainAccount{} -func NewMsgRestoreInterchainAccount(creator string, chainId string, accountType ICAAccountType) *MsgRestoreInterchainAccount { +func NewMsgRestoreInterchainAccount(creator, chainId, connectionId, owner string) *MsgRestoreInterchainAccount { return &MsgRestoreInterchainAccount{ - Creator: creator, - ChainId: chainId, - AccountType: accountType, + Creator: creator, + ChainId: chainId, + ConnectionId: connectionId, + AccountOwner: owner, } } @@ -44,5 +47,17 @@ func (msg *MsgRestoreInterchainAccount) ValidateBasic() error { if err != nil { return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "invalid creator address (%s)", err) } + if msg.ChainId == "" { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "chain ID must be specified") + } + if !strings.HasPrefix(msg.ConnectionId, "connection-") { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "connection ID must be specified") + } + if msg.AccountOwner == "" { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "ICA account owner must be specified") + } + if !strings.HasPrefix(msg.AccountOwner, msg.ChainId) { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "ICA account owner does not match chain ID") + } return nil } diff --git a/x/stakeibc/types/message_restore_interchain_account_test.go b/x/stakeibc/types/message_restore_interchain_account_test.go index c0e7577a78..4b00fd54bd 100644 --- a/x/stakeibc/types/message_restore_interchain_account_test.go +++ b/x/stakeibc/types/message_restore_interchain_account_test.go @@ -3,36 +3,93 @@ package types import ( "testing" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/stretchr/testify/require" "github.com/Stride-Labs/stride/v16/testutil/sample" ) func TestMsgRestoreInterchainAccount_ValidateBasic(t *testing.T) { + validChainId := "chain-0" + validConnectionId := "connection-0" + validHostZoneOwner := "chain-0.DELEGATION" + validTradeRouteOwner := "chain-0.reward.host.CONVERTER_TRADE" + tests := []struct { name string msg MsgRestoreInterchainAccount - err error + err string }{ { - name: "invalid address", + name: "valid host zone message", msg: MsgRestoreInterchainAccount{ - Creator: "invalid_address", + Creator: sample.AccAddress(), + ChainId: validChainId, + ConnectionId: validConnectionId, + AccountOwner: validHostZoneOwner, + }, + }, + { + name: "valid trade route message", + msg: MsgRestoreInterchainAccount{ + Creator: sample.AccAddress(), + ChainId: validChainId, + ConnectionId: validConnectionId, + AccountOwner: validTradeRouteOwner, }, - err: sdkerrors.ErrInvalidAddress, - }, { - name: "not admin address", + }, + { + name: "missing chain id", msg: MsgRestoreInterchainAccount{ - Creator: sample.AccAddress(), + Creator: sample.AccAddress(), + ChainId: "", + ConnectionId: validConnectionId, + AccountOwner: validHostZoneOwner, + }, + err: "chain ID must be specified", + }, + { + name: "missing connection id", + msg: MsgRestoreInterchainAccount{ + Creator: sample.AccAddress(), + ChainId: validChainId, + ConnectionId: "con-0", + AccountOwner: validHostZoneOwner, + }, + err: "connection ID must be specified", + }, + { + name: "missing account owner", + msg: MsgRestoreInterchainAccount{ + Creator: sample.AccAddress(), + ChainId: validChainId, + ConnectionId: validConnectionId, + AccountOwner: "", + }, + err: "ICA account owner must be specified", + }, + { + name: "chain id does not match owner", + msg: MsgRestoreInterchainAccount{ + Creator: sample.AccAddress(), + ChainId: validChainId, + ConnectionId: validConnectionId, + AccountOwner: "chain-1.reward.host.CONVERTER_TRADE", + }, + err: "ICA account owner does not match chain ID", + }, + { + name: "invalid address", + msg: MsgRestoreInterchainAccount{ + Creator: "invalid_address", }, + err: "invalid address", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.msg.ValidateBasic() - if tt.err != nil { - require.ErrorIs(t, err, tt.err) + if tt.err != "" { + require.ErrorContains(t, err, tt.err) return } require.NoError(t, err) diff --git a/x/stakeibc/types/message_update_trade_route.go b/x/stakeibc/types/message_update_trade_route.go new file mode 100644 index 0000000000..e95a8a4fd6 --- /dev/null +++ b/x/stakeibc/types/message_update_trade_route.go @@ -0,0 +1,63 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + + errorsmod "cosmossdk.io/errors" + sdkmath "cosmossdk.io/math" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +const TypeMsgUpdateTradeRoute = "update_trade_route" + +var ( + _ sdk.Msg = &MsgUpdateTradeRoute{} + _ legacytx.LegacyMsg = &MsgUpdateTradeRoute{} +) + +func (msg *MsgUpdateTradeRoute) Type() string { + return TypeMsgUpdateTradeRoute +} + +func (msg *MsgUpdateTradeRoute) Route() string { + return RouterKey +} + +func (msg *MsgUpdateTradeRoute) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(msg) + return sdk.MustSortJSON(bz) +} + +func (msg *MsgUpdateTradeRoute) GetSigners() []sdk.AccAddress { + addr, _ := sdk.AccAddressFromBech32(msg.Authority) + return []sdk.AccAddress{addr} +} +func (msg *MsgUpdateTradeRoute) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return errorsmod.Wrap(err, "invalid authority address") + } + + if msg.HostDenom == "" { + return errorsmod.Wrapf(sdkerrors.ErrNotFound, "missing host denom") + } + if msg.RewardDenom == "" { + return errorsmod.Wrapf(sdkerrors.ErrNotFound, "missing reward denom") + } + + if msg.PoolId < 1 { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "invalid pool id") + } + if msg.MaxSwapAmount.GT(sdkmath.ZeroInt()) && msg.MinSwapAmount.GT(msg.MaxSwapAmount) { + return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "min swap amount cannot be greater than max swap amount") + } + maxAllowedSwapLossRate, err := sdk.NewDecFromStr(msg.MaxAllowedSwapLossRate) + if err != nil { + return errorsmod.Wrapf(err, "unable to cast max allowed swap loss rate to a decimal") + } + if maxAllowedSwapLossRate.LT(sdk.ZeroDec()) || maxAllowedSwapLossRate.GT(sdk.OneDec()) { + return errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "max allowed swap loss rate must be between 0 and 1") + } + + return nil +} diff --git a/x/stakeibc/types/message_update_trade_route_test.go b/x/stakeibc/types/message_update_trade_route_test.go new file mode 100644 index 0000000000..1f16430697 --- /dev/null +++ b/x/stakeibc/types/message_update_trade_route_test.go @@ -0,0 +1,164 @@ +package types_test + +import ( + "testing" + + sdkmath "cosmossdk.io/math" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" + + "github.com/Stride-Labs/stride/v16/app/apptesting" + "github.com/Stride-Labs/stride/v16/x/stakeibc/types" +) + +func TestMsgUpdateTradeRoute(t *testing.T) { + apptesting.SetupConfig() + + authority := authtypes.NewModuleAddress(govtypes.ModuleName).String() + + validDenom := "denom" + validPoolId := uint64(1) + validMaxAllowedSwapLossRate := "0.05" + validMinSwapAmount := sdkmath.NewInt(100) + validMaxSwapAmount := sdkmath.NewInt(10000) + + tests := []struct { + name string + msg types.MsgUpdateTradeRoute + err string + }{ + { + name: "successful message", + msg: types.MsgUpdateTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: validDenom, + PoolId: validPoolId, + MaxAllowedSwapLossRate: validMaxAllowedSwapLossRate, + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + }, + }, + { + name: "invalid authority", + msg: types.MsgUpdateTradeRoute{ + Authority: "", + HostDenom: validDenom, + RewardDenom: validDenom, + PoolId: validPoolId, + MaxAllowedSwapLossRate: validMaxAllowedSwapLossRate, + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + }, + err: "invalid authority address", + }, + { + name: "invalid host denom", + msg: types.MsgUpdateTradeRoute{ + Authority: authority, + HostDenom: "", + RewardDenom: validDenom, + PoolId: validPoolId, + MaxAllowedSwapLossRate: validMaxAllowedSwapLossRate, + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + }, + err: "missing host denom", + }, + { + name: "invalid reward denom", + msg: types.MsgUpdateTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: "", + PoolId: validPoolId, + MaxAllowedSwapLossRate: validMaxAllowedSwapLossRate, + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + }, + err: "missing reward denom", + }, + { + name: "invalid pool id", + msg: types.MsgUpdateTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: validDenom, + PoolId: 0, + MaxAllowedSwapLossRate: validMaxAllowedSwapLossRate, + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + }, + err: "invalid pool id", + }, + { + name: "invalid swap loss rate - negative", + msg: types.MsgUpdateTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: validDenom, + PoolId: validPoolId, + MaxAllowedSwapLossRate: "-0.01", + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + }, + err: "max allowed swap loss rate must be between 0 and 1", + }, + { + name: "invalid swap loss rate - greater than 1", + msg: types.MsgUpdateTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: validDenom, + PoolId: validPoolId, + MaxAllowedSwapLossRate: "1.01", + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + }, + err: "max allowed swap loss rate must be between 0 and 1", + }, + { + name: "invalid swap loss rate - can't cast", + msg: types.MsgUpdateTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: validDenom, + PoolId: validPoolId, + MaxAllowedSwapLossRate: "", + MinSwapAmount: validMinSwapAmount, + MaxSwapAmount: validMaxSwapAmount, + }, + err: "unable to cast max allowed swap loss rate to a decimal", + }, + { + name: "invalid min/max swap amount", + msg: types.MsgUpdateTradeRoute{ + Authority: authority, + HostDenom: validDenom, + RewardDenom: validDenom, + PoolId: validPoolId, + MaxAllowedSwapLossRate: validMaxAllowedSwapLossRate, + MinSwapAmount: sdkmath.NewInt(10), + MaxSwapAmount: sdkmath.NewInt(5), + }, + err: "min swap amount cannot be greater than max swap amount", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.err == "" { + require.NoError(t, test.msg.ValidateBasic(), "test: %v", test.name) + require.Equal(t, test.msg.Route(), types.RouterKey) + require.Equal(t, test.msg.Type(), "update_trade_route") + + signers := test.msg.GetSigners() + require.Equal(t, len(signers), 1) + require.Equal(t, signers[0].String(), authority) + } else { + require.ErrorContains(t, test.msg.ValidateBasic(), test.err, "test: %v", test.name) + } + }) + } +} diff --git a/x/stakeibc/types/osmosis.pb.go b/x/stakeibc/types/osmosis.pb.go new file mode 100644 index 0000000000..87e2564c21 --- /dev/null +++ b/x/stakeibc/types/osmosis.pb.go @@ -0,0 +1,1370 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: osmosis/gamm/v1beta1/osmosis.proto + +package types + +import ( + cosmossdk_io_math "cosmossdk.io/math" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + _ "github.com/cosmos/gogoproto/types" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" + io "io" + math "math" + math_bits "math/bits" + time "time" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf +var _ = time.Kitchen + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgSwapExactAmountIn stores the tx Msg type to swap tokens in the trade ICA +type MsgSwapExactAmountIn struct { + Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty" yaml:"sender"` + Routes []SwapAmountInRoute `protobuf:"bytes,2,rep,name=routes,proto3" json:"routes"` + TokenIn types.Coin `protobuf:"bytes,3,opt,name=token_in,json=tokenIn,proto3" json:"token_in" yaml:"token_in"` + TokenOutMinAmount cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=token_out_min_amount,json=tokenOutMinAmount,proto3,customtype=cosmossdk.io/math.Int" json:"token_out_min_amount" yaml:"token_out_min_amount"` +} + +func (m *MsgSwapExactAmountIn) Reset() { *m = MsgSwapExactAmountIn{} } +func (m *MsgSwapExactAmountIn) String() string { return proto.CompactTextString(m) } +func (*MsgSwapExactAmountIn) ProtoMessage() {} +func (*MsgSwapExactAmountIn) Descriptor() ([]byte, []int) { + return fileDescriptor_39668b2e9488de8c, []int{0} +} +func (m *MsgSwapExactAmountIn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSwapExactAmountIn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSwapExactAmountIn.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgSwapExactAmountIn) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSwapExactAmountIn.Merge(m, src) +} +func (m *MsgSwapExactAmountIn) XXX_Size() int { + return m.Size() +} +func (m *MsgSwapExactAmountIn) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSwapExactAmountIn.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSwapExactAmountIn proto.InternalMessageInfo + +func (m *MsgSwapExactAmountIn) GetSender() string { + if m != nil { + return m.Sender + } + return "" +} + +func (m *MsgSwapExactAmountIn) GetRoutes() []SwapAmountInRoute { + if m != nil { + return m.Routes + } + return nil +} + +func (m *MsgSwapExactAmountIn) GetTokenIn() types.Coin { + if m != nil { + return m.TokenIn + } + return types.Coin{} +} + +type SwapAmountInRoute struct { + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty" yaml:"pool_id"` + TokenOutDenom string `protobuf:"bytes,2,opt,name=token_out_denom,json=tokenOutDenom,proto3" json:"token_out_denom,omitempty" yaml:"token_out_denom"` +} + +func (m *SwapAmountInRoute) Reset() { *m = SwapAmountInRoute{} } +func (m *SwapAmountInRoute) String() string { return proto.CompactTextString(m) } +func (*SwapAmountInRoute) ProtoMessage() {} +func (*SwapAmountInRoute) Descriptor() ([]byte, []int) { + return fileDescriptor_39668b2e9488de8c, []int{1} +} +func (m *SwapAmountInRoute) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SwapAmountInRoute) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SwapAmountInRoute.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SwapAmountInRoute) XXX_Merge(src proto.Message) { + xxx_messageInfo_SwapAmountInRoute.Merge(m, src) +} +func (m *SwapAmountInRoute) XXX_Size() int { + return m.Size() +} +func (m *SwapAmountInRoute) XXX_DiscardUnknown() { + xxx_messageInfo_SwapAmountInRoute.DiscardUnknown(m) +} + +var xxx_messageInfo_SwapAmountInRoute proto.InternalMessageInfo + +func (m *SwapAmountInRoute) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *SwapAmountInRoute) GetTokenOutDenom() string { + if m != nil { + return m.TokenOutDenom + } + return "" +} + +// A TwapRecord stores the most recent price of a pair of denom's +type OsmosisTwapRecord struct { + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // Lexicographically smaller denom of the pair + Asset0Denom string `protobuf:"bytes,2,opt,name=asset0_denom,json=asset0Denom,proto3" json:"asset0_denom,omitempty"` + // Lexicographically larger denom of the pair + Asset1Denom string `protobuf:"bytes,3,opt,name=asset1_denom,json=asset1Denom,proto3" json:"asset1_denom,omitempty"` + // height this record corresponds to, for debugging purposes + Height int64 `protobuf:"varint,4,opt,name=height,proto3" json:"record_height" yaml:"record_height"` + // This field should only exist until we have a global registry in the state + // machine, mapping prior block heights within {TIME RANGE} to times. + Time time.Time `protobuf:"bytes,5,opt,name=time,proto3,stdtime" json:"time" yaml:"record_time"` + // We store the last spot prices in the struct, so that we can interpolate + // accumulator values for times between when accumulator records are stored. + P0LastSpotPrice cosmossdk_io_math.LegacyDec `protobuf:"bytes,6,opt,name=p0_last_spot_price,json=p0LastSpotPrice,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"p0_last_spot_price"` + P1LastSpotPrice cosmossdk_io_math.LegacyDec `protobuf:"bytes,7,opt,name=p1_last_spot_price,json=p1LastSpotPrice,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"p1_last_spot_price"` + P0ArithmeticTwapAccumulator cosmossdk_io_math.LegacyDec `protobuf:"bytes,8,opt,name=p0_arithmetic_twap_accumulator,json=p0ArithmeticTwapAccumulator,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"p0_arithmetic_twap_accumulator"` + P1ArithmeticTwapAccumulator cosmossdk_io_math.LegacyDec `protobuf:"bytes,9,opt,name=p1_arithmetic_twap_accumulator,json=p1ArithmeticTwapAccumulator,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"p1_arithmetic_twap_accumulator"` + GeometricTwapAccumulator cosmossdk_io_math.LegacyDec `protobuf:"bytes,10,opt,name=geometric_twap_accumulator,json=geometricTwapAccumulator,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"geometric_twap_accumulator"` + // This field contains the time in which the last spot price error occured. + // It is used to alert the caller if they are getting a potentially erroneous + // TWAP, due to an unforeseen underlying error. + LastErrorTime time.Time `protobuf:"bytes,11,opt,name=last_error_time,json=lastErrorTime,proto3,stdtime" json:"last_error_time" yaml:"last_error_time"` +} + +func (m *OsmosisTwapRecord) Reset() { *m = OsmosisTwapRecord{} } +func (m *OsmosisTwapRecord) String() string { return proto.CompactTextString(m) } +func (*OsmosisTwapRecord) ProtoMessage() {} +func (*OsmosisTwapRecord) Descriptor() ([]byte, []int) { + return fileDescriptor_39668b2e9488de8c, []int{2} +} +func (m *OsmosisTwapRecord) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OsmosisTwapRecord) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OsmosisTwapRecord.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *OsmosisTwapRecord) XXX_Merge(src proto.Message) { + xxx_messageInfo_OsmosisTwapRecord.Merge(m, src) +} +func (m *OsmosisTwapRecord) XXX_Size() int { + return m.Size() +} +func (m *OsmosisTwapRecord) XXX_DiscardUnknown() { + xxx_messageInfo_OsmosisTwapRecord.DiscardUnknown(m) +} + +var xxx_messageInfo_OsmosisTwapRecord proto.InternalMessageInfo + +func (m *OsmosisTwapRecord) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *OsmosisTwapRecord) GetAsset0Denom() string { + if m != nil { + return m.Asset0Denom + } + return "" +} + +func (m *OsmosisTwapRecord) GetAsset1Denom() string { + if m != nil { + return m.Asset1Denom + } + return "" +} + +func (m *OsmosisTwapRecord) GetHeight() int64 { + if m != nil { + return m.Height + } + return 0 +} + +func (m *OsmosisTwapRecord) GetTime() time.Time { + if m != nil { + return m.Time + } + return time.Time{} +} + +func (m *OsmosisTwapRecord) GetLastErrorTime() time.Time { + if m != nil { + return m.LastErrorTime + } + return time.Time{} +} + +func init() { + proto.RegisterType((*MsgSwapExactAmountIn)(nil), "osmosis.gamm.v1beta1.MsgSwapExactAmountIn") + proto.RegisterType((*SwapAmountInRoute)(nil), "osmosis.gamm.v1beta1.SwapAmountInRoute") + proto.RegisterType((*OsmosisTwapRecord)(nil), "osmosis.gamm.v1beta1.OsmosisTwapRecord") +} + +func init() { + proto.RegisterFile("osmosis/gamm/v1beta1/osmosis.proto", fileDescriptor_39668b2e9488de8c) +} + +var fileDescriptor_39668b2e9488de8c = []byte{ + // 774 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x53, 0x4f, 0x6f, 0xe3, 0x44, + 0x14, 0x8f, 0x9b, 0x90, 0xee, 0x4e, 0x08, 0x51, 0xac, 0xc0, 0x9a, 0x54, 0xb2, 0xbb, 0x46, 0x82, + 0x2e, 0x28, 0x76, 0x5c, 0x24, 0x0e, 0x2b, 0x2e, 0x31, 0xdb, 0x43, 0xa4, 0x94, 0x5d, 0xb9, 0x7b, + 0xe2, 0x62, 0x4d, 0x9c, 0xa9, 0x33, 0x6a, 0xc6, 0x63, 0x79, 0xc6, 0x4d, 0x7b, 0xe7, 0xc4, 0xa9, + 0x1f, 0x85, 0x8f, 0xd1, 0x63, 0x8f, 0x88, 0x83, 0x41, 0xed, 0x01, 0x89, 0x03, 0x87, 0x7c, 0x02, + 0x34, 0x33, 0x4e, 0xda, 0xa4, 0x85, 0x6d, 0x2f, 0xd1, 0xf8, 0xcd, 0xef, 0xcf, 0x7b, 0xf3, 0x7e, + 0x01, 0x36, 0x65, 0x84, 0x32, 0xcc, 0xdc, 0x18, 0x12, 0xe2, 0x9e, 0x7a, 0x63, 0xc4, 0xa1, 0xe7, + 0x96, 0x45, 0x27, 0xcd, 0x28, 0xa7, 0x7a, 0x67, 0xf9, 0x29, 0x30, 0x4e, 0x89, 0xe9, 0x76, 0x62, + 0x1a, 0x53, 0x09, 0x70, 0xc5, 0x49, 0x61, 0xbb, 0x6d, 0x48, 0x70, 0x42, 0x5d, 0xf9, 0x5b, 0x96, + 0xcc, 0x48, 0xf2, 0xdd, 0x31, 0x64, 0x68, 0xe5, 0x10, 0x51, 0x9c, 0x94, 0xf7, 0x56, 0x4c, 0x69, + 0x3c, 0x43, 0xae, 0xfc, 0x1a, 0xe7, 0xc7, 0x2e, 0xc7, 0x04, 0x31, 0x0e, 0x49, 0xaa, 0x00, 0xf6, + 0x3f, 0x5b, 0xa0, 0x73, 0xc8, 0xe2, 0xa3, 0x39, 0x4c, 0x0f, 0xce, 0x60, 0xc4, 0x07, 0x84, 0xe6, + 0x09, 0x1f, 0x26, 0xfa, 0x2b, 0x50, 0x67, 0x28, 0x99, 0xa0, 0xcc, 0xd0, 0x76, 0xb5, 0xbd, 0xe7, + 0x7e, 0x7b, 0x51, 0x58, 0xcd, 0x73, 0x48, 0x66, 0xaf, 0x6d, 0x55, 0xb7, 0x83, 0x12, 0xa0, 0x1f, + 0x80, 0x7a, 0x46, 0x73, 0x8e, 0x98, 0xb1, 0xb5, 0x5b, 0xdd, 0x6b, 0xec, 0x7f, 0xe5, 0x3c, 0x34, + 0x94, 0x23, 0x3c, 0x96, 0xf2, 0x81, 0xc0, 0xfb, 0xb5, 0xcb, 0xc2, 0xaa, 0x04, 0x25, 0x59, 0x3f, + 0x04, 0xcf, 0x38, 0x3d, 0x41, 0x49, 0x88, 0x13, 0xa3, 0xba, 0xab, 0xed, 0x35, 0xf6, 0x3f, 0x77, + 0xd4, 0x78, 0x8e, 0x18, 0x6f, 0xa5, 0xf3, 0x03, 0xc5, 0x89, 0xff, 0x42, 0x50, 0x17, 0x85, 0xd5, + 0x52, 0x2d, 0x2d, 0x89, 0x76, 0xb0, 0x2d, 0x8f, 0xc3, 0x44, 0x27, 0xa0, 0xa3, 0xaa, 0x34, 0xe7, + 0x21, 0xc1, 0x49, 0x08, 0xa5, 0xb7, 0x51, 0x93, 0xe3, 0x7c, 0x2f, 0xf8, 0xbf, 0x17, 0xd6, 0xa7, + 0xca, 0x81, 0x4d, 0x4e, 0x1c, 0x4c, 0x5d, 0x02, 0xf9, 0xd4, 0x19, 0x26, 0x7c, 0x51, 0x58, 0x3b, + 0x77, 0x85, 0xd7, 0x25, 0xec, 0xa0, 0x2d, 0xcb, 0x6f, 0x73, 0x7e, 0x88, 0x13, 0x35, 0xd2, 0xeb, + 0x2f, 0x7f, 0xf9, 0xeb, 0xd7, 0xaf, 0x5f, 0xae, 0x6d, 0x9c, 0xcd, 0x61, 0xda, 0x43, 0xe2, 0x55, + 0x7b, 0x8a, 0xd8, 0xc3, 0x89, 0xfd, 0xb3, 0x06, 0xda, 0xf7, 0x5e, 0x42, 0xff, 0x06, 0x6c, 0xa7, + 0x94, 0xce, 0x42, 0x3c, 0x91, 0xcf, 0x5d, 0xf3, 0xf5, 0x45, 0x61, 0x7d, 0xa2, 0x5a, 0x28, 0x2f, + 0xec, 0xa0, 0x2e, 0x4e, 0xc3, 0x89, 0xee, 0x83, 0xd6, 0x6d, 0x5b, 0x13, 0x94, 0x50, 0x62, 0x6c, + 0xc9, 0xa1, 0xba, 0x8b, 0xc2, 0xfa, 0x6c, 0xb3, 0x6f, 0x09, 0xb0, 0x83, 0xe6, 0xb2, 0xe5, 0x37, + 0xf2, 0xfb, 0xb2, 0x0e, 0xda, 0x6f, 0x55, 0xb3, 0xef, 0xe7, 0x30, 0x0d, 0x50, 0x44, 0xb3, 0x89, + 0xfe, 0x62, 0xa3, 0x8d, 0x95, 0xe5, 0x4b, 0xf0, 0x31, 0x64, 0x0c, 0xf1, 0xfe, 0x5d, 0xbf, 0xa0, + 0xa1, 0x6a, 0x52, 0x71, 0x05, 0xf1, 0x4a, 0x48, 0xf5, 0x0e, 0xc4, 0x53, 0x90, 0x01, 0xa8, 0x4f, + 0x11, 0x8e, 0xa7, 0x6a, 0x09, 0x55, 0xff, 0xd5, 0xdf, 0x85, 0xd5, 0xcc, 0xa4, 0x75, 0xa8, 0x2e, + 0x16, 0x85, 0xd5, 0x51, 0x03, 0xac, 0x95, 0xed, 0xa0, 0x24, 0xea, 0x3f, 0x82, 0x9a, 0x88, 0xb0, + 0xf1, 0x91, 0x0c, 0x48, 0xd7, 0x51, 0xf9, 0x76, 0x96, 0xf9, 0x76, 0xde, 0x2f, 0xf3, 0xed, 0x9b, + 0x65, 0x42, 0xf4, 0x35, 0x3d, 0x41, 0xb6, 0x2f, 0xfe, 0xb0, 0xb4, 0x40, 0xea, 0xe8, 0xef, 0x80, + 0x9e, 0xf6, 0xc3, 0x19, 0x64, 0x3c, 0x64, 0x29, 0xe5, 0x61, 0x9a, 0xe1, 0x08, 0x19, 0x75, 0xf9, + 0x9c, 0x5f, 0x94, 0x19, 0xd9, 0xb9, 0x9f, 0x91, 0x11, 0x8a, 0x61, 0x74, 0xfe, 0x06, 0x45, 0x41, + 0x2b, 0xed, 0x8f, 0x20, 0xe3, 0x47, 0x29, 0xe5, 0xef, 0x04, 0x57, 0x2a, 0x7a, 0xf7, 0x14, 0xb7, + 0x9f, 0xa2, 0xe8, 0xad, 0x2b, 0x4e, 0x81, 0x99, 0xf6, 0x43, 0x98, 0x61, 0x3e, 0x25, 0x88, 0xe3, + 0x28, 0xe4, 0x73, 0x98, 0x86, 0x30, 0x8a, 0x72, 0x92, 0xcf, 0x20, 0xa7, 0x99, 0xf1, 0xec, 0xf1, + 0xea, 0x3b, 0x69, 0x7f, 0xb0, 0x52, 0x12, 0xab, 0x1f, 0xdc, 0xea, 0x48, 0x27, 0xef, 0x7f, 0x9d, + 0x9e, 0x3f, 0xc5, 0xc9, 0xfb, 0x6f, 0x27, 0x08, 0xba, 0x31, 0xa2, 0x04, 0xf1, 0xec, 0x21, 0x17, + 0xf0, 0x78, 0x17, 0x63, 0x25, 0xb3, 0x69, 0x71, 0x0c, 0x5a, 0x72, 0x0b, 0x28, 0xcb, 0x68, 0x26, + 0x17, 0x6f, 0x34, 0x3e, 0x98, 0x1a, 0xbb, 0x4c, 0x4d, 0xf9, 0x37, 0xda, 0x10, 0x50, 0xc9, 0x69, + 0x8a, 0xea, 0x81, 0x28, 0x0a, 0x9e, 0x3f, 0xba, 0xbc, 0x36, 0xb5, 0xab, 0x6b, 0x53, 0xfb, 0xf3, + 0xda, 0xd4, 0x2e, 0x6e, 0xcc, 0xca, 0xd5, 0x8d, 0x59, 0xf9, 0xed, 0xc6, 0xac, 0xfc, 0xb4, 0x1f, + 0x63, 0x3e, 0xcd, 0xc7, 0x4e, 0x44, 0x89, 0x7b, 0xc4, 0x33, 0x3c, 0x41, 0xbd, 0x11, 0x1c, 0x33, + 0x97, 0xc9, 0xb3, 0x7b, 0xea, 0x7d, 0xe7, 0x9e, 0xb9, 0x8c, 0xc3, 0x13, 0x84, 0xc7, 0x91, 0xcb, + 0xcf, 0x53, 0xc4, 0xc6, 0x75, 0xd9, 0xd4, 0xb7, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x7e, 0xfc, + 0x9f, 0x22, 0x3d, 0x06, 0x00, 0x00, +} + +func (m *MsgSwapExactAmountIn) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgSwapExactAmountIn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSwapExactAmountIn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.TokenOutMinAmount.Size() + i -= size + if _, err := m.TokenOutMinAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintOsmosis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + { + size, err := m.TokenIn.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintOsmosis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Routes) > 0 { + for iNdEx := len(m.Routes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Routes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintOsmosis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Sender) > 0 { + i -= len(m.Sender) + copy(dAtA[i:], m.Sender) + i = encodeVarintOsmosis(dAtA, i, uint64(len(m.Sender))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *SwapAmountInRoute) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SwapAmountInRoute) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SwapAmountInRoute) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TokenOutDenom) > 0 { + i -= len(m.TokenOutDenom) + copy(dAtA[i:], m.TokenOutDenom) + i = encodeVarintOsmosis(dAtA, i, uint64(len(m.TokenOutDenom))) + i-- + dAtA[i] = 0x12 + } + if m.PoolId != 0 { + i = encodeVarintOsmosis(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *OsmosisTwapRecord) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *OsmosisTwapRecord) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OsmosisTwapRecord) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + n2, err2 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.LastErrorTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.LastErrorTime):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintOsmosis(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0x5a + { + size := m.GeometricTwapAccumulator.Size() + i -= size + if _, err := m.GeometricTwapAccumulator.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintOsmosis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + { + size := m.P1ArithmeticTwapAccumulator.Size() + i -= size + if _, err := m.P1ArithmeticTwapAccumulator.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintOsmosis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + { + size := m.P0ArithmeticTwapAccumulator.Size() + i -= size + if _, err := m.P0ArithmeticTwapAccumulator.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintOsmosis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + { + size := m.P1LastSpotPrice.Size() + i -= size + if _, err := m.P1LastSpotPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintOsmosis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + { + size := m.P0LastSpotPrice.Size() + i -= size + if _, err := m.P0LastSpotPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintOsmosis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + n3, err3 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time):]) + if err3 != nil { + return 0, err3 + } + i -= n3 + i = encodeVarintOsmosis(dAtA, i, uint64(n3)) + i-- + dAtA[i] = 0x2a + if m.Height != 0 { + i = encodeVarintOsmosis(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x20 + } + if len(m.Asset1Denom) > 0 { + i -= len(m.Asset1Denom) + copy(dAtA[i:], m.Asset1Denom) + i = encodeVarintOsmosis(dAtA, i, uint64(len(m.Asset1Denom))) + i-- + dAtA[i] = 0x1a + } + if len(m.Asset0Denom) > 0 { + i -= len(m.Asset0Denom) + copy(dAtA[i:], m.Asset0Denom) + i = encodeVarintOsmosis(dAtA, i, uint64(len(m.Asset0Denom))) + i-- + dAtA[i] = 0x12 + } + if m.PoolId != 0 { + i = encodeVarintOsmosis(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintOsmosis(dAtA []byte, offset int, v uint64) int { + offset -= sovOsmosis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgSwapExactAmountIn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovOsmosis(uint64(l)) + } + if len(m.Routes) > 0 { + for _, e := range m.Routes { + l = e.Size() + n += 1 + l + sovOsmosis(uint64(l)) + } + } + l = m.TokenIn.Size() + n += 1 + l + sovOsmosis(uint64(l)) + l = m.TokenOutMinAmount.Size() + n += 1 + l + sovOsmosis(uint64(l)) + return n +} + +func (m *SwapAmountInRoute) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovOsmosis(uint64(m.PoolId)) + } + l = len(m.TokenOutDenom) + if l > 0 { + n += 1 + l + sovOsmosis(uint64(l)) + } + return n +} + +func (m *OsmosisTwapRecord) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovOsmosis(uint64(m.PoolId)) + } + l = len(m.Asset0Denom) + if l > 0 { + n += 1 + l + sovOsmosis(uint64(l)) + } + l = len(m.Asset1Denom) + if l > 0 { + n += 1 + l + sovOsmosis(uint64(l)) + } + if m.Height != 0 { + n += 1 + sovOsmosis(uint64(m.Height)) + } + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time) + n += 1 + l + sovOsmosis(uint64(l)) + l = m.P0LastSpotPrice.Size() + n += 1 + l + sovOsmosis(uint64(l)) + l = m.P1LastSpotPrice.Size() + n += 1 + l + sovOsmosis(uint64(l)) + l = m.P0ArithmeticTwapAccumulator.Size() + n += 1 + l + sovOsmosis(uint64(l)) + l = m.P1ArithmeticTwapAccumulator.Size() + n += 1 + l + sovOsmosis(uint64(l)) + l = m.GeometricTwapAccumulator.Size() + n += 1 + l + sovOsmosis(uint64(l)) + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.LastErrorTime) + n += 1 + l + sovOsmosis(uint64(l)) + return n +} + +func sovOsmosis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozOsmosis(x uint64) (n int) { + return sovOsmosis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgSwapExactAmountIn) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgSwapExactAmountIn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSwapExactAmountIn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sender = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Routes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthOsmosis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Routes = append(m.Routes, SwapAmountInRoute{}) + if err := m.Routes[len(m.Routes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenIn", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthOsmosis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TokenIn.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenOutMinAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TokenOutMinAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipOsmosis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthOsmosis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SwapAmountInRoute) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SwapAmountInRoute: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SwapAmountInRoute: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TokenOutDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TokenOutDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipOsmosis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthOsmosis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OsmosisTwapRecord) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OsmosisTwapRecord: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OsmosisTwapRecord: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset0Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Asset0Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Asset1Denom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Asset1Denom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthOsmosis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field P0LastSpotPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.P0LastSpotPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field P1LastSpotPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.P1LastSpotPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field P0ArithmeticTwapAccumulator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.P0ArithmeticTwapAccumulator.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field P1ArithmeticTwapAccumulator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.P1ArithmeticTwapAccumulator.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GeometricTwapAccumulator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + 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 ErrInvalidLengthOsmosis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GeometricTwapAccumulator.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LastErrorTime", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOsmosis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthOsmosis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthOsmosis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.LastErrorTime, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipOsmosis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthOsmosis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipOsmosis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOsmosis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOsmosis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowOsmosis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthOsmosis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupOsmosis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthOsmosis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthOsmosis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowOsmosis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupOsmosis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/stakeibc/types/query.pb.go b/x/stakeibc/types/query.pb.go index e7ba7beffd..4ebacfb2da 100644 --- a/x/stakeibc/types/query.pb.go +++ b/x/stakeibc/types/query.pb.go @@ -931,6 +931,86 @@ func (m *QueryAddressUnbondingsResponse) GetAddressUnbondings() []AddressUnbondi return nil } +type QueryAllTradeRoutes struct { +} + +func (m *QueryAllTradeRoutes) Reset() { *m = QueryAllTradeRoutes{} } +func (m *QueryAllTradeRoutes) String() string { return proto.CompactTextString(m) } +func (*QueryAllTradeRoutes) ProtoMessage() {} +func (*QueryAllTradeRoutes) Descriptor() ([]byte, []int) { + return fileDescriptor_494b786fe66f2b80, []int{20} +} +func (m *QueryAllTradeRoutes) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllTradeRoutes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllTradeRoutes.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllTradeRoutes) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllTradeRoutes.Merge(m, src) +} +func (m *QueryAllTradeRoutes) XXX_Size() int { + return m.Size() +} +func (m *QueryAllTradeRoutes) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllTradeRoutes.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllTradeRoutes proto.InternalMessageInfo + +type QueryAllTradeRoutesResponse struct { + TradeRoutes []TradeRoute `protobuf:"bytes,1,rep,name=trade_routes,json=tradeRoutes,proto3" json:"trade_routes"` +} + +func (m *QueryAllTradeRoutesResponse) Reset() { *m = QueryAllTradeRoutesResponse{} } +func (m *QueryAllTradeRoutesResponse) String() string { return proto.CompactTextString(m) } +func (*QueryAllTradeRoutesResponse) ProtoMessage() {} +func (*QueryAllTradeRoutesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_494b786fe66f2b80, []int{21} +} +func (m *QueryAllTradeRoutesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryAllTradeRoutesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryAllTradeRoutesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryAllTradeRoutesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryAllTradeRoutesResponse.Merge(m, src) +} +func (m *QueryAllTradeRoutesResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryAllTradeRoutesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryAllTradeRoutesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryAllTradeRoutesResponse proto.InternalMessageInfo + +func (m *QueryAllTradeRoutesResponse) GetTradeRoutes() []TradeRoute { + if m != nil { + return m.TradeRoutes + } + return nil +} + func init() { proto.RegisterType((*QueryInterchainAccountFromAddressRequest)(nil), "stride.stakeibc.QueryInterchainAccountFromAddressRequest") proto.RegisterType((*QueryInterchainAccountFromAddressResponse)(nil), "stride.stakeibc.QueryInterchainAccountFromAddressResponse") @@ -952,85 +1032,92 @@ func init() { proto.RegisterType((*QueryGetNextPacketSequenceResponse)(nil), "stride.stakeibc.QueryGetNextPacketSequenceResponse") proto.RegisterType((*QueryAddressUnbondings)(nil), "stride.stakeibc.QueryAddressUnbondings") proto.RegisterType((*QueryAddressUnbondingsResponse)(nil), "stride.stakeibc.QueryAddressUnbondingsResponse") + proto.RegisterType((*QueryAllTradeRoutes)(nil), "stride.stakeibc.QueryAllTradeRoutes") + proto.RegisterType((*QueryAllTradeRoutesResponse)(nil), "stride.stakeibc.QueryAllTradeRoutesResponse") } func init() { proto.RegisterFile("stride/stakeibc/query.proto", fileDescriptor_494b786fe66f2b80) } var fileDescriptor_494b786fe66f2b80 = []byte{ - // 1158 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x97, 0xdd, 0x6e, 0x1b, 0x45, - 0x1b, 0xc7, 0xb3, 0x4d, 0x9a, 0x8f, 0x27, 0x89, 0xf2, 0x76, 0xde, 0x88, 0x38, 0xdb, 0xc4, 0x21, - 0xd3, 0xd2, 0x7c, 0x90, 0x7a, 0x89, 0x53, 0x2a, 0x35, 0xa2, 0x82, 0x44, 0x6a, 0x1b, 0xa3, 0x80, - 0x82, 0x0b, 0x15, 0x2a, 0x07, 0xd6, 0x78, 0x77, 0xb0, 0x57, 0x5d, 0xcf, 0xb8, 0xbb, 0xeb, 0x90, - 0x10, 0x59, 0x95, 0xb8, 0x82, 0x0a, 0xc4, 0x09, 0x67, 0x45, 0x1c, 0x70, 0xcc, 0x55, 0xf4, 0x8c, - 0x4a, 0x9c, 0x70, 0x14, 0xa1, 0x84, 0x2b, 0xa8, 0xb8, 0x00, 0xb4, 0x33, 0xb3, 0x6b, 0x7b, 0x3f, - 0x8c, 0xd3, 0x33, 0xcf, 0xcc, 0xf3, 0xf1, 0x9b, 0x67, 0x9e, 0xf9, 0xcf, 0x1a, 0xae, 0x7a, 0xbe, - 0x6b, 0x5b, 0xd4, 0xf0, 0x7c, 0xf2, 0x84, 0xda, 0x55, 0xd3, 0x78, 0xda, 0xa2, 0xee, 0x71, 0xa1, - 0xe9, 0x72, 0x9f, 0xa3, 0x19, 0xb9, 0x58, 0x08, 0x17, 0xf5, 0xd9, 0x1a, 0xaf, 0x71, 0xb1, 0x66, - 0x04, 0xbf, 0xa4, 0x99, 0xbe, 0x50, 0xe3, 0xbc, 0xe6, 0x50, 0x83, 0x34, 0x6d, 0x83, 0x30, 0xc6, - 0x7d, 0xe2, 0xdb, 0x9c, 0x79, 0x6a, 0x75, 0xdd, 0xe4, 0x5e, 0x83, 0x7b, 0x46, 0x95, 0x78, 0x54, - 0x46, 0x37, 0x0e, 0x37, 0xab, 0xd4, 0x27, 0x9b, 0x46, 0x93, 0xd4, 0x6c, 0x26, 0x8c, 0xc3, 0x48, - 0x71, 0x9a, 0x26, 0x71, 0x49, 0x23, 0x8c, 0xb4, 0x14, 0x5f, 0x3d, 0x24, 0x8e, 0x6d, 0x11, 0x9f, - 0xbb, 0x59, 0x06, 0x75, 0xee, 0xf9, 0x95, 0x6f, 0x39, 0xa3, 0xca, 0xe0, 0x5a, 0xdc, 0x80, 0x36, - 0xb9, 0x59, 0xaf, 0xf8, 0x2e, 0x31, 0x9f, 0xd0, 0x30, 0xca, 0x4a, 0xdc, 0x88, 0x58, 0x96, 0x4b, - 0x3d, 0xaf, 0xd2, 0x62, 0x55, 0xce, 0x2c, 0x9b, 0xd5, 0xa4, 0x21, 0x7e, 0x06, 0xab, 0x9f, 0x05, - 0xfb, 0x29, 0x31, 0x9f, 0xba, 0x66, 0x9d, 0xd8, 0x6c, 0xc7, 0x34, 0x79, 0x8b, 0xf9, 0xf7, 0x5d, - 0xde, 0xd8, 0x91, 0x4e, 0x65, 0xfa, 0xb4, 0x45, 0x3d, 0x1f, 0xcd, 0xc2, 0x65, 0xfe, 0x0d, 0xa3, - 0x6e, 0x4e, 0x7b, 0x5b, 0x5b, 0x9d, 0x28, 0xcb, 0x01, 0xba, 0x0b, 0xd3, 0x26, 0x67, 0x8c, 0x9a, - 0x41, 0x0d, 0x2a, 0xb6, 0x95, 0xbb, 0x14, 0xac, 0xee, 0xe6, 0x5e, 0x9f, 0x2e, 0xcd, 0x1e, 0x93, - 0x86, 0xb3, 0x8d, 0x7b, 0x96, 0x71, 0x79, 0xaa, 0x33, 0x2e, 0x59, 0xf8, 0xb9, 0x06, 0x6b, 0x03, - 0x10, 0x78, 0x4d, 0xce, 0x3c, 0x8a, 0x4c, 0xd0, 0xed, 0xc8, 0xae, 0x42, 0xa4, 0x61, 0x45, 0x6d, - 0x4e, 0x72, 0xed, 0xbe, 0xf3, 0xfa, 0x74, 0x69, 0x59, 0x66, 0xce, 0xb6, 0xc5, 0xe5, 0x9c, 0x1d, - 0x4f, 0xa8, 0x92, 0xe1, 0x59, 0x40, 0x82, 0xe8, 0x40, 0x1c, 0x9c, 0xda, 0x3d, 0xde, 0x87, 0xff, - 0xf7, 0xcc, 0x2a, 0xa2, 0xf7, 0x61, 0x54, 0x1e, 0xb0, 0xc8, 0x3e, 0x59, 0x9c, 0x2b, 0xc4, 0x1a, - 0xae, 0x20, 0x1d, 0x76, 0x47, 0x5e, 0x9e, 0x2e, 0x0d, 0x95, 0x95, 0x31, 0xbe, 0x0d, 0xf3, 0x22, - 0xda, 0x03, 0xea, 0x3f, 0x0a, 0x3b, 0x20, 0x2a, 0xf4, 0x3c, 0x8c, 0x4b, 0x68, 0xdb, 0x52, 0xb5, - 0x1e, 0x13, 0xe3, 0x92, 0x85, 0xbf, 0x04, 0x3d, 0xcd, 0x4f, 0xc1, 0x6c, 0x03, 0x44, 0xfd, 0x14, - 0x00, 0x0d, 0xaf, 0x4e, 0x16, 0xf5, 0x04, 0x50, 0xe4, 0x58, 0xee, 0xb2, 0xc6, 0xb7, 0x60, 0x2e, - 0x8c, 0xbc, 0xc7, 0x3d, 0xff, 0x31, 0x67, 0x74, 0x20, 0x9e, 0x5c, 0xd2, 0x4b, 0xd1, 0x7c, 0x00, - 0x13, 0x51, 0xf3, 0xaa, 0xea, 0xcc, 0x27, 0x60, 0x42, 0x2f, 0x55, 0x9f, 0xf1, 0xba, 0x1a, 0x63, - 0xa2, 0x78, 0x76, 0x1c, 0x27, 0xce, 0x73, 0x1f, 0xa0, 0x73, 0xed, 0x54, 0xe4, 0x1b, 0x05, 0x79, - 0x47, 0x0b, 0xc1, 0x1d, 0x2d, 0x48, 0x05, 0x50, 0x77, 0xb4, 0x70, 0x40, 0x6a, 0xa1, 0x6f, 0xb9, - 0xcb, 0x13, 0xbf, 0xd0, 0x14, 0x7d, 0x4f, 0x8e, 0x74, 0xfa, 0xe1, 0x0b, 0xd1, 0xa3, 0x07, 0x3d, - 0x88, 0x97, 0x04, 0xe2, 0xca, 0x7f, 0x22, 0xca, 0xd4, 0x3d, 0x8c, 0x86, 0x6a, 0x94, 0x4f, 0xb8, - 0xd5, 0x72, 0x68, 0xec, 0x46, 0x22, 0x18, 0x61, 0xa4, 0x41, 0xd5, 0xa1, 0x88, 0xdf, 0xf8, 0x3d, - 0xd5, 0x21, 0x31, 0x07, 0xb5, 0x2b, 0x04, 0x23, 0xc1, 0x0d, 0x08, 0x3d, 0x82, 0xdf, 0x78, 0x0f, - 0xae, 0x86, 0x67, 0x78, 0x2f, 0xd0, 0x92, 0xcf, 0xa5, 0x94, 0x84, 0x49, 0xd6, 0xe0, 0x7f, 0x52, - 0x62, 0x6c, 0x8b, 0x32, 0xdf, 0xfe, 0xda, 0x8e, 0x14, 0x60, 0x46, 0xcc, 0x97, 0xa2, 0x69, 0x5c, - 0x87, 0x85, 0xf4, 0x48, 0x2a, 0xfb, 0x1e, 0x4c, 0xf7, 0xa8, 0x95, 0x3a, 0xbb, 0xc5, 0x44, 0x5d, - 0xbb, 0xbd, 0x55, 0x6d, 0xa7, 0x68, 0xd7, 0x1c, 0x5e, 0x54, 0xcc, 0x3b, 0x8e, 0x93, 0xc2, 0x1c, - 0x81, 0x24, 0x96, 0xb3, 0x41, 0x86, 0xdf, 0x0c, 0xe4, 0x2b, 0x58, 0x0e, 0xb7, 0xfc, 0x29, 0x3d, - 0xf2, 0x0f, 0x82, 0x59, 0xff, 0x61, 0x80, 0xc1, 0xcc, 0xa8, 0x61, 0x17, 0x01, 0xcc, 0x3a, 0x61, - 0x8c, 0x3a, 0x9d, 0x2b, 0x34, 0xa1, 0x66, 0x4a, 0x16, 0x9a, 0x83, 0xb1, 0x26, 0x77, 0xfd, 0x48, - 0x3c, 0xcb, 0xa3, 0xc1, 0xb0, 0x64, 0xe1, 0x8f, 0x00, 0xf7, 0x0b, 0xae, 0x36, 0xa3, 0xc3, 0xb8, - 0xa7, 0xe6, 0x44, 0xec, 0x91, 0x72, 0x34, 0xc6, 0x45, 0x78, 0x4b, 0x16, 0x42, 0xf6, 0xc1, 0x17, - 0xa1, 0xfc, 0x7b, 0x28, 0x07, 0x63, 0x3d, 0xba, 0x59, 0x0e, 0x87, 0xf8, 0x08, 0xf2, 0xe9, 0x3e, - 0x51, 0xc6, 0x47, 0x80, 0x12, 0x0f, 0x4a, 0xa8, 0x37, 0xcb, 0x89, 0x1a, 0xc6, 0xe3, 0xa8, 0x3a, - 0x5e, 0x21, 0xf1, 0xf8, 0xc5, 0x7f, 0xa6, 0xe0, 0xb2, 0x48, 0x8d, 0x9e, 0xc1, 0xa8, 0xd4, 0x4d, - 0x74, 0x2d, 0x11, 0x2f, 0x29, 0xce, 0xfa, 0xf5, 0xfe, 0x46, 0x12, 0x1b, 0xaf, 0x7f, 0xf7, 0xc7, - 0xdf, 0x3f, 0x5c, 0xba, 0x8e, 0xb0, 0xf1, 0x50, 0x58, 0x3b, 0xa4, 0xea, 0x19, 0xe9, 0xcf, 0x35, - 0x7a, 0xa1, 0x01, 0x74, 0x14, 0x16, 0xad, 0xa7, 0x27, 0x48, 0x93, 0x6f, 0xfd, 0xdd, 0x81, 0x6c, - 0x15, 0xd3, 0xb6, 0x60, 0xba, 0x85, 0x8a, 0x8a, 0xe9, 0xe6, 0x7e, 0x1a, 0x54, 0x47, 0xa7, 0x8d, - 0x93, 0x50, 0x8a, 0xdb, 0xe8, 0x27, 0x0d, 0xc6, 0x43, 0x05, 0x42, 0xab, 0x99, 0x59, 0x63, 0xf2, - 0xa9, 0xaf, 0x0d, 0x60, 0xa9, 0xe8, 0xee, 0x08, 0xba, 0x2d, 0xb4, 0xd9, 0x97, 0x2e, 0xd2, 0xc9, - 0x6e, 0xb8, 0xef, 0x35, 0x98, 0x0c, 0xe3, 0xed, 0x38, 0x4e, 0x16, 0x5f, 0x52, 0xde, 0xb3, 0xf8, - 0x52, 0x44, 0x1a, 0x17, 0x04, 0xdf, 0x2a, 0xba, 0x31, 0x18, 0x1f, 0xfa, 0x45, 0x83, 0xe9, 0x1e, - 0x61, 0xcc, 0x3a, 0xd8, 0x34, 0xb9, 0xcd, 0x3a, 0xd8, 0x54, 0xa5, 0x1d, 0xf0, 0x60, 0x1b, 0xc2, - 0x37, 0xfc, 0x2a, 0x31, 0x4e, 0x02, 0x09, 0x6f, 0xa3, 0x1f, 0x35, 0x58, 0xe8, 0xf7, 0x3d, 0x84, - 0xee, 0xa4, 0x93, 0x0c, 0xf0, 0x15, 0xa7, 0x6f, 0xbf, 0x89, 0xab, 0xba, 0xf7, 0xbf, 0x69, 0x30, - 0xd5, 0xad, 0x88, 0x68, 0x23, 0xb3, 0x95, 0x52, 0x54, 0x59, 0xbf, 0x39, 0xa0, 0xb5, 0xaa, 0xe0, - 0x3d, 0x51, 0xc1, 0x0f, 0xd1, 0xdd, 0xbe, 0x15, 0xec, 0xd1, 0x71, 0xe3, 0x24, 0xfe, 0x54, 0xb5, - 0xd1, 0xcf, 0x1a, 0xcc, 0x74, 0xc7, 0x0f, 0x9a, 0x71, 0x23, 0xb3, 0xc5, 0x2e, 0xc0, 0x9d, 0xf1, - 0xb8, 0xe0, 0xa2, 0xe0, 0xde, 0x40, 0xeb, 0x83, 0x73, 0xa3, 0xdf, 0x35, 0x40, 0x49, 0x89, 0x47, - 0xc5, 0xcc, 0x8a, 0x65, 0x3e, 0x36, 0xfa, 0xd6, 0x85, 0x7c, 0x14, 0xf3, 0x81, 0x60, 0xfe, 0x18, - 0xed, 0xf5, 0x65, 0x66, 0xf4, 0xc8, 0xaf, 0x34, 0x45, 0x84, 0x4a, 0xf8, 0xc4, 0x88, 0x3b, 0xaf, - 0x9e, 0xb6, 0xb6, 0x71, 0xa2, 0x1e, 0xb2, 0x36, 0xfa, 0x55, 0x83, 0x2b, 0xc9, 0x57, 0x67, 0x25, - 0xa3, 0x94, 0x71, 0x43, 0xdd, 0x18, 0xd0, 0xf0, 0x82, 0x52, 0xd5, 0x79, 0xae, 0x8c, 0x13, 0x75, - 0xe9, 0xda, 0xbb, 0xfb, 0x2f, 0xcf, 0xf2, 0xda, 0xab, 0xb3, 0xbc, 0xf6, 0xd7, 0x59, 0x5e, 0x7b, - 0x7e, 0x9e, 0x1f, 0x7a, 0x75, 0x9e, 0x1f, 0xfa, 0xf3, 0x3c, 0x3f, 0xf4, 0xb8, 0x58, 0xb3, 0xfd, - 0x7a, 0xab, 0x5a, 0x30, 0x79, 0x23, 0x2d, 0xec, 0xe1, 0xe6, 0x6d, 0xe3, 0xa8, 0x13, 0xdc, 0x3f, - 0x6e, 0x52, 0xaf, 0x3a, 0x2a, 0xfe, 0x59, 0x6d, 0xfd, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xe8, 0xb0, - 0x27, 0x34, 0x97, 0x0e, 0x00, 0x00, + // 1239 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x97, 0x4d, 0x6f, 0x1b, 0x45, + 0x18, 0xc7, 0xb3, 0x6d, 0x9a, 0xa6, 0x4f, 0xd2, 0x86, 0x0e, 0x81, 0x38, 0x9b, 0xc4, 0x21, 0xd3, + 0xd0, 0xbc, 0x34, 0xf5, 0x12, 0xa7, 0x54, 0x6a, 0x44, 0x05, 0x8e, 0x68, 0x1b, 0xa3, 0x80, 0x82, + 0x5b, 0x2a, 0x54, 0x0e, 0xd6, 0x78, 0x77, 0xb0, 0x57, 0x5d, 0xef, 0xb8, 0xbb, 0xe3, 0x90, 0x10, + 0x59, 0x95, 0xf8, 0x00, 0xa8, 0x02, 0x21, 0x24, 0x6e, 0x45, 0x1c, 0x38, 0xf3, 0x29, 0x7a, 0xa3, + 0x12, 0x17, 0x4e, 0x11, 0x4a, 0xf8, 0x04, 0xfd, 0x04, 0x68, 0x67, 0x67, 0xd7, 0xeb, 0x7d, 0x31, + 0x4e, 0x6f, 0x9e, 0x99, 0xe7, 0xe5, 0x37, 0xcf, 0xcc, 0x3c, 0xff, 0x35, 0xcc, 0xb8, 0xdc, 0x31, + 0x0d, 0xaa, 0xb9, 0x9c, 0x3c, 0xa6, 0x66, 0x4d, 0xd7, 0x9e, 0xb4, 0xa9, 0x73, 0x50, 0x68, 0x39, + 0x8c, 0x33, 0x34, 0xe1, 0x2f, 0x16, 0x82, 0x45, 0x75, 0xb2, 0xce, 0xea, 0x4c, 0xac, 0x69, 0xde, + 0x2f, 0xdf, 0x4c, 0x9d, 0xad, 0x33, 0x56, 0xb7, 0xa8, 0x46, 0x5a, 0xa6, 0x46, 0x6c, 0x9b, 0x71, + 0xc2, 0x4d, 0x66, 0xbb, 0x72, 0x75, 0x55, 0x67, 0x6e, 0x93, 0xb9, 0x5a, 0x8d, 0xb8, 0xd4, 0x8f, + 0xae, 0xed, 0xad, 0xd7, 0x28, 0x27, 0xeb, 0x5a, 0x8b, 0xd4, 0x4d, 0x5b, 0x18, 0x07, 0x91, 0xe2, + 0x34, 0x2d, 0xe2, 0x90, 0x66, 0x10, 0x69, 0x3e, 0xbe, 0xba, 0x47, 0x2c, 0xd3, 0x20, 0x9c, 0x39, + 0x59, 0x06, 0x0d, 0xe6, 0xf2, 0xea, 0xb7, 0xcc, 0xa6, 0xd2, 0xe0, 0x4a, 0xdc, 0x80, 0xb6, 0x98, + 0xde, 0xa8, 0x72, 0x87, 0xe8, 0x8f, 0x69, 0x10, 0x65, 0x29, 0x6e, 0x44, 0x0c, 0xc3, 0xa1, 0xae, + 0x5b, 0x6d, 0xdb, 0x35, 0x66, 0x1b, 0xa6, 0x5d, 0x97, 0x86, 0x0b, 0x71, 0x43, 0xee, 0x10, 0x83, + 0x56, 0x1d, 0xd6, 0xe6, 0x32, 0x21, 0x7e, 0x0a, 0xcb, 0x9f, 0x7b, 0x5b, 0x2e, 0xdb, 0x9c, 0x3a, + 0x7a, 0x83, 0x98, 0x76, 0x49, 0xd7, 0x59, 0xdb, 0xe6, 0x77, 0x1d, 0xd6, 0x2c, 0xf9, 0x71, 0x2b, + 0xf4, 0x49, 0x9b, 0xba, 0x1c, 0x4d, 0xc2, 0x39, 0xf6, 0x8d, 0x4d, 0x9d, 0x9c, 0xf2, 0x8e, 0xb2, + 0x7c, 0xa1, 0xe2, 0x0f, 0xd0, 0x6d, 0xb8, 0xa8, 0x33, 0xdb, 0xa6, 0xba, 0x57, 0xa6, 0xaa, 0x69, + 0xe4, 0xce, 0x78, 0xab, 0x5b, 0xb9, 0x57, 0x47, 0xf3, 0x93, 0x07, 0xa4, 0x69, 0x6d, 0xe2, 0x9e, + 0x65, 0x5c, 0x19, 0xef, 0x8e, 0xcb, 0x06, 0x7e, 0xa6, 0xc0, 0xca, 0x00, 0x04, 0x6e, 0x8b, 0xd9, + 0x2e, 0x45, 0x3a, 0xa8, 0x66, 0x68, 0x57, 0x25, 0xbe, 0x61, 0x55, 0xee, 0xdf, 0xe7, 0xda, 0x7a, + 0xf7, 0xd5, 0xd1, 0xfc, 0x82, 0x9f, 0x39, 0xdb, 0x16, 0x57, 0x72, 0x66, 0x3c, 0xa1, 0x4c, 0x86, + 0x27, 0x01, 0x09, 0xa2, 0x5d, 0x71, 0xb6, 0x72, 0xf7, 0x78, 0x07, 0xde, 0xec, 0x99, 0x95, 0x44, + 0xef, 0xc3, 0x88, 0x7f, 0x07, 0x44, 0xf6, 0xb1, 0xe2, 0x54, 0x21, 0x76, 0x27, 0x0b, 0xbe, 0xc3, + 0xd6, 0xf0, 0x8b, 0xa3, 0xf9, 0xa1, 0x8a, 0x34, 0xc6, 0x37, 0x61, 0x5a, 0x44, 0xbb, 0x47, 0xf9, + 0xc3, 0xe0, 0x92, 0x84, 0x85, 0x9e, 0x86, 0x51, 0x1f, 0xda, 0x34, 0x64, 0xad, 0xcf, 0x8b, 0x71, + 0xd9, 0xc0, 0x5f, 0x82, 0x9a, 0xe6, 0x27, 0x61, 0x36, 0x01, 0xc2, 0x2b, 0xe7, 0x01, 0x9d, 0x5d, + 0x1e, 0x2b, 0xaa, 0x09, 0xa0, 0xd0, 0xb1, 0x12, 0xb1, 0xc6, 0x37, 0x60, 0x2a, 0x88, 0xbc, 0xcd, + 0x5c, 0xfe, 0x88, 0xd9, 0x74, 0x20, 0x9e, 0x5c, 0xd2, 0x4b, 0xd2, 0x7c, 0x00, 0x17, 0xc2, 0xfb, + 0x2d, 0xab, 0x33, 0x9d, 0x80, 0x09, 0xbc, 0x64, 0x7d, 0x46, 0x1b, 0x72, 0x8c, 0x89, 0xe4, 0x29, + 0x59, 0x56, 0x9c, 0xe7, 0x2e, 0x40, 0xf7, 0x65, 0xca, 0xc8, 0x57, 0x0b, 0xfe, 0x33, 0x2e, 0x78, + 0xcf, 0xb8, 0xe0, 0x37, 0x09, 0xf9, 0x8c, 0x0b, 0xbb, 0xa4, 0x1e, 0xf8, 0x56, 0x22, 0x9e, 0xf8, + 0xb9, 0x22, 0xe9, 0x7b, 0x72, 0xa4, 0xd3, 0x9f, 0x3d, 0x15, 0x3d, 0xba, 0xd7, 0x83, 0x78, 0x46, + 0x20, 0x2e, 0xfd, 0x2f, 0xa2, 0x9f, 0xba, 0x87, 0x51, 0x93, 0x17, 0xe5, 0x53, 0x66, 0xb4, 0x2d, + 0x1a, 0x7b, 0x91, 0x08, 0x86, 0x6d, 0xd2, 0xa4, 0xf2, 0x50, 0xc4, 0x6f, 0xfc, 0x9e, 0xbc, 0x21, + 0x31, 0x07, 0xb9, 0x2b, 0x04, 0xc3, 0xde, 0x0b, 0x08, 0x3c, 0xbc, 0xdf, 0x78, 0x1b, 0x66, 0x82, + 0x33, 0xbc, 0xe3, 0xb5, 0x9b, 0x07, 0x7e, 0xb7, 0x09, 0x92, 0xac, 0xc0, 0x1b, 0x7e, 0x17, 0x32, + 0x0d, 0x6a, 0x73, 0xf3, 0x6b, 0x33, 0xec, 0x00, 0x13, 0x62, 0xbe, 0x1c, 0x4e, 0xe3, 0x06, 0xcc, + 0xa6, 0x47, 0x92, 0xd9, 0xb7, 0xe1, 0x62, 0x4f, 0x43, 0x93, 0x67, 0x37, 0x97, 0xa8, 0x6b, 0xd4, + 0x5b, 0xd6, 0x76, 0x9c, 0x46, 0xe6, 0xf0, 0x9c, 0x64, 0x2e, 0x59, 0x56, 0x0a, 0x73, 0x08, 0x92, + 0x58, 0xce, 0x06, 0x39, 0xfb, 0x7a, 0x20, 0x5f, 0xc1, 0x42, 0xb0, 0xe5, 0xcf, 0xe8, 0x3e, 0xdf, + 0xf5, 0x66, 0xf9, 0x7d, 0x0f, 0xc3, 0xd6, 0xc3, 0x0b, 0x3b, 0x07, 0xa0, 0x37, 0x88, 0x6d, 0x53, + 0xab, 0xfb, 0x84, 0x2e, 0xc8, 0x99, 0xb2, 0x81, 0xa6, 0xe0, 0x7c, 0x8b, 0x39, 0x3c, 0x6c, 0x9e, + 0x95, 0x11, 0x6f, 0x58, 0x36, 0xf0, 0x47, 0x80, 0xfb, 0x05, 0x97, 0x9b, 0x51, 0x61, 0xd4, 0x95, + 0x73, 0x22, 0xf6, 0x70, 0x25, 0x1c, 0xe3, 0x22, 0xbc, 0xed, 0x17, 0xc2, 0xbf, 0x07, 0x5f, 0x04, + 0x0a, 0xe1, 0xa2, 0x1c, 0x9c, 0xef, 0xe9, 0x9b, 0x95, 0x60, 0x88, 0xf7, 0x21, 0x9f, 0xee, 0x13, + 0x66, 0x7c, 0x08, 0x28, 0xa1, 0x39, 0x41, 0xbf, 0x59, 0x48, 0xd4, 0x30, 0x1e, 0x47, 0xd6, 0xf1, + 0x32, 0x89, 0xc7, 0xc7, 0x6f, 0xc9, 0x1e, 0x5b, 0xb2, 0xac, 0x07, 0x9e, 0x54, 0x55, 0x3c, 0xa5, + 0x72, 0xb1, 0xde, 0x3d, 0xec, 0xc8, 0x74, 0x48, 0xf3, 0x31, 0x8c, 0x47, 0x84, 0x2d, 0xe0, 0x98, + 0x49, 0x70, 0x74, 0x7d, 0x25, 0xc1, 0x18, 0xef, 0x46, 0x2b, 0x7e, 0x7f, 0x09, 0xce, 0x89, 0x2c, + 0xe8, 0x29, 0x8c, 0xf8, 0x3d, 0x1b, 0x5d, 0x49, 0xc4, 0x48, 0x0a, 0x83, 0xba, 0xd8, 0xdf, 0xc8, + 0x87, 0xc4, 0xab, 0xdf, 0xfd, 0xf5, 0xef, 0x8f, 0x67, 0x16, 0x11, 0xd6, 0xee, 0x0b, 0x6b, 0x8b, + 0xd4, 0x5c, 0x2d, 0xfd, 0x6b, 0x02, 0x3d, 0x57, 0x00, 0xba, 0xdd, 0x1d, 0xad, 0xa6, 0x27, 0x48, + 0x93, 0x0e, 0xf5, 0xda, 0x40, 0xb6, 0x92, 0x69, 0x53, 0x30, 0xdd, 0x40, 0x45, 0xc9, 0x74, 0x7d, + 0x27, 0x0d, 0xaa, 0xab, 0x11, 0xda, 0x61, 0x20, 0x03, 0x1d, 0xf4, 0x8b, 0x02, 0xa3, 0x41, 0xf7, + 0x43, 0xcb, 0x99, 0x59, 0x63, 0xad, 0x5b, 0x5d, 0x19, 0xc0, 0x52, 0xd2, 0xdd, 0x12, 0x74, 0x1b, + 0x68, 0xbd, 0x2f, 0x5d, 0xd8, 0xa3, 0xa3, 0x70, 0x3f, 0x28, 0x30, 0x16, 0xc4, 0x2b, 0x59, 0x56, + 0x16, 0x5f, 0x52, 0x5a, 0xb2, 0xf8, 0x52, 0x04, 0x02, 0x17, 0x04, 0xdf, 0x32, 0xba, 0x3a, 0x18, + 0x1f, 0xfa, 0x4d, 0x81, 0x8b, 0x3d, 0x4d, 0x39, 0xeb, 0x60, 0xd3, 0x5a, 0x7d, 0xd6, 0xc1, 0xa6, + 0x76, 0xf9, 0x01, 0x0f, 0xb6, 0x29, 0x7c, 0x83, 0x2f, 0x22, 0xed, 0xd0, 0x93, 0x8f, 0x0e, 0xfa, + 0x49, 0x81, 0xd9, 0x7e, 0xdf, 0x62, 0xe8, 0x56, 0x3a, 0xc9, 0x00, 0x5f, 0x90, 0xea, 0xe6, 0xeb, + 0xb8, 0xca, 0x57, 0xfe, 0x87, 0x02, 0xe3, 0xd1, 0x6e, 0x8c, 0xd6, 0x32, 0xaf, 0x52, 0x8a, 0x22, + 0xa8, 0xd7, 0x07, 0xb4, 0x96, 0x15, 0xbc, 0x23, 0x2a, 0xf8, 0x21, 0xba, 0xdd, 0xb7, 0x82, 0x3d, + 0x1a, 0xa2, 0x1d, 0xc6, 0x65, 0xb2, 0x83, 0x7e, 0x55, 0x60, 0x22, 0x1a, 0xdf, 0xbb, 0x8c, 0x6b, + 0x99, 0x57, 0xec, 0x14, 0xdc, 0x19, 0xc2, 0x86, 0x8b, 0x82, 0x7b, 0x0d, 0xad, 0x0e, 0xce, 0x8d, + 0xfe, 0x54, 0x00, 0x25, 0xe5, 0x05, 0x15, 0x33, 0x2b, 0x96, 0x29, 0x74, 0xea, 0xc6, 0xa9, 0x7c, + 0x24, 0xf3, 0xae, 0x60, 0xfe, 0x04, 0x6d, 0xf7, 0x65, 0xb6, 0xe9, 0x3e, 0xaf, 0xb6, 0x44, 0x84, + 0x6a, 0x20, 0x6f, 0xe2, 0xcd, 0x4b, 0x59, 0xed, 0x68, 0x87, 0x52, 0x44, 0x3b, 0xe8, 0x77, 0x05, + 0x2e, 0x27, 0x15, 0x6f, 0x29, 0xa3, 0x94, 0x71, 0x43, 0x55, 0x1b, 0xd0, 0xf0, 0x94, 0xad, 0xaa, + 0x2b, 0x95, 0xda, 0xa1, 0x7c, 0x74, 0x1d, 0xf4, 0xb3, 0x02, 0x97, 0x7a, 0x75, 0x0d, 0x2d, 0x66, + 0x1e, 0x79, 0xc4, 0x4a, 0x5d, 0x1b, 0xc4, 0x2a, 0x24, 0x5c, 0x17, 0x84, 0xd7, 0xd0, 0x4a, 0x5f, + 0xc2, 0xa8, 0x8c, 0x6e, 0xed, 0xbc, 0x38, 0xce, 0x2b, 0x2f, 0x8f, 0xf3, 0xca, 0x3f, 0xc7, 0x79, + 0xe5, 0xd9, 0x49, 0x7e, 0xe8, 0xe5, 0x49, 0x7e, 0xe8, 0xef, 0x93, 0xfc, 0xd0, 0xa3, 0x62, 0xdd, + 0xe4, 0x8d, 0x76, 0xad, 0xa0, 0xb3, 0x66, 0x5a, 0xb8, 0xbd, 0xf5, 0x9b, 0xda, 0x7e, 0x24, 0xe8, + 0x41, 0x8b, 0xba, 0xb5, 0x11, 0xf1, 0x7f, 0x73, 0xe3, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa1, + 0xba, 0x20, 0x28, 0xd0, 0x0f, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1066,6 +1153,8 @@ type QueryClient interface { NextPacketSequence(ctx context.Context, in *QueryGetNextPacketSequenceRequest, opts ...grpc.CallOption) (*QueryGetNextPacketSequenceResponse, error) // Queries an address's unbondings AddressUnbondings(ctx context.Context, in *QueryAddressUnbondings, opts ...grpc.CallOption) (*QueryAddressUnbondingsResponse, error) + // Queries all trade routes + AllTradeRoutes(ctx context.Context, in *QueryAllTradeRoutes, opts ...grpc.CallOption) (*QueryAllTradeRoutesResponse, error) } type queryClient struct { @@ -1166,6 +1255,15 @@ func (c *queryClient) AddressUnbondings(ctx context.Context, in *QueryAddressUnb return out, nil } +func (c *queryClient) AllTradeRoutes(ctx context.Context, in *QueryAllTradeRoutes, opts ...grpc.CallOption) (*QueryAllTradeRoutesResponse, error) { + out := new(QueryAllTradeRoutesResponse) + err := c.cc.Invoke(ctx, "/stride.stakeibc.Query/AllTradeRoutes", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Parameters queries the parameters of the module. @@ -1189,6 +1287,8 @@ type QueryServer interface { NextPacketSequence(context.Context, *QueryGetNextPacketSequenceRequest) (*QueryGetNextPacketSequenceResponse, error) // Queries an address's unbondings AddressUnbondings(context.Context, *QueryAddressUnbondings) (*QueryAddressUnbondingsResponse, error) + // Queries all trade routes + AllTradeRoutes(context.Context, *QueryAllTradeRoutes) (*QueryAllTradeRoutesResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -1225,6 +1325,9 @@ func (*UnimplementedQueryServer) NextPacketSequence(ctx context.Context, req *Qu func (*UnimplementedQueryServer) AddressUnbondings(ctx context.Context, req *QueryAddressUnbondings) (*QueryAddressUnbondingsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AddressUnbondings not implemented") } +func (*UnimplementedQueryServer) AllTradeRoutes(ctx context.Context, req *QueryAllTradeRoutes) (*QueryAllTradeRoutesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AllTradeRoutes not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -1410,6 +1513,24 @@ func _Query_AddressUnbondings_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Query_AllTradeRoutes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryAllTradeRoutes) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).AllTradeRoutes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakeibc.Query/AllTradeRoutes", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).AllTradeRoutes(ctx, req.(*QueryAllTradeRoutes)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "stride.stakeibc.Query", HandlerType: (*QueryServer)(nil), @@ -1454,6 +1575,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "AddressUnbondings", Handler: _Query_AddressUnbondings_Handler, }, + { + MethodName: "AllTradeRoutes", + Handler: _Query_AllTradeRoutes_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "stride/stakeibc/query.proto", @@ -2111,6 +2236,66 @@ func (m *QueryAddressUnbondingsResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *QueryAllTradeRoutes) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllTradeRoutes) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllTradeRoutes) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryAllTradeRoutesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryAllTradeRoutesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryAllTradeRoutesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.TradeRoutes) > 0 { + for iNdEx := len(m.TradeRoutes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.TradeRoutes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -2387,6 +2572,30 @@ func (m *QueryAddressUnbondingsResponse) Size() (n int) { return n } +func (m *QueryAllTradeRoutes) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryAllTradeRoutesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.TradeRoutes) > 0 { + for _, e := range m.TradeRoutes { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -4071,6 +4280,140 @@ func (m *QueryAddressUnbondingsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryAllTradeRoutes) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllTradeRoutes: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllTradeRoutes: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryAllTradeRoutesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryAllTradeRoutesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryAllTradeRoutesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TradeRoutes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TradeRoutes = append(m.TradeRoutes, TradeRoute{}) + if err := m.TradeRoutes[len(m.TradeRoutes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/stakeibc/types/query.pb.gw.go b/x/stakeibc/types/query.pb.gw.go index 9f8b481472..09aeee14b9 100644 --- a/x/stakeibc/types/query.pb.gw.go +++ b/x/stakeibc/types/query.pb.gw.go @@ -451,6 +451,24 @@ func local_request_Query_AddressUnbondings_0(ctx context.Context, marshaler runt } +func request_Query_AllTradeRoutes_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllTradeRoutes + var metadata runtime.ServerMetadata + + msg, err := client.AllTradeRoutes(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_AllTradeRoutes_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryAllTradeRoutes + var metadata runtime.ServerMetadata + + msg, err := server.AllTradeRoutes(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -664,6 +682,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_AllTradeRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_AllTradeRoutes_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllTradeRoutes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -885,6 +926,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_AllTradeRoutes_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_AllTradeRoutes_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_AllTradeRoutes_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -906,6 +967,8 @@ var ( pattern_Query_NextPacketSequence_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"Stride-Labs", "stride", "stakeibc", "next_packet_sequence", "channel_id", "port_id"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_AddressUnbondings_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"Stride-Labs", "stride", "stakeibc", "unbondings", "address"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_AllTradeRoutes_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"Stride-Labs", "stride", "stakeibc", "trade_routes"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -926,4 +989,6 @@ var ( forward_Query_NextPacketSequence_0 = runtime.ForwardResponseMessage forward_Query_AddressUnbondings_0 = runtime.ForwardResponseMessage + + forward_Query_AllTradeRoutes_0 = runtime.ForwardResponseMessage ) diff --git a/x/stakeibc/types/trade_route.go b/x/stakeibc/types/trade_route.go new file mode 100644 index 0000000000..c209088718 --- /dev/null +++ b/x/stakeibc/types/trade_route.go @@ -0,0 +1,23 @@ +package types + +import fmt "fmt" + +// Builds the store key (as a string) from the reward and host denom's +func GetTradeRouteId(rewardDenom, hostDenom string) string { + return rewardDenom + "-" + hostDenom +} + +// Builds the store key (as a string) from the reward and host denom's +func (t TradeRoute) GetRouteId() string { + return GetTradeRouteId(t.RewardDenomOnRewardZone, t.HostDenomOnHostZone) +} + +// Builds the store key from the reward and host denom's +func (t TradeRoute) GetKey() []byte { + return TradeRouteKeyFromDenoms(t.RewardDenomOnRewardZone, t.HostDenomOnHostZone) +} + +// Human readable description for logging +func (t TradeRoute) Description() string { + return fmt.Sprintf("TradeRoute from %s to %s", t.RewardDenomOnRewardZone, t.HostDenomOnHostZone) +} diff --git a/x/stakeibc/types/trade_route.pb.go b/x/stakeibc/types/trade_route.pb.go new file mode 100644 index 0000000000..bb5b11aa9f --- /dev/null +++ b/x/stakeibc/types/trade_route.pb.go @@ -0,0 +1,1333 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: stride/stakeibc/trade_route.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Stores pool information needed to execute the swap along a trade route +type TradeConfig struct { + // Currently Osmosis is the only trade chain so this is an osmosis pool id + PoolId uint64 `protobuf:"varint,1,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // Spot price in the pool to convert the reward denom to the host denom + // output_tokens = swap_price * input tokens + // This value may be slightly stale as it is updated by an ICQ + SwapPrice github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,2,opt,name=swap_price,json=swapPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"swap_price"` + // unix time in seconds that the price was last updated + PriceUpdateTimestamp uint64 `protobuf:"varint,3,opt,name=price_update_timestamp,json=priceUpdateTimestamp,proto3" json:"price_update_timestamp,omitempty"` + // Threshold defining the percentage of tokens that could be lost in the trade + // This captures both the loss from slippage and from a stale price on stride + // 0.05 means the output from the trade can be no less than a 5% deviation + // from the current value + MaxAllowedSwapLossRate github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=max_allowed_swap_loss_rate,json=maxAllowedSwapLossRate,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"max_allowed_swap_loss_rate"` + // min and max set boundaries of reward denom on trade chain we will swap + // min also decides when reward token transfers are worth it (transfer fees) + MinSwapAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,5,opt,name=min_swap_amount,json=minSwapAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_swap_amount"` + MaxSwapAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=max_swap_amount,json=maxSwapAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_swap_amount"` +} + +func (m *TradeConfig) Reset() { *m = TradeConfig{} } +func (m *TradeConfig) String() string { return proto.CompactTextString(m) } +func (*TradeConfig) ProtoMessage() {} +func (*TradeConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_c252b142ecf88017, []int{0} +} +func (m *TradeConfig) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TradeConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TradeConfig.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TradeConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_TradeConfig.Merge(m, src) +} +func (m *TradeConfig) XXX_Size() int { + return m.Size() +} +func (m *TradeConfig) XXX_DiscardUnknown() { + xxx_messageInfo_TradeConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_TradeConfig proto.InternalMessageInfo + +func (m *TradeConfig) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *TradeConfig) GetPriceUpdateTimestamp() uint64 { + if m != nil { + return m.PriceUpdateTimestamp + } + return 0 +} + +// TradeRoute represents a round trip including info on transfer and how to do +// the swap. It makes the assumption that the reward token is always foreign to +// the host so therefore the first two hops are to unwind the ibc denom enroute +// to the trade chain and the last hop is the return so funds start/end in the +// withdrawl ICA on hostZone +// The structure is key'd on reward denom and host denom in their native forms +// (i.e. reward_denom_on_reward_zone and host_denom_on_host_zone) +type TradeRoute struct { + // ibc denom for the reward on the host zone + RewardDenomOnHostZone string `protobuf:"bytes,1,opt,name=reward_denom_on_host_zone,json=rewardDenomOnHostZone,proto3" json:"reward_denom_on_host_zone,omitempty"` + // should be the native denom for the reward chain + RewardDenomOnRewardZone string `protobuf:"bytes,2,opt,name=reward_denom_on_reward_zone,json=rewardDenomOnRewardZone,proto3" json:"reward_denom_on_reward_zone,omitempty"` + // ibc denom of the reward on the trade chain, input to the swap + RewardDenomOnTradeZone string `protobuf:"bytes,3,opt,name=reward_denom_on_trade_zone,json=rewardDenomOnTradeZone,proto3" json:"reward_denom_on_trade_zone,omitempty"` + // ibc of the host denom on the trade chain, output from the swap + HostDenomOnTradeZone string `protobuf:"bytes,4,opt,name=host_denom_on_trade_zone,json=hostDenomOnTradeZone,proto3" json:"host_denom_on_trade_zone,omitempty"` + // should be the same as the native host denom on the host chain + HostDenomOnHostZone string `protobuf:"bytes,5,opt,name=host_denom_on_host_zone,json=hostDenomOnHostZone,proto3" json:"host_denom_on_host_zone,omitempty"` + // ICAAccount on the host zone with the reward tokens + // This is the same as the host zone withdrawal ICA account + HostAccount ICAAccount `protobuf:"bytes,6,opt,name=host_account,json=hostAccount,proto3" json:"host_account"` + // ICAAccount on the reward zone that is acts as the intermediate + // receiver of the transfer from host zone to trade zone + RewardAccount ICAAccount `protobuf:"bytes,7,opt,name=reward_account,json=rewardAccount,proto3" json:"reward_account"` + // ICAAccount responsible for executing the swap of reward + // tokens for host tokens + TradeAccount ICAAccount `protobuf:"bytes,8,opt,name=trade_account,json=tradeAccount,proto3" json:"trade_account"` + // Channel responsible for the transfer of reward tokens from the host + // zone to the reward zone. This is the channel ID on the host zone side + HostToRewardChannelId string `protobuf:"bytes,9,opt,name=host_to_reward_channel_id,json=hostToRewardChannelId,proto3" json:"host_to_reward_channel_id,omitempty"` + // Channel responsible for the transfer of reward tokens from the reward + // zone to the trade zone. This is the channel ID on the reward zone side + RewardToTradeChannelId string `protobuf:"bytes,10,opt,name=reward_to_trade_channel_id,json=rewardToTradeChannelId,proto3" json:"reward_to_trade_channel_id,omitempty"` + // Channel responsible for the transfer of host tokens from the trade + // zone, back to the host zone. This is the channel ID on the trade zone side + TradeToHostChannelId string `protobuf:"bytes,11,opt,name=trade_to_host_channel_id,json=tradeToHostChannelId,proto3" json:"trade_to_host_channel_id,omitempty"` + // specifies the configuration needed to execute the swap + // such as pool_id, slippage, min trade amount, etc. + TradeConfig TradeConfig `protobuf:"bytes,12,opt,name=trade_config,json=tradeConfig,proto3" json:"trade_config"` +} + +func (m *TradeRoute) Reset() { *m = TradeRoute{} } +func (m *TradeRoute) String() string { return proto.CompactTextString(m) } +func (*TradeRoute) ProtoMessage() {} +func (*TradeRoute) Descriptor() ([]byte, []int) { + return fileDescriptor_c252b142ecf88017, []int{1} +} +func (m *TradeRoute) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TradeRoute) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_TradeRoute.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *TradeRoute) XXX_Merge(src proto.Message) { + xxx_messageInfo_TradeRoute.Merge(m, src) +} +func (m *TradeRoute) XXX_Size() int { + return m.Size() +} +func (m *TradeRoute) XXX_DiscardUnknown() { + xxx_messageInfo_TradeRoute.DiscardUnknown(m) +} + +var xxx_messageInfo_TradeRoute proto.InternalMessageInfo + +func (m *TradeRoute) GetRewardDenomOnHostZone() string { + if m != nil { + return m.RewardDenomOnHostZone + } + return "" +} + +func (m *TradeRoute) GetRewardDenomOnRewardZone() string { + if m != nil { + return m.RewardDenomOnRewardZone + } + return "" +} + +func (m *TradeRoute) GetRewardDenomOnTradeZone() string { + if m != nil { + return m.RewardDenomOnTradeZone + } + return "" +} + +func (m *TradeRoute) GetHostDenomOnTradeZone() string { + if m != nil { + return m.HostDenomOnTradeZone + } + return "" +} + +func (m *TradeRoute) GetHostDenomOnHostZone() string { + if m != nil { + return m.HostDenomOnHostZone + } + return "" +} + +func (m *TradeRoute) GetHostAccount() ICAAccount { + if m != nil { + return m.HostAccount + } + return ICAAccount{} +} + +func (m *TradeRoute) GetRewardAccount() ICAAccount { + if m != nil { + return m.RewardAccount + } + return ICAAccount{} +} + +func (m *TradeRoute) GetTradeAccount() ICAAccount { + if m != nil { + return m.TradeAccount + } + return ICAAccount{} +} + +func (m *TradeRoute) GetHostToRewardChannelId() string { + if m != nil { + return m.HostToRewardChannelId + } + return "" +} + +func (m *TradeRoute) GetRewardToTradeChannelId() string { + if m != nil { + return m.RewardToTradeChannelId + } + return "" +} + +func (m *TradeRoute) GetTradeToHostChannelId() string { + if m != nil { + return m.TradeToHostChannelId + } + return "" +} + +func (m *TradeRoute) GetTradeConfig() TradeConfig { + if m != nil { + return m.TradeConfig + } + return TradeConfig{} +} + +func init() { + proto.RegisterType((*TradeConfig)(nil), "stride.stakeibc.TradeConfig") + proto.RegisterType((*TradeRoute)(nil), "stride.stakeibc.TradeRoute") +} + +func init() { proto.RegisterFile("stride/stakeibc/trade_route.proto", fileDescriptor_c252b142ecf88017) } + +var fileDescriptor_c252b142ecf88017 = []byte{ + // 661 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0xcf, 0x4f, 0x13, 0x41, + 0x14, 0xc7, 0x5b, 0xf9, 0x65, 0xa7, 0x45, 0x92, 0x15, 0x61, 0x29, 0xa6, 0x20, 0x07, 0xc3, 0x85, + 0xdd, 0x88, 0x84, 0x10, 0xc3, 0xa5, 0x50, 0x0d, 0x4d, 0x48, 0x34, 0x4b, 0xf5, 0x80, 0x87, 0xc9, + 0x74, 0x77, 0x2c, 0x1b, 0xba, 0xf3, 0x36, 0x3b, 0x53, 0xbb, 0xfa, 0x57, 0xf8, 0xc7, 0xf8, 0x47, + 0x70, 0x24, 0x9e, 0x8c, 0x07, 0x62, 0xe8, 0x9f, 0xe1, 0xc5, 0xcc, 0x9b, 0x5d, 0xd8, 0x82, 0x07, + 0x34, 0x9e, 0xda, 0xd9, 0xf7, 0x3e, 0xdf, 0x37, 0x6f, 0xbe, 0x33, 0x8f, 0x3c, 0x91, 0x2a, 0x09, + 0x03, 0xee, 0x4a, 0xc5, 0x4e, 0x79, 0xd8, 0xf5, 0x5d, 0x95, 0xb0, 0x80, 0xd3, 0x04, 0x06, 0x8a, + 0x3b, 0x71, 0x02, 0x0a, 0xac, 0x39, 0x93, 0xe2, 0xe4, 0x29, 0xf5, 0xf9, 0x1e, 0xf4, 0x00, 0x63, + 0xae, 0xfe, 0x67, 0xd2, 0xea, 0xb7, 0x94, 0x42, 0x9f, 0x51, 0xe6, 0xfb, 0x30, 0x10, 0x2a, 0x4b, + 0x59, 0xf2, 0x41, 0x46, 0x20, 0xa9, 0x61, 0xcd, 0xc2, 0x84, 0xd6, 0x46, 0x13, 0xa4, 0xda, 0xd1, + 0xa5, 0xf7, 0x41, 0x7c, 0x08, 0x7b, 0xd6, 0x22, 0x99, 0x89, 0x01, 0xfa, 0x34, 0x0c, 0xec, 0xf2, + 0x6a, 0x79, 0x7d, 0xd2, 0x9b, 0xd6, 0xcb, 0x76, 0x60, 0xbd, 0x27, 0x44, 0x0e, 0x59, 0x4c, 0xe3, + 0x24, 0xf4, 0xb9, 0x7d, 0x6f, 0xb5, 0xbc, 0x5e, 0xd9, 0xdb, 0x3d, 0xbb, 0x58, 0x29, 0xfd, 0xb8, + 0x58, 0x79, 0xda, 0x0b, 0xd5, 0xc9, 0xa0, 0xeb, 0xf8, 0x10, 0x65, 0xea, 0xd9, 0xcf, 0x86, 0x0c, + 0x4e, 0x5d, 0xf5, 0x29, 0xe6, 0xd2, 0x69, 0x71, 0xff, 0xdb, 0xd7, 0x0d, 0x92, 0x15, 0x6f, 0x71, + 0xdf, 0xab, 0x68, 0xbd, 0x37, 0x5a, 0xce, 0xda, 0x22, 0x0b, 0xa8, 0x4b, 0x07, 0x71, 0xc0, 0x14, + 0xa7, 0x2a, 0x8c, 0xb8, 0x54, 0x2c, 0x8a, 0xed, 0x09, 0xdc, 0xc4, 0x3c, 0x46, 0xdf, 0x62, 0xb0, + 0x93, 0xc7, 0xac, 0x94, 0xd4, 0x23, 0x96, 0x52, 0xd6, 0xef, 0xc3, 0x90, 0x07, 0x14, 0xb7, 0xd7, + 0x07, 0x29, 0x69, 0xc2, 0x14, 0xb7, 0x27, 0xff, 0xc3, 0x16, 0x17, 0x22, 0x96, 0x36, 0x8d, 0xfc, + 0xd1, 0x90, 0xc5, 0x87, 0x20, 0xa5, 0xc7, 0x14, 0xb7, 0xde, 0x91, 0xb9, 0x28, 0x14, 0xa6, 0x22, + 0x8b, 0xf4, 0x49, 0xdb, 0x53, 0x58, 0xce, 0xf9, 0x8b, 0x72, 0x6d, 0xa1, 0xbc, 0xd9, 0x28, 0x14, + 0x5a, 0xb9, 0x89, 0x22, 0xa8, 0xcb, 0xd2, 0x31, 0xdd, 0xe9, 0x7f, 0xd4, 0x65, 0xe9, 0xb5, 0xee, + 0xda, 0xaf, 0x29, 0x42, 0xd0, 0x65, 0x4f, 0xdf, 0x2f, 0x6b, 0x87, 0x2c, 0x25, 0x7c, 0xc8, 0x92, + 0x80, 0x06, 0x5c, 0x40, 0x44, 0x41, 0xd0, 0x13, 0x90, 0x8a, 0x7e, 0x06, 0xc1, 0xd1, 0xf6, 0x8a, + 0xf7, 0xc8, 0x24, 0xb4, 0x74, 0xfc, 0xb5, 0x38, 0x00, 0xa9, 0x8e, 0x41, 0x70, 0x6b, 0x97, 0x2c, + 0xdf, 0x24, 0xb3, 0x35, 0xb2, 0x78, 0x2d, 0xbc, 0xc5, 0x31, 0xd6, 0xc3, 0x05, 0xd2, 0x2f, 0x48, + 0xfd, 0x26, 0x6d, 0xae, 0x3d, 0xc2, 0x13, 0x08, 0x2f, 0x8c, 0xc1, 0xb8, 0x69, 0x64, 0xb7, 0x89, + 0x8d, 0x7b, 0xfc, 0x13, 0x89, 0x56, 0x7b, 0xf3, 0x3a, 0x7e, 0x8b, 0xdb, 0x22, 0x8b, 0xe3, 0xdc, + 0x75, 0xa7, 0x68, 0x99, 0xf7, 0xb0, 0x80, 0x5d, 0xf5, 0xd9, 0x22, 0x35, 0xcc, 0xcb, 0xde, 0x11, + 0xba, 0x50, 0xdd, 0x5c, 0x76, 0x6e, 0x3c, 0x49, 0xa7, 0xbd, 0xdf, 0x6c, 0x9a, 0x94, 0xbd, 0x49, + 0x6d, 0x91, 0x57, 0xd5, 0x58, 0xf6, 0xc9, 0x3a, 0x20, 0x0f, 0xb2, 0x7e, 0x73, 0x9d, 0x99, 0xbb, + 0xea, 0xcc, 0x1a, 0x30, 0x57, 0x7a, 0x45, 0x66, 0x4d, 0xbf, 0xb9, 0xd0, 0xfd, 0xbb, 0x0a, 0xd5, + 0x90, 0xcb, 0x75, 0x76, 0xc8, 0x12, 0xf6, 0xa5, 0x20, 0xf7, 0xcd, 0x3f, 0x61, 0x42, 0x70, 0x7c, + 0xf0, 0x15, 0xe3, 0xbc, 0x4e, 0xe8, 0x80, 0xb1, 0x6d, 0xdf, 0x44, 0xdb, 0x41, 0xc1, 0x3b, 0x05, + 0xd9, 0xd9, 0x17, 0x50, 0x52, 0xf4, 0xae, 0x03, 0x66, 0xa2, 0x5c, 0xb1, 0xdb, 0xc4, 0x36, 0x84, + 0x02, 0x73, 0xfc, 0x05, 0xb2, 0x6a, 0xbc, 0xc3, 0x78, 0x07, 0xb4, 0x01, 0xd7, 0xdc, 0x4b, 0x52, + 0xcb, 0x2a, 0xe1, 0x70, 0xb2, 0x6b, 0xd8, 0xf4, 0xe3, 0x5b, 0x4d, 0x17, 0x06, 0x58, 0x6e, 0x83, + 0x2a, 0x7c, 0x3a, 0x3c, 0xbb, 0x6c, 0x94, 0xcf, 0x2f, 0x1b, 0xe5, 0x9f, 0x97, 0x8d, 0xf2, 0x97, + 0x51, 0xa3, 0x74, 0x3e, 0x6a, 0x94, 0xbe, 0x8f, 0x1a, 0xa5, 0xe3, 0xcd, 0xc2, 0x73, 0x3a, 0x42, + 0xd1, 0x8d, 0x43, 0xd6, 0x95, 0x6e, 0x36, 0x52, 0x3f, 0x3e, 0xdb, 0x76, 0xd3, 0xc2, 0x88, 0xd6, + 0xcf, 0xab, 0x3b, 0x8d, 0x83, 0xf3, 0xf9, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x7e, 0xc7, + 0x96, 0xc2, 0x05, 0x00, 0x00, +} + +func (m *TradeConfig) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TradeConfig) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TradeConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.MaxSwapAmount.Size() + i -= size + if _, err := m.MaxSwapAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTradeRoute(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size := m.MinSwapAmount.Size() + i -= size + if _, err := m.MinSwapAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTradeRoute(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + { + size := m.MaxAllowedSwapLossRate.Size() + i -= size + if _, err := m.MaxAllowedSwapLossRate.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTradeRoute(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if m.PriceUpdateTimestamp != 0 { + i = encodeVarintTradeRoute(dAtA, i, uint64(m.PriceUpdateTimestamp)) + i-- + dAtA[i] = 0x18 + } + { + size := m.SwapPrice.Size() + i -= size + if _, err := m.SwapPrice.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTradeRoute(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if m.PoolId != 0 { + i = encodeVarintTradeRoute(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *TradeRoute) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TradeRoute) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TradeRoute) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.TradeConfig.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTradeRoute(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x62 + if len(m.TradeToHostChannelId) > 0 { + i -= len(m.TradeToHostChannelId) + copy(dAtA[i:], m.TradeToHostChannelId) + i = encodeVarintTradeRoute(dAtA, i, uint64(len(m.TradeToHostChannelId))) + i-- + dAtA[i] = 0x5a + } + if len(m.RewardToTradeChannelId) > 0 { + i -= len(m.RewardToTradeChannelId) + copy(dAtA[i:], m.RewardToTradeChannelId) + i = encodeVarintTradeRoute(dAtA, i, uint64(len(m.RewardToTradeChannelId))) + i-- + dAtA[i] = 0x52 + } + if len(m.HostToRewardChannelId) > 0 { + i -= len(m.HostToRewardChannelId) + copy(dAtA[i:], m.HostToRewardChannelId) + i = encodeVarintTradeRoute(dAtA, i, uint64(len(m.HostToRewardChannelId))) + i-- + dAtA[i] = 0x4a + } + { + size, err := m.TradeAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTradeRoute(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + { + size, err := m.RewardAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTradeRoute(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3a + { + size, err := m.HostAccount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTradeRoute(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + if len(m.HostDenomOnHostZone) > 0 { + i -= len(m.HostDenomOnHostZone) + copy(dAtA[i:], m.HostDenomOnHostZone) + i = encodeVarintTradeRoute(dAtA, i, uint64(len(m.HostDenomOnHostZone))) + i-- + dAtA[i] = 0x2a + } + if len(m.HostDenomOnTradeZone) > 0 { + i -= len(m.HostDenomOnTradeZone) + copy(dAtA[i:], m.HostDenomOnTradeZone) + i = encodeVarintTradeRoute(dAtA, i, uint64(len(m.HostDenomOnTradeZone))) + i-- + dAtA[i] = 0x22 + } + if len(m.RewardDenomOnTradeZone) > 0 { + i -= len(m.RewardDenomOnTradeZone) + copy(dAtA[i:], m.RewardDenomOnTradeZone) + i = encodeVarintTradeRoute(dAtA, i, uint64(len(m.RewardDenomOnTradeZone))) + i-- + dAtA[i] = 0x1a + } + if len(m.RewardDenomOnRewardZone) > 0 { + i -= len(m.RewardDenomOnRewardZone) + copy(dAtA[i:], m.RewardDenomOnRewardZone) + i = encodeVarintTradeRoute(dAtA, i, uint64(len(m.RewardDenomOnRewardZone))) + i-- + dAtA[i] = 0x12 + } + if len(m.RewardDenomOnHostZone) > 0 { + i -= len(m.RewardDenomOnHostZone) + copy(dAtA[i:], m.RewardDenomOnHostZone) + i = encodeVarintTradeRoute(dAtA, i, uint64(len(m.RewardDenomOnHostZone))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintTradeRoute(dAtA []byte, offset int, v uint64) int { + offset -= sovTradeRoute(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *TradeConfig) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.PoolId != 0 { + n += 1 + sovTradeRoute(uint64(m.PoolId)) + } + l = m.SwapPrice.Size() + n += 1 + l + sovTradeRoute(uint64(l)) + if m.PriceUpdateTimestamp != 0 { + n += 1 + sovTradeRoute(uint64(m.PriceUpdateTimestamp)) + } + l = m.MaxAllowedSwapLossRate.Size() + n += 1 + l + sovTradeRoute(uint64(l)) + l = m.MinSwapAmount.Size() + n += 1 + l + sovTradeRoute(uint64(l)) + l = m.MaxSwapAmount.Size() + n += 1 + l + sovTradeRoute(uint64(l)) + return n +} + +func (m *TradeRoute) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.RewardDenomOnHostZone) + if l > 0 { + n += 1 + l + sovTradeRoute(uint64(l)) + } + l = len(m.RewardDenomOnRewardZone) + if l > 0 { + n += 1 + l + sovTradeRoute(uint64(l)) + } + l = len(m.RewardDenomOnTradeZone) + if l > 0 { + n += 1 + l + sovTradeRoute(uint64(l)) + } + l = len(m.HostDenomOnTradeZone) + if l > 0 { + n += 1 + l + sovTradeRoute(uint64(l)) + } + l = len(m.HostDenomOnHostZone) + if l > 0 { + n += 1 + l + sovTradeRoute(uint64(l)) + } + l = m.HostAccount.Size() + n += 1 + l + sovTradeRoute(uint64(l)) + l = m.RewardAccount.Size() + n += 1 + l + sovTradeRoute(uint64(l)) + l = m.TradeAccount.Size() + n += 1 + l + sovTradeRoute(uint64(l)) + l = len(m.HostToRewardChannelId) + if l > 0 { + n += 1 + l + sovTradeRoute(uint64(l)) + } + l = len(m.RewardToTradeChannelId) + if l > 0 { + n += 1 + l + sovTradeRoute(uint64(l)) + } + l = len(m.TradeToHostChannelId) + if l > 0 { + n += 1 + l + sovTradeRoute(uint64(l)) + } + l = m.TradeConfig.Size() + n += 1 + l + sovTradeRoute(uint64(l)) + return n +} + +func sovTradeRoute(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTradeRoute(x uint64) (n int) { + return sovTradeRoute(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *TradeConfig) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TradeConfig: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TradeConfig: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) + } + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SwapPrice", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.SwapPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PriceUpdateTimestamp", wireType) + } + m.PriceUpdateTimestamp = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PriceUpdateTimestamp |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxAllowedSwapLossRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxAllowedSwapLossRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinSwapAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinSwapAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxSwapAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxSwapAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTradeRoute(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTradeRoute + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TradeRoute) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TradeRoute: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TradeRoute: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenomOnHostZone", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardDenomOnHostZone = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenomOnRewardZone", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardDenomOnRewardZone = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenomOnTradeZone", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardDenomOnTradeZone = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostDenomOnTradeZone", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostDenomOnTradeZone = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostDenomOnHostZone", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostDenomOnHostZone = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.HostAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.RewardAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TradeAccount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TradeAccount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostToRewardChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostToRewardChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardToTradeChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardToTradeChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TradeToHostChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + 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 ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TradeToHostChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TradeConfig", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTradeRoute + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTradeRoute + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TradeConfig.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTradeRoute(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTradeRoute + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTradeRoute(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTradeRoute + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTradeRoute + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTradeRoute + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTradeRoute + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTradeRoute = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTradeRoute = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTradeRoute = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/stakeibc/types/tx.pb.go b/x/stakeibc/types/tx.pb.go index a96e7df94c..c1172c2719 100644 --- a/x/stakeibc/types/tx.pb.go +++ b/x/stakeibc/types/tx.pb.go @@ -9,6 +9,8 @@ import ( _ "github.com/cosmos/cosmos-proto" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" @@ -1094,9 +1096,10 @@ func (m *MsgDeleteValidatorResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgDeleteValidatorResponse proto.InternalMessageInfo type MsgRestoreInterchainAccount struct { - Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` - ChainId string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` - AccountType ICAAccountType `protobuf:"varint,3,opt,name=account_type,json=accountType,proto3,enum=stride.stakeibc.ICAAccountType" json:"account_type,omitempty"` + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + ChainId string `protobuf:"bytes,2,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + ConnectionId string `protobuf:"bytes,3,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` + AccountOwner string `protobuf:"bytes,4,opt,name=account_owner,json=accountOwner,proto3" json:"account_owner,omitempty"` } func (m *MsgRestoreInterchainAccount) Reset() { *m = MsgRestoreInterchainAccount{} } @@ -1146,11 +1149,18 @@ func (m *MsgRestoreInterchainAccount) GetChainId() string { return "" } -func (m *MsgRestoreInterchainAccount) GetAccountType() ICAAccountType { +func (m *MsgRestoreInterchainAccount) GetConnectionId() string { + if m != nil { + return m.ConnectionId + } + return "" +} + +func (m *MsgRestoreInterchainAccount) GetAccountOwner() string { if m != nil { - return m.AccountType + return m.AccountOwner } - return ICAAccountType_DELEGATION + return "" } type MsgRestoreInterchainAccountResponse struct { @@ -1552,6 +1562,441 @@ func (m *MsgResumeHostZoneResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgResumeHostZoneResponse proto.InternalMessageInfo +// Creates a new trade route +type MsgCreateTradeRoute struct { + // authority is the address that controls the module (defaults to x/gov unless + // overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // The chain ID of the host zone + HostChainId string `protobuf:"bytes,2,opt,name=host_chain_id,json=hostChainId,proto3" json:"host_chain_id,omitempty"` + // Connection IDs between stride and the other zones + StrideToRewardConnectionId string `protobuf:"bytes,3,opt,name=stride_to_reward_connection_id,json=strideToRewardConnectionId,proto3" json:"stride_to_reward_connection_id,omitempty"` + StrideToTradeConnectionId string `protobuf:"bytes,4,opt,name=stride_to_trade_connection_id,json=strideToTradeConnectionId,proto3" json:"stride_to_trade_connection_id,omitempty"` + // Transfer channels between the host, reward, and trade zones + HostToRewardTransferChannelId string `protobuf:"bytes,5,opt,name=host_to_reward_transfer_channel_id,json=hostToRewardTransferChannelId,proto3" json:"host_to_reward_transfer_channel_id,omitempty"` + RewardToTradeTransferChannelId string `protobuf:"bytes,6,opt,name=reward_to_trade_transfer_channel_id,json=rewardToTradeTransferChannelId,proto3" json:"reward_to_trade_transfer_channel_id,omitempty"` + TradeToHostTransferChannelId string `protobuf:"bytes,7,opt,name=trade_to_host_transfer_channel_id,json=tradeToHostTransferChannelId,proto3" json:"trade_to_host_transfer_channel_id,omitempty"` + // ibc denom for the reward token on the host zone (e.g. ibc/usdc on dYdX) + RewardDenomOnHost string `protobuf:"bytes,8,opt,name=reward_denom_on_host,json=rewardDenomOnHost,proto3" json:"reward_denom_on_host,omitempty"` + // native denom of reward token on the reward zone (e.g. usdc on Noble) + RewardDenomOnReward string `protobuf:"bytes,9,opt,name=reward_denom_on_reward,json=rewardDenomOnReward,proto3" json:"reward_denom_on_reward,omitempty"` + // ibc denom of the reward token on the trade zone (e.g. ibc/usdc on Osmosis) + RewardDenomOnTrade string `protobuf:"bytes,10,opt,name=reward_denom_on_trade,json=rewardDenomOnTrade,proto3" json:"reward_denom_on_trade,omitempty"` + // ibc denom of the host's token on the trade zone (e.g. ibc/dydx on Osmosis) + HostDenomOnTrade string `protobuf:"bytes,11,opt,name=host_denom_on_trade,json=hostDenomOnTrade,proto3" json:"host_denom_on_trade,omitempty"` + // the host zone's native denom (e.g. dydx on dYdX) + HostDenomOnHost string `protobuf:"bytes,12,opt,name=host_denom_on_host,json=hostDenomOnHost,proto3" json:"host_denom_on_host,omitempty"` + // The osmosis pool ID + PoolId uint64 `protobuf:"varint,13,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // Threshold defining the percentage of tokens that could be lost in the trade + // This captures both the loss from slippage and from a stale price on stride + // "0.05" means the output from the trade can be no less than a 5% deviation + // from the current value + MaxAllowedSwapLossRate string `protobuf:"bytes,14,opt,name=max_allowed_swap_loss_rate,json=maxAllowedSwapLossRate,proto3" json:"max_allowed_swap_loss_rate,omitempty"` + // minimum amount of reward tokens to initate a swap + // if not provided, defaults to 0 + MinSwapAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,15,opt,name=min_swap_amount,json=minSwapAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_swap_amount"` + // maximum amount of reward tokens in a single swap + // if not provided, defaults to 10e24 + MaxSwapAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,16,opt,name=max_swap_amount,json=maxSwapAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_swap_amount"` +} + +func (m *MsgCreateTradeRoute) Reset() { *m = MsgCreateTradeRoute{} } +func (m *MsgCreateTradeRoute) String() string { return proto.CompactTextString(m) } +func (*MsgCreateTradeRoute) ProtoMessage() {} +func (*MsgCreateTradeRoute) Descriptor() ([]byte, []int) { + return fileDescriptor_9b7e09c9ad51cd54, []int{32} +} +func (m *MsgCreateTradeRoute) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateTradeRoute) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateTradeRoute.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateTradeRoute) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateTradeRoute.Merge(m, src) +} +func (m *MsgCreateTradeRoute) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateTradeRoute) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateTradeRoute.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateTradeRoute proto.InternalMessageInfo + +func (m *MsgCreateTradeRoute) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgCreateTradeRoute) GetHostChainId() string { + if m != nil { + return m.HostChainId + } + return "" +} + +func (m *MsgCreateTradeRoute) GetStrideToRewardConnectionId() string { + if m != nil { + return m.StrideToRewardConnectionId + } + return "" +} + +func (m *MsgCreateTradeRoute) GetStrideToTradeConnectionId() string { + if m != nil { + return m.StrideToTradeConnectionId + } + return "" +} + +func (m *MsgCreateTradeRoute) GetHostToRewardTransferChannelId() string { + if m != nil { + return m.HostToRewardTransferChannelId + } + return "" +} + +func (m *MsgCreateTradeRoute) GetRewardToTradeTransferChannelId() string { + if m != nil { + return m.RewardToTradeTransferChannelId + } + return "" +} + +func (m *MsgCreateTradeRoute) GetTradeToHostTransferChannelId() string { + if m != nil { + return m.TradeToHostTransferChannelId + } + return "" +} + +func (m *MsgCreateTradeRoute) GetRewardDenomOnHost() string { + if m != nil { + return m.RewardDenomOnHost + } + return "" +} + +func (m *MsgCreateTradeRoute) GetRewardDenomOnReward() string { + if m != nil { + return m.RewardDenomOnReward + } + return "" +} + +func (m *MsgCreateTradeRoute) GetRewardDenomOnTrade() string { + if m != nil { + return m.RewardDenomOnTrade + } + return "" +} + +func (m *MsgCreateTradeRoute) GetHostDenomOnTrade() string { + if m != nil { + return m.HostDenomOnTrade + } + return "" +} + +func (m *MsgCreateTradeRoute) GetHostDenomOnHost() string { + if m != nil { + return m.HostDenomOnHost + } + return "" +} + +func (m *MsgCreateTradeRoute) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *MsgCreateTradeRoute) GetMaxAllowedSwapLossRate() string { + if m != nil { + return m.MaxAllowedSwapLossRate + } + return "" +} + +type MsgCreateTradeRouteResponse struct { +} + +func (m *MsgCreateTradeRouteResponse) Reset() { *m = MsgCreateTradeRouteResponse{} } +func (m *MsgCreateTradeRouteResponse) String() string { return proto.CompactTextString(m) } +func (*MsgCreateTradeRouteResponse) ProtoMessage() {} +func (*MsgCreateTradeRouteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9b7e09c9ad51cd54, []int{33} +} +func (m *MsgCreateTradeRouteResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgCreateTradeRouteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgCreateTradeRouteResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgCreateTradeRouteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgCreateTradeRouteResponse.Merge(m, src) +} +func (m *MsgCreateTradeRouteResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgCreateTradeRouteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgCreateTradeRouteResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgCreateTradeRouteResponse proto.InternalMessageInfo + +// Deletes a trade route +type MsgDeleteTradeRoute struct { + // authority is the address that controls the module (defaults to x/gov unless + // overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // The reward denom of the route in it's native form (e.g. usdc) + RewardDenom string `protobuf:"bytes,2,opt,name=reward_denom,json=rewardDenom,proto3" json:"reward_denom,omitempty"` + // The host zone's denom in it's native form (e.g. dydx) + HostDenom string `protobuf:"bytes,3,opt,name=host_denom,json=hostDenom,proto3" json:"host_denom,omitempty"` +} + +func (m *MsgDeleteTradeRoute) Reset() { *m = MsgDeleteTradeRoute{} } +func (m *MsgDeleteTradeRoute) String() string { return proto.CompactTextString(m) } +func (*MsgDeleteTradeRoute) ProtoMessage() {} +func (*MsgDeleteTradeRoute) Descriptor() ([]byte, []int) { + return fileDescriptor_9b7e09c9ad51cd54, []int{34} +} +func (m *MsgDeleteTradeRoute) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDeleteTradeRoute) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDeleteTradeRoute.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgDeleteTradeRoute) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDeleteTradeRoute.Merge(m, src) +} +func (m *MsgDeleteTradeRoute) XXX_Size() int { + return m.Size() +} +func (m *MsgDeleteTradeRoute) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDeleteTradeRoute.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDeleteTradeRoute proto.InternalMessageInfo + +func (m *MsgDeleteTradeRoute) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgDeleteTradeRoute) GetRewardDenom() string { + if m != nil { + return m.RewardDenom + } + return "" +} + +func (m *MsgDeleteTradeRoute) GetHostDenom() string { + if m != nil { + return m.HostDenom + } + return "" +} + +type MsgDeleteTradeRouteResponse struct { +} + +func (m *MsgDeleteTradeRouteResponse) Reset() { *m = MsgDeleteTradeRouteResponse{} } +func (m *MsgDeleteTradeRouteResponse) String() string { return proto.CompactTextString(m) } +func (*MsgDeleteTradeRouteResponse) ProtoMessage() {} +func (*MsgDeleteTradeRouteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9b7e09c9ad51cd54, []int{35} +} +func (m *MsgDeleteTradeRouteResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgDeleteTradeRouteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgDeleteTradeRouteResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgDeleteTradeRouteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgDeleteTradeRouteResponse.Merge(m, src) +} +func (m *MsgDeleteTradeRouteResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgDeleteTradeRouteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgDeleteTradeRouteResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgDeleteTradeRouteResponse proto.InternalMessageInfo + +// Updates the config of a trade route +type MsgUpdateTradeRoute struct { + // authority is the address that controls the module (defaults to x/gov unless + // overwritten). + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // The reward denom of the route in it's native form (e.g. usdc) + RewardDenom string `protobuf:"bytes,2,opt,name=reward_denom,json=rewardDenom,proto3" json:"reward_denom,omitempty"` + // The host zone's denom in it's native form (e.g. dydx) + HostDenom string `protobuf:"bytes,3,opt,name=host_denom,json=hostDenom,proto3" json:"host_denom,omitempty"` + // The osmosis pool ID + PoolId uint64 `protobuf:"varint,4,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + // Threshold defining the percentage of tokens that could be lost in the trade + // This captures both the loss from slippage and from a stale price on stride + // "0.05" means the output from the trade can be no less than a 5% deviation + // from the current value + MaxAllowedSwapLossRate string `protobuf:"bytes,5,opt,name=max_allowed_swap_loss_rate,json=maxAllowedSwapLossRate,proto3" json:"max_allowed_swap_loss_rate,omitempty"` + // minimum amount of reward tokens to initate a swap + // if not provided, defaults to 0 + MinSwapAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=min_swap_amount,json=minSwapAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"min_swap_amount"` + // maximum amount of reward tokens in a single swap + // if not provided, defaults to 10e24 + MaxSwapAmount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=max_swap_amount,json=maxSwapAmount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"max_swap_amount"` +} + +func (m *MsgUpdateTradeRoute) Reset() { *m = MsgUpdateTradeRoute{} } +func (m *MsgUpdateTradeRoute) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateTradeRoute) ProtoMessage() {} +func (*MsgUpdateTradeRoute) Descriptor() ([]byte, []int) { + return fileDescriptor_9b7e09c9ad51cd54, []int{36} +} +func (m *MsgUpdateTradeRoute) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateTradeRoute) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateTradeRoute.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateTradeRoute) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateTradeRoute.Merge(m, src) +} +func (m *MsgUpdateTradeRoute) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateTradeRoute) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateTradeRoute.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateTradeRoute proto.InternalMessageInfo + +func (m *MsgUpdateTradeRoute) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateTradeRoute) GetRewardDenom() string { + if m != nil { + return m.RewardDenom + } + return "" +} + +func (m *MsgUpdateTradeRoute) GetHostDenom() string { + if m != nil { + return m.HostDenom + } + return "" +} + +func (m *MsgUpdateTradeRoute) GetPoolId() uint64 { + if m != nil { + return m.PoolId + } + return 0 +} + +func (m *MsgUpdateTradeRoute) GetMaxAllowedSwapLossRate() string { + if m != nil { + return m.MaxAllowedSwapLossRate + } + return "" +} + +type MsgUpdateTradeRouteResponse struct { +} + +func (m *MsgUpdateTradeRouteResponse) Reset() { *m = MsgUpdateTradeRouteResponse{} } +func (m *MsgUpdateTradeRouteResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateTradeRouteResponse) ProtoMessage() {} +func (*MsgUpdateTradeRouteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9b7e09c9ad51cd54, []int{37} +} +func (m *MsgUpdateTradeRouteResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateTradeRouteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateTradeRouteResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgUpdateTradeRouteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateTradeRouteResponse.Merge(m, src) +} +func (m *MsgUpdateTradeRouteResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateTradeRouteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateTradeRouteResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateTradeRouteResponse proto.InternalMessageInfo + func init() { proto.RegisterType((*MsgUpdateInnerRedemptionRateBounds)(nil), "stride.stakeibc.MsgUpdateInnerRedemptionRateBounds") proto.RegisterType((*MsgUpdateInnerRedemptionRateBoundsResponse)(nil), "stride.stakeibc.MsgUpdateInnerRedemptionRateBoundsResponse") @@ -1585,111 +2030,147 @@ func init() { proto.RegisterType((*MsgCalibrateDelegationResponse)(nil), "stride.stakeibc.MsgCalibrateDelegationResponse") proto.RegisterType((*MsgResumeHostZone)(nil), "stride.stakeibc.MsgResumeHostZone") proto.RegisterType((*MsgResumeHostZoneResponse)(nil), "stride.stakeibc.MsgResumeHostZoneResponse") + proto.RegisterType((*MsgCreateTradeRoute)(nil), "stride.stakeibc.MsgCreateTradeRoute") + proto.RegisterType((*MsgCreateTradeRouteResponse)(nil), "stride.stakeibc.MsgCreateTradeRouteResponse") + proto.RegisterType((*MsgDeleteTradeRoute)(nil), "stride.stakeibc.MsgDeleteTradeRoute") + proto.RegisterType((*MsgDeleteTradeRouteResponse)(nil), "stride.stakeibc.MsgDeleteTradeRouteResponse") + proto.RegisterType((*MsgUpdateTradeRoute)(nil), "stride.stakeibc.MsgUpdateTradeRoute") + proto.RegisterType((*MsgUpdateTradeRouteResponse)(nil), "stride.stakeibc.MsgUpdateTradeRouteResponse") } func init() { proto.RegisterFile("stride/stakeibc/tx.proto", fileDescriptor_9b7e09c9ad51cd54) } var fileDescriptor_9b7e09c9ad51cd54 = []byte{ - // 1581 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4f, 0x6f, 0xdc, 0xc6, - 0x15, 0x17, 0x2d, 0x59, 0x5e, 0x3f, 0xfd, 0xa7, 0x64, 0x99, 0xa2, 0xea, 0x5d, 0x99, 0xea, 0x1f, - 0xd5, 0xb5, 0x76, 0x2b, 0xc9, 0x68, 0x51, 0xb7, 0x3d, 0x68, 0x25, 0x17, 0x5e, 0xc0, 0x32, 0x0a, - 0xca, 0xae, 0x01, 0x03, 0x05, 0x3b, 0x4b, 0x8e, 0xb8, 0x84, 0xc9, 0xe1, 0x9a, 0xc3, 0x95, 0xd7, - 0x3d, 0x14, 0xbe, 0x14, 0xe8, 0xa5, 0x40, 0x82, 0x00, 0x39, 0x06, 0x3e, 0xe4, 0x10, 0x24, 0xb7, - 0xc0, 0x1f, 0xc2, 0x40, 0x2e, 0x86, 0x4f, 0x41, 0x0e, 0x9b, 0xc0, 0xbe, 0xe4, 0xac, 0x4f, 0x10, - 0xcc, 0x90, 0x3b, 0x4b, 0xae, 0x66, 0x25, 0x59, 0x56, 0x7c, 0x92, 0x66, 0xde, 0x6f, 0xde, 0xfb, - 0xbd, 0x37, 0x6f, 0xde, 0x7b, 0x4b, 0xd0, 0x68, 0x1c, 0x79, 0x0e, 0xae, 0xd0, 0x18, 0x3d, 0xc2, - 0x5e, 0xdd, 0xae, 0xc4, 0xed, 0x72, 0x33, 0x0a, 0xe3, 0x50, 0x9d, 0x4a, 0x24, 0xe5, 0xae, 0x44, - 0xbf, 0xda, 0x0f, 0xf5, 0x6c, 0x64, 0x21, 0xdb, 0x0e, 0x5b, 0x24, 0x4e, 0xce, 0xe8, 0xa5, 0x7e, - 0xc8, 0x3e, 0xf2, 0x3d, 0x07, 0xc5, 0x61, 0x94, 0x02, 0xe6, 0xdc, 0xd0, 0x0d, 0xf9, 0xbf, 0x15, - 0xf6, 0x5f, 0xba, 0xbb, 0x60, 0x87, 0x34, 0x08, 0xa9, 0x95, 0x08, 0x92, 0x45, 0x2a, 0x2a, 0x26, - 0xab, 0x4a, 0x1d, 0x51, 0x5c, 0xd9, 0x5f, 0xab, 0xe3, 0x18, 0xad, 0x55, 0xec, 0xd0, 0x23, 0x89, - 0xdc, 0xf8, 0xe6, 0x1c, 0x18, 0x3b, 0xd4, 0xbd, 0xdf, 0x74, 0x50, 0x8c, 0x6b, 0x84, 0xe0, 0xc8, - 0xc4, 0x0e, 0x0e, 0x9a, 0xb1, 0x17, 0x12, 0x13, 0xc5, 0xb8, 0x1a, 0xb6, 0x88, 0x43, 0x55, 0x0d, - 0x2e, 0xd8, 0x11, 0x66, 0x44, 0x34, 0x65, 0x49, 0x59, 0xb9, 0x68, 0x76, 0x97, 0xea, 0x02, 0x14, - 0xec, 0x06, 0xf2, 0x88, 0xe5, 0x39, 0xda, 0xb9, 0x54, 0xc4, 0xd6, 0x35, 0x47, 0x7d, 0x02, 0x0b, - 0x01, 0x13, 0x30, 0xad, 0x56, 0x24, 0xd4, 0x5a, 0x11, 0x8a, 0xb1, 0x36, 0xcc, 0xb0, 0xd5, 0xbf, - 0xbc, 0xec, 0x94, 0x86, 0xbe, 0xeb, 0x94, 0x7e, 0xed, 0x7a, 0x71, 0xa3, 0x55, 0x2f, 0xdb, 0x61, - 0x90, 0xf2, 0x4f, 0xff, 0xac, 0x52, 0xe7, 0x51, 0x25, 0x7e, 0xda, 0xc4, 0xb4, 0xbc, 0x8d, 0xed, - 0xd7, 0x2f, 0x56, 0x21, 0x75, 0x6f, 0x1b, 0xdb, 0xe6, 0x7c, 0xe0, 0x11, 0x09, 0x67, 0x6e, 0x18, - 0xb5, 0x07, 0x18, 0x1e, 0x39, 0x13, 0xc3, 0xa8, 0x2d, 0x31, 0x6c, 0x5c, 0x87, 0x6b, 0xc7, 0x07, - 0xd3, 0xc4, 0xb4, 0x19, 0x12, 0x8a, 0x8d, 0x8f, 0x15, 0x98, 0xdc, 0xa1, 0xee, 0x1d, 0xef, 0x71, - 0xcb, 0x73, 0x76, 0xd9, 0x95, 0x1f, 0x11, 0xe7, 0xbf, 0xc1, 0x28, 0x0a, 0x58, 0xaa, 0x24, 0x51, - 0xae, 0x96, 0xdf, 0xc1, 0x81, 0x1a, 0x89, 0xcd, 0xf4, 0xb4, 0x7a, 0x05, 0xa0, 0x11, 0xd2, 0xd8, - 0x72, 0x30, 0x09, 0x83, 0xe4, 0x16, 0xcc, 0x8b, 0x6c, 0x67, 0x9b, 0x6d, 0x18, 0xcf, 0x14, 0x98, - 0xcf, 0x73, 0xea, 0xd2, 0x55, 0xf7, 0xa0, 0x40, 0x63, 0x2b, 0x0e, 0x1f, 0x61, 0xc2, 0xc9, 0x8d, - 0xad, 0x2f, 0x94, 0xd3, 0x98, 0xb0, 0xec, 0x2a, 0xa7, 0xd9, 0x55, 0xde, 0x0a, 0x3d, 0x52, 0xfd, - 0x3d, 0xa3, 0xf7, 0xe5, 0xf7, 0xa5, 0x95, 0x13, 0xd0, 0x63, 0x07, 0xa8, 0x79, 0x81, 0xc6, 0xf7, - 0x98, 0x6e, 0xe3, 0x73, 0x05, 0x66, 0x18, 0x85, 0xdd, 0x9d, 0x0f, 0x1b, 0x99, 0x55, 0x98, 0xf5, - 0x69, 0x90, 0x38, 0x68, 0x79, 0x75, 0x3b, 0x17, 0xa2, 0x69, 0x9f, 0x06, 0x9c, 0x5e, 0xad, 0x6e, - 0x27, 0x91, 0xba, 0x0b, 0x0b, 0x87, 0x58, 0x8a, 0x58, 0xad, 0xc1, 0x5c, 0x1c, 0x21, 0x42, 0x91, - 0xcd, 0x13, 0xcf, 0x0e, 0x83, 0xa6, 0x8f, 0x63, 0xcc, 0xa9, 0x17, 0xcc, 0xd9, 0x8c, 0x6c, 0x2b, - 0x15, 0x19, 0x5f, 0x28, 0x30, 0xb5, 0x43, 0xdd, 0x2d, 0x1f, 0xa3, 0xa8, 0x8a, 0x7c, 0x44, 0x6c, - 0x7c, 0xba, 0x67, 0xd7, 0x8b, 0xc7, 0xf0, 0x7b, 0xc5, 0x83, 0x19, 0x6f, 0x20, 0x42, 0xb0, 0x9f, - 0xbc, 0x19, 0xb3, 0xbb, 0x34, 0x16, 0xe0, 0x72, 0x1f, 0x53, 0x91, 0xd3, 0x5f, 0x25, 0x39, 0xcd, - 0xf2, 0x1e, 0x07, 0x1f, 0xea, 0xe6, 0x16, 0x81, 0x67, 0xb0, 0xf5, 0xef, 0x90, 0xa4, 0x85, 0xc5, - 0x2c, 0xb0, 0x8d, 0x87, 0x21, 0xc1, 0xaa, 0x0e, 0x85, 0x08, 0xdb, 0xd8, 0xdb, 0xc7, 0x51, 0xea, - 0x87, 0x58, 0x1b, 0x1a, 0x4f, 0xf6, 0x0c, 0x59, 0xe1, 0xc7, 0xd7, 0xe7, 0x61, 0x96, 0x8b, 0x5c, - 0x8f, 0xc6, 0x38, 0xba, 0xdd, 0xd5, 0xf6, 0x57, 0x98, 0xb0, 0x43, 0x42, 0x70, 0x72, 0xaf, 0xdd, - 0xe0, 0x57, 0xb5, 0x83, 0x4e, 0x69, 0xee, 0x29, 0x0a, 0xfc, 0x9b, 0x46, 0x4e, 0x6c, 0x98, 0xe3, - 0xbd, 0x75, 0xcd, 0x51, 0x0d, 0x18, 0xaf, 0x63, 0xbb, 0xb1, 0xb1, 0xde, 0x8c, 0xf0, 0x9e, 0xd7, - 0xd6, 0xc6, 0x39, 0xa1, 0xdc, 0x9e, 0x7a, 0x23, 0xf7, 0x42, 0x93, 0x72, 0x75, 0xe9, 0xa0, 0x53, - 0x9a, 0x49, 0xf4, 0xf7, 0x64, 0x46, 0xe6, 0xe1, 0xaa, 0x6b, 0x70, 0xb1, 0x97, 0xb3, 0xe7, 0xf9, - 0xa1, 0xb9, 0x83, 0x4e, 0x69, 0x3a, 0x39, 0x24, 0x44, 0x86, 0x59, 0xf0, 0xd2, 0x0c, 0xce, 0x5e, - 0xcc, 0x68, 0xfe, 0x62, 0xee, 0x42, 0x92, 0xa2, 0x7b, 0x38, 0xb2, 0xd2, 0x4b, 0x67, 0xbe, 0x02, - 0x57, 0x5b, 0x3c, 0xe8, 0x94, 0xf4, 0x44, 0xad, 0x04, 0x64, 0x98, 0x33, 0xdd, 0xdd, 0xad, 0x64, - 0x93, 0xa7, 0xe4, 0x74, 0x8b, 0xd4, 0x43, 0xe2, 0x78, 0xc4, 0xb5, 0x9a, 0x38, 0xf2, 0x42, 0x47, - 0x1b, 0x5b, 0x52, 0x56, 0x46, 0xaa, 0x8b, 0x07, 0x9d, 0xd2, 0xe5, 0x44, 0x59, 0x3f, 0xc2, 0x30, - 0xa7, 0xc4, 0xd6, 0xdf, 0xf9, 0x8e, 0xea, 0xc3, 0x2c, 0xeb, 0x28, 0xfd, 0x25, 0x7d, 0xe2, 0x0c, - 0x4a, 0xfa, 0x4c, 0xe0, 0x91, 0xbe, 0x36, 0xc2, 0xac, 0xa1, 0xf6, 0x21, 0x6b, 0x93, 0x67, 0x62, - 0x0d, 0xb5, 0xfb, 0xac, 0xfd, 0x11, 0x34, 0x56, 0x7e, 0x7c, 0x5e, 0x4d, 0x2c, 0x3e, 0x01, 0x58, - 0x98, 0xa0, 0xba, 0x8f, 0x1d, 0x6d, 0x8a, 0x97, 0x8d, 0x4b, 0x3e, 0x0d, 0x32, 0xc5, 0xe6, 0x56, - 0x22, 0xbc, 0x59, 0xf8, 0xdf, 0xf3, 0xd2, 0xd0, 0x8f, 0xcf, 0x4b, 0x43, 0xc6, 0x15, 0x58, 0x94, - 0xe4, 0xac, 0xc8, 0xe9, 0xff, 0x2a, 0xbc, 0x64, 0x6d, 0xf9, 0xc8, 0x0b, 0xee, 0x13, 0x07, 0xfb, - 0xd8, 0x45, 0x31, 0x76, 0x78, 0x59, 0x3b, 0xaa, 0xc5, 0x2f, 0xc1, 0xb8, 0x78, 0x5e, 0xbd, 0x7a, - 0x03, 0xdd, 0x17, 0x56, 0x73, 0xd4, 0x39, 0x38, 0x8f, 0x9b, 0xa1, 0xdd, 0xe0, 0x8f, 0x6f, 0xc4, - 0x4c, 0x16, 0xea, 0x3c, 0x8c, 0x52, 0x4c, 0x1c, 0xf1, 0xee, 0xd2, 0x95, 0xb1, 0x0c, 0x57, 0x07, - 0xd2, 0x10, 0x64, 0xe3, 0xf4, 0x69, 0xd6, 0x93, 0x02, 0xf3, 0x8f, 0xee, 0x20, 0x74, 0x14, 0xd1, - 0x5c, 0x1d, 0x38, 0xd7, 0x57, 0x07, 0x96, 0x61, 0x82, 0xb4, 0x02, 0x2b, 0xea, 0x6a, 0x4c, 0xb9, - 0x8e, 0x93, 0x56, 0x20, 0xac, 0x18, 0x4b, 0x50, 0x94, 0x5b, 0xcd, 0x06, 0x71, 0x7a, 0x87, 0xba, - 0x9b, 0x8e, 0xf3, 0xfe, 0x94, 0x6e, 0x02, 0x88, 0x01, 0x8f, 0x6a, 0xc3, 0x4b, 0xc3, 0x2b, 0x63, - 0xeb, 0x7a, 0xb9, 0x6f, 0x6e, 0x2c, 0x0b, 0x3b, 0x66, 0x06, 0x6d, 0xe8, 0xa0, 0xf5, 0xd3, 0x10, - 0x1c, 0x3f, 0x53, 0xb8, 0x90, 0xbd, 0x3f, 0xb7, 0xe7, 0xc3, 0x03, 0xec, 0xb9, 0x8d, 0xf8, 0xb4, - 0x5c, 0x37, 0xa0, 0xb0, 0x8f, 0x7c, 0x0b, 0x39, 0x4e, 0x94, 0xf6, 0x15, 0xed, 0xf5, 0x8b, 0xd5, - 0xb9, 0x34, 0xa7, 0x37, 0x1d, 0x27, 0xc2, 0x94, 0xee, 0xc6, 0x91, 0x47, 0x5c, 0xf3, 0xc2, 0x3e, - 0xf2, 0xd9, 0x0e, 0xcb, 0x80, 0x27, 0xdc, 0x2a, 0xcf, 0x80, 0x11, 0x33, 0x5d, 0x19, 0x06, 0x2c, - 0x0d, 0xe2, 0x27, 0x9c, 0x78, 0xa6, 0x80, 0xba, 0x43, 0xdd, 0x6d, 0xcc, 0xba, 0xa3, 0x00, 0x7d, - 0x48, 0xfa, 0xc6, 0x2f, 0x40, 0x3f, 0xcc, 0x40, 0x10, 0xfc, 0x54, 0x49, 0x9f, 0x1b, 0x8d, 0xc3, - 0x08, 0xd7, 0x48, 0x8c, 0x23, 0xde, 0x82, 0x37, 0x93, 0x91, 0xfe, 0x74, 0xcd, 0xbb, 0x0a, 0xe3, - 0xe9, 0x4f, 0x02, 0x8b, 0xd5, 0x0e, 0xce, 0x75, 0x72, 0xbd, 0x74, 0x28, 0x29, 0x6a, 0x5b, 0x9b, - 0xa9, 0x9d, 0x7b, 0x4f, 0x9b, 0xd8, 0x1c, 0x43, 0xbd, 0x85, 0xf1, 0x2b, 0x58, 0x3e, 0x82, 0x97, - 0xe0, 0xff, 0x98, 0x5f, 0x42, 0x32, 0xac, 0x0a, 0xef, 0x76, 0x1b, 0x28, 0xc2, 0xf4, 0x56, 0xdb, - 0x6e, 0xf0, 0xa2, 0x74, 0x2a, 0x1f, 0x34, 0x60, 0x11, 0x0c, 0x9b, 0x38, 0x0d, 0xb5, 0xd9, 0x5d, - 0x1a, 0xd7, 0x60, 0xe5, 0x38, 0x93, 0x82, 0x5e, 0x8b, 0x4f, 0x81, 0xbd, 0x02, 0xc1, 0xca, 0xd9, - 0xcf, 0x3f, 0x4b, 0x18, 0x8b, 0xbc, 0x46, 0xe6, 0xcd, 0x0a, 0x4e, 0x2e, 0x2f, 0x4a, 0x5b, 0xc8, - 0xf7, 0xea, 0xac, 0x15, 0x6c, 0x27, 0x18, 0x2f, 0x24, 0x67, 0x1d, 0xa8, 0xa4, 0x0e, 0x49, 0x0c, - 0x09, 0x2a, 0xb7, 0x79, 0x78, 0x4c, 0x4c, 0x5b, 0x01, 0x16, 0xd3, 0xc9, 0x69, 0x58, 0xa4, 0x1e, - 0xe7, 0x35, 0x75, 0xcd, 0xac, 0x77, 0x26, 0x60, 0x78, 0x87, 0xba, 0xea, 0x03, 0x18, 0xcb, 0x4e, - 0xe3, 0x87, 0x13, 0x32, 0xff, 0xa3, 0x41, 0xff, 0xcd, 0x31, 0x00, 0x31, 0x29, 0xff, 0x0b, 0x26, - 0xfb, 0x26, 0x7d, 0x43, 0x7a, 0x34, 0x87, 0xd1, 0xaf, 0x1d, 0x8f, 0x11, 0x16, 0x1e, 0xc0, 0x58, - 0x76, 0x1c, 0x95, 0x52, 0xcf, 0x00, 0xe4, 0xd4, 0x25, 0x33, 0xa2, 0xba, 0x07, 0xd3, 0x87, 0xe6, - 0xc3, 0x5f, 0xca, 0x0f, 0xe7, 0x51, 0xfa, 0xf5, 0x93, 0xa0, 0x84, 0x9d, 0x36, 0xcc, 0x0f, 0xe8, - 0xd9, 0xd2, 0x30, 0xc8, 0xb1, 0xfa, 0xfa, 0xc9, 0xb1, 0xc2, 0x72, 0x08, 0xb3, 0xb2, 0x0e, 0x3c, - 0x20, 0x42, 0x87, 0x80, 0x7a, 0xe5, 0x84, 0x40, 0x61, 0xf0, 0x9f, 0x30, 0x91, 0xef, 0xac, 0x57, - 0x65, 0x1a, 0x72, 0x10, 0xfd, 0xb7, 0xc7, 0x42, 0x84, 0xfa, 0x16, 0x5c, 0x92, 0x37, 0x45, 0xa9, - 0x0e, 0x29, 0x54, 0x5f, 0x3b, 0x31, 0x54, 0x98, 0xb5, 0x61, 0xaa, 0xbf, 0x8d, 0x2d, 0xcb, 0xb4, - 0xf4, 0x81, 0xf4, 0xdf, 0x9d, 0x00, 0x24, 0x8c, 0xfc, 0x07, 0xb4, 0x81, 0xad, 0x68, 0x40, 0xbe, - 0xc9, 0xd1, 0xfa, 0x8d, 0x77, 0x41, 0x0b, 0xfb, 0xff, 0x57, 0xe0, 0xca, 0xd1, 0xcd, 0x44, 0x1a, - 0xb9, 0x23, 0x8f, 0xe8, 0x7f, 0x7a, 0xe7, 0x23, 0xd9, 0xdc, 0x95, 0x15, 0x6a, 0x69, 0xee, 0x4a, - 0x80, 0xf2, 0xdc, 0x3d, 0xa2, 0x22, 0xab, 0x0f, 0x61, 0x3c, 0xf7, 0xe3, 0x7d, 0x49, 0xfe, 0xe0, - 0x7a, 0x08, 0x7d, 0xe5, 0x38, 0x44, 0xb6, 0x4a, 0xf6, 0x75, 0x42, 0x69, 0x95, 0xcc, 0x63, 0xe4, - 0x55, 0x52, 0xde, 0xda, 0xd4, 0x4f, 0x14, 0x28, 0x1d, 0xf7, 0x15, 0x70, 0x63, 0xf0, 0x6d, 0x0c, - 0x3c, 0xa4, 0xff, 0xf9, 0x14, 0x87, 0xb2, 0x7e, 0xf7, 0xb5, 0x38, 0x63, 0x40, 0x72, 0x66, 0x30, - 0x72, 0xbf, 0xe5, 0x0d, 0xae, 0x7a, 0xe7, 0xe5, 0x9b, 0xa2, 0xf2, 0xea, 0x4d, 0x51, 0xf9, 0xe1, - 0x4d, 0x51, 0xf9, 0xe8, 0x6d, 0x71, 0xe8, 0xd5, 0xdb, 0xe2, 0xd0, 0xb7, 0x6f, 0x8b, 0x43, 0x0f, - 0xd7, 0x33, 0x93, 0xc3, 0x2e, 0xd7, 0xb7, 0x7a, 0x07, 0xd5, 0x69, 0x25, 0xfd, 0x46, 0xbb, 0xbf, - 0xf6, 0x87, 0x4a, 0x3b, 0xf3, 0xdd, 0x97, 0x4d, 0x12, 0xf5, 0x51, 0xfe, 0x55, 0x75, 0xe3, 0xa7, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xe3, 0xea, 0x73, 0x2e, 0x17, 0x16, 0x00, 0x00, + // 2057 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x59, 0x4f, 0x6f, 0x24, 0x47, + 0x15, 0xf7, 0xac, 0xbd, 0xf6, 0xf8, 0xd9, 0x5e, 0xdb, 0x6d, 0xaf, 0x77, 0xdc, 0x1b, 0xcf, 0x78, + 0xdb, 0x1b, 0x30, 0x4e, 0x3c, 0x83, 0xed, 0x28, 0x80, 0x01, 0x09, 0xff, 0x09, 0x64, 0xc4, 0x3a, + 0x41, 0x6d, 0x27, 0x2b, 0xad, 0x84, 0x9a, 0x9a, 0xee, 0xda, 0x99, 0xd6, 0x76, 0x77, 0x4d, 0xba, + 0x7a, 0xec, 0x59, 0x0e, 0x28, 0x42, 0x42, 0x42, 0x08, 0x24, 0x10, 0x12, 0x27, 0x84, 0x72, 0xe0, + 0x80, 0xe0, 0x12, 0xa1, 0x7c, 0x88, 0x20, 0x24, 0x14, 0xe5, 0x84, 0x38, 0x18, 0xb4, 0x7b, 0x08, + 0x67, 0x7f, 0x02, 0x54, 0x55, 0x3d, 0x35, 0xdd, 0x3d, 0x35, 0x1e, 0xdb, 0x71, 0x56, 0x5c, 0x6c, + 0x57, 0xd5, 0xaf, 0xde, 0xfb, 0xbd, 0x57, 0xef, 0xbd, 0x7a, 0xd5, 0x86, 0x02, 0x8d, 0x42, 0xd7, + 0xc1, 0x15, 0x1a, 0xa1, 0x27, 0xd8, 0xad, 0xd9, 0x95, 0xa8, 0x5d, 0x6e, 0x86, 0x24, 0x22, 0xda, + 0xb4, 0x58, 0x29, 0x77, 0x56, 0xf4, 0x52, 0x16, 0x7a, 0x8c, 0x3c, 0xd7, 0x41, 0x11, 0x09, 0xc5, + 0x0e, 0x7d, 0xbe, 0x4e, 0xea, 0x84, 0xff, 0x59, 0x61, 0x7f, 0xc5, 0xb3, 0x8b, 0x36, 0xa1, 0x3e, + 0xa1, 0x96, 0x58, 0x10, 0x83, 0x78, 0xa9, 0x28, 0x46, 0x95, 0x1a, 0xa2, 0xb8, 0x72, 0xbc, 0x51, + 0xc3, 0x11, 0xda, 0xa8, 0xd8, 0xc4, 0x0d, 0xe2, 0xf5, 0x3b, 0xf1, 0xba, 0x4f, 0xeb, 0x95, 0xe3, + 0x0d, 0xf6, 0x2b, 0x5e, 0x98, 0x45, 0xbe, 0x1b, 0x90, 0x0a, 0xff, 0x29, 0xa6, 0x8c, 0xbf, 0xdf, + 0x00, 0xe3, 0x80, 0xd6, 0xdf, 0x69, 0x3a, 0x28, 0xc2, 0xd5, 0x20, 0xc0, 0xa1, 0x89, 0x1d, 0xec, + 0x37, 0x23, 0x97, 0x04, 0x26, 0x8a, 0xf0, 0x2e, 0x69, 0x05, 0x0e, 0xd5, 0x0a, 0x30, 0x66, 0x87, + 0x98, 0x91, 0x2e, 0xe4, 0x96, 0x73, 0xab, 0xe3, 0x66, 0x67, 0xa8, 0x2d, 0x42, 0xde, 0x6e, 0x20, + 0x37, 0xb0, 0x5c, 0xa7, 0x70, 0x23, 0x5e, 0x62, 0xe3, 0xaa, 0xa3, 0x9d, 0xc0, 0xa2, 0xcf, 0x16, + 0x98, 0x54, 0x2b, 0x94, 0x62, 0xad, 0x10, 0x45, 0xb8, 0x30, 0xcc, 0xb0, 0xbb, 0xdf, 0xfa, 0xf8, + 0xb4, 0x34, 0xf4, 0xaf, 0xd3, 0xd2, 0x97, 0xea, 0x6e, 0xd4, 0x68, 0xd5, 0xca, 0x36, 0xf1, 0x63, + 0x5b, 0xe3, 0x5f, 0xeb, 0xd4, 0x79, 0x52, 0x89, 0x9e, 0x36, 0x31, 0x2d, 0xef, 0x63, 0xfb, 0xd3, + 0x8f, 0xd6, 0x21, 0x76, 0xc5, 0x3e, 0xb6, 0xcd, 0x05, 0xdf, 0x0d, 0x14, 0x9c, 0xb9, 0x62, 0xd4, + 0xee, 0xa3, 0x78, 0xe4, 0x5a, 0x14, 0xa3, 0xb6, 0x42, 0xb1, 0xf1, 0x2a, 0xac, 0x0d, 0x76, 0xa6, + 0x89, 0x69, 0x93, 0x04, 0x14, 0x1b, 0xbf, 0xc9, 0xc1, 0xad, 0x03, 0x5a, 0x7f, 0xe0, 0xbe, 0xd7, + 0x72, 0x9d, 0x43, 0x16, 0x1e, 0xe7, 0xf8, 0xf9, 0xbb, 0x30, 0x8a, 0x7c, 0xd2, 0x0a, 0x22, 0xe1, + 0xe5, 0xdd, 0xf2, 0x25, 0x0c, 0xa8, 0x06, 0x91, 0x19, 0xef, 0xd6, 0x96, 0x00, 0x1a, 0x84, 0x46, + 0x96, 0x83, 0x03, 0xe2, 0x8b, 0x53, 0x30, 0xc7, 0xd9, 0xcc, 0x3e, 0x9b, 0x30, 0xde, 0xcf, 0xc1, + 0x42, 0x9a, 0x53, 0x87, 0xae, 0xf6, 0x18, 0xf2, 0x34, 0xb2, 0x22, 0xf2, 0x04, 0x07, 0x9c, 0xdc, + 0xc4, 0xe6, 0x62, 0x39, 0xf6, 0x09, 0x8b, 0xc4, 0x72, 0x1c, 0x89, 0xe5, 0x3d, 0xe2, 0x06, 0xbb, + 0x5f, 0x65, 0xf4, 0xfe, 0xfc, 0xef, 0xd2, 0xea, 0x05, 0xe8, 0xb1, 0x0d, 0xd4, 0x1c, 0xa3, 0xd1, + 0x11, 0x93, 0x6d, 0xfc, 0x31, 0x07, 0xb3, 0x8c, 0xc2, 0xe1, 0xc1, 0x8b, 0xf5, 0xcc, 0x3a, 0xcc, + 0x79, 0xd4, 0x17, 0x06, 0x5a, 0x6e, 0xcd, 0x4e, 0xb9, 0x68, 0xc6, 0xa3, 0x3e, 0xa7, 0x57, 0xad, + 0xd9, 0xc2, 0x53, 0x6f, 0xc1, 0x62, 0x0f, 0x4b, 0xe9, 0xab, 0x0d, 0x98, 0x8f, 0x42, 0x14, 0x50, + 0x64, 0xf3, 0xc0, 0xb3, 0x89, 0xdf, 0xf4, 0x70, 0x84, 0x39, 0xf5, 0xbc, 0x39, 0x97, 0x58, 0xdb, + 0x8b, 0x97, 0x8c, 0x3f, 0xe5, 0x60, 0xfa, 0x80, 0xd6, 0xf7, 0x3c, 0x8c, 0xc2, 0x5d, 0xe4, 0xa1, + 0xc0, 0xc6, 0x57, 0x4b, 0xbb, 0xae, 0x3f, 0x86, 0x3f, 0x97, 0x3f, 0x98, 0xf2, 0x06, 0x0a, 0x02, + 0xec, 0x89, 0x9c, 0x31, 0x3b, 0x43, 0x63, 0x11, 0xee, 0x64, 0x98, 0xca, 0x98, 0xfe, 0x8b, 0x88, + 0x69, 0x16, 0xf7, 0xd8, 0x7f, 0x51, 0x27, 0x77, 0x17, 0x78, 0x04, 0x5b, 0x3f, 0x26, 0x41, 0x5c, + 0x58, 0xcc, 0x3c, 0x9b, 0x78, 0x44, 0x02, 0xac, 0xe9, 0x90, 0x0f, 0xb1, 0x8d, 0xdd, 0x63, 0x1c, + 0xc6, 0x76, 0xc8, 0xb1, 0x51, 0xe0, 0xc1, 0x9e, 0x20, 0x2b, 0xed, 0xf8, 0xeb, 0x4d, 0x98, 0xe3, + 0x4b, 0x75, 0x97, 0x46, 0x38, 0x7c, 0xb3, 0x23, 0xed, 0xdb, 0x30, 0x65, 0x93, 0x20, 0xc0, 0xe2, + 0x5c, 0x3b, 0xce, 0xdf, 0x2d, 0x9c, 0x9d, 0x96, 0xe6, 0x9f, 0x22, 0xdf, 0xdb, 0x36, 0x52, 0xcb, + 0x86, 0x39, 0xd9, 0x1d, 0x57, 0x1d, 0xcd, 0x80, 0xc9, 0x1a, 0xb6, 0x1b, 0x5b, 0x9b, 0xcd, 0x10, + 0x3f, 0x76, 0xdb, 0x85, 0x49, 0x4e, 0x28, 0x35, 0xa7, 0xbd, 0x96, 0xca, 0x50, 0x51, 0xae, 0x6e, + 0x9f, 0x9d, 0x96, 0x66, 0x85, 0xfc, 0xee, 0x9a, 0x91, 0x48, 0x5c, 0x6d, 0x03, 0xc6, 0xbb, 0x31, + 0x7b, 0x93, 0x6f, 0x9a, 0x3f, 0x3b, 0x2d, 0xcd, 0x88, 0x4d, 0x72, 0xc9, 0x30, 0xf3, 0x6e, 0x1c, + 0xc1, 0xc9, 0x83, 0x19, 0x4d, 0x1f, 0xcc, 0x5b, 0x20, 0x42, 0xf4, 0x31, 0x0e, 0xad, 0xf8, 0xd0, + 0x99, 0xad, 0xc0, 0xc5, 0x16, 0xcf, 0x4e, 0x4b, 0xba, 0x10, 0xab, 0x00, 0x19, 0xe6, 0x6c, 0x67, + 0x76, 0x4f, 0x4c, 0xf2, 0x90, 0x9c, 0x69, 0x05, 0x35, 0x12, 0x38, 0x6e, 0x50, 0xb7, 0x9a, 0x38, + 0x74, 0x89, 0x53, 0x98, 0x58, 0xce, 0xad, 0x8e, 0xec, 0xde, 0x3d, 0x3b, 0x2d, 0xdd, 0x11, 0xc2, + 0xb2, 0x08, 0xc3, 0x9c, 0x96, 0x53, 0x3f, 0xe0, 0x33, 0x9a, 0x07, 0x73, 0xec, 0x46, 0xc9, 0x96, + 0xf4, 0xa9, 0x6b, 0x28, 0xe9, 0xb3, 0xbe, 0x1b, 0x64, 0xae, 0x11, 0xa6, 0x0d, 0xb5, 0x7b, 0xb4, + 0xdd, 0xba, 0x16, 0x6d, 0xa8, 0x9d, 0xd1, 0xf6, 0x35, 0x28, 0xb0, 0xf2, 0xe3, 0xf1, 0x6a, 0x62, + 0xf1, 0x6e, 0xc1, 0xc2, 0x01, 0xaa, 0x79, 0xd8, 0x29, 0x4c, 0xf3, 0xb2, 0x71, 0xdb, 0xa3, 0x7e, + 0xa2, 0xd8, 0xbc, 0x21, 0x16, 0xb7, 0xf3, 0x3f, 0xff, 0xa0, 0x34, 0xf4, 0xdf, 0x0f, 0x4a, 0x43, + 0xc6, 0x12, 0xdc, 0x55, 0xc4, 0xac, 0x8c, 0xe9, 0x9f, 0xe5, 0x78, 0xc9, 0xda, 0xf3, 0x90, 0xeb, + 0xbf, 0x13, 0x38, 0xd8, 0xc3, 0x75, 0x14, 0x61, 0x87, 0x97, 0xb5, 0xf3, 0xae, 0xf8, 0x65, 0x98, + 0x94, 0xe9, 0xd5, 0xad, 0x37, 0xd0, 0xc9, 0xb0, 0xaa, 0xa3, 0xcd, 0xc3, 0x4d, 0xdc, 0x24, 0x76, + 0x83, 0x27, 0xdf, 0x88, 0x29, 0x06, 0xda, 0x02, 0x8c, 0x52, 0x1c, 0x38, 0x32, 0xef, 0xe2, 0x91, + 0xb1, 0x02, 0xf7, 0xfa, 0xd2, 0x90, 0x64, 0xa3, 0x38, 0x35, 0x6b, 0xa2, 0xc0, 0xbc, 0xdb, 0x69, + 0x9a, 0xce, 0x23, 0x9a, 0xaa, 0x03, 0x37, 0x32, 0x75, 0x60, 0x05, 0xa6, 0x82, 0x96, 0x6f, 0x85, + 0x1d, 0x89, 0x31, 0xd7, 0xc9, 0xa0, 0xe5, 0x4b, 0x2d, 0xc6, 0x32, 0x14, 0xd5, 0x5a, 0x93, 0x4e, + 0x9c, 0x39, 0xa0, 0xf5, 0x1d, 0xc7, 0xf9, 0xfc, 0x94, 0xb6, 0x01, 0x64, 0x33, 0x48, 0x0b, 0xc3, + 0xcb, 0xc3, 0xab, 0x13, 0x9b, 0x7a, 0x39, 0xd3, 0x40, 0x96, 0xa5, 0x1e, 0x33, 0x81, 0x36, 0x74, + 0x28, 0x64, 0x69, 0x48, 0x8e, 0x7f, 0xc8, 0xf1, 0x45, 0x96, 0x7f, 0xf5, 0xae, 0x0d, 0x0f, 0xb1, + 0x5b, 0x6f, 0x44, 0x57, 0xe5, 0xba, 0x05, 0xf9, 0x63, 0xe4, 0x59, 0xc8, 0x71, 0xc2, 0xf8, 0x5e, + 0x29, 0x7c, 0xfa, 0xd1, 0xfa, 0x7c, 0x1c, 0xd3, 0x3b, 0x8e, 0x13, 0x62, 0x4a, 0x0f, 0xa3, 0xd0, + 0x0d, 0xea, 0xe6, 0xd8, 0x31, 0xf2, 0xd8, 0x0c, 0x8b, 0x80, 0x13, 0xae, 0x95, 0x47, 0xc0, 0x88, + 0x19, 0x8f, 0x0c, 0x03, 0x96, 0xfb, 0xf1, 0x93, 0x46, 0xbc, 0x9f, 0x03, 0xed, 0x80, 0xd6, 0xf7, + 0x31, 0xbb, 0x1d, 0x25, 0xe8, 0x45, 0xd2, 0x37, 0x5e, 0x02, 0xbd, 0x97, 0x81, 0x24, 0xf8, 0xfb, + 0x5c, 0x9c, 0x6e, 0x34, 0x22, 0x21, 0xae, 0x06, 0x11, 0x0e, 0xf9, 0x15, 0xbc, 0x63, 0xdb, 0xf2, + 0xfe, 0xbc, 0xf4, 0xe5, 0xbd, 0x92, 0xbd, 0x5f, 0xc4, 0x75, 0x96, 0xbe, 0x45, 0x56, 0x60, 0x0a, + 0x09, 0x25, 0x16, 0x39, 0x09, 0x64, 0x7e, 0x4d, 0xc6, 0x93, 0x6f, 0xb3, 0x39, 0xe3, 0x65, 0x58, + 0x39, 0x87, 0x9d, 0xb4, 0xe2, 0x3d, 0x7e, 0x14, 0xa2, 0x65, 0x95, 0x36, 0x1e, 0x36, 0x50, 0x88, + 0xe9, 0x1b, 0x6d, 0xbb, 0xc1, 0x4b, 0xd3, 0x95, 0x2c, 0x29, 0x00, 0xf3, 0x23, 0x69, 0xe2, 0xd8, + 0xe1, 0x66, 0x67, 0x68, 0xac, 0xc1, 0xea, 0x20, 0x95, 0x92, 0x5e, 0x8b, 0xf7, 0x82, 0xdd, 0x32, + 0xc1, 0x8a, 0xda, 0x17, 0xdf, 0x51, 0x18, 0x77, 0x79, 0xa5, 0x4c, 0xab, 0x95, 0x9c, 0xea, 0xbc, + 0x34, 0xed, 0x21, 0xcf, 0xad, 0xb1, 0x0b, 0x61, 0x5f, 0x60, 0x5c, 0x12, 0x5c, 0xb7, 0xa3, 0x44, + 0x35, 0x52, 0x28, 0x92, 0x54, 0xde, 0xe4, 0xee, 0x31, 0x31, 0x6d, 0xf9, 0x58, 0xf6, 0x28, 0x57, + 0x61, 0x11, 0x5b, 0x9c, 0x96, 0x24, 0xd5, 0xfc, 0x32, 0xcf, 0xbb, 0xa1, 0x3d, 0x26, 0x06, 0x1f, + 0x85, 0xc8, 0xc1, 0x26, 0x69, 0x45, 0x58, 0x7b, 0x1d, 0xc6, 0x51, 0x2b, 0x6a, 0x90, 0xd0, 0x8d, + 0x9e, 0x0a, 0x5d, 0xe7, 0xa4, 0x55, 0x17, 0xaa, 0x19, 0x30, 0xc5, 0x53, 0x35, 0x43, 0x66, 0x82, + 0x4d, 0xee, 0xc5, 0x6e, 0xd9, 0x85, 0xa2, 0xa8, 0x84, 0x56, 0x44, 0xac, 0x10, 0x9f, 0xa0, 0xd0, + 0xb1, 0x54, 0xa9, 0xa1, 0x0b, 0xd4, 0x11, 0x31, 0x39, 0x66, 0x2f, 0x99, 0x28, 0xdf, 0x81, 0xa5, + 0xae, 0x8c, 0x88, 0xf1, 0xce, 0x88, 0x10, 0x89, 0xb3, 0xd8, 0x11, 0xc1, 0x4d, 0x4b, 0x49, 0xa8, + 0x82, 0x68, 0xb8, 0xba, 0x1c, 0x54, 0x8d, 0x11, 0xef, 0xb7, 0xcc, 0x25, 0x86, 0xec, 0xf0, 0x38, + 0xea, 0x69, 0x82, 0xbe, 0x0f, 0x2b, 0x1d, 0x11, 0x1d, 0x32, 0x2a, 0x59, 0xa2, 0x15, 0x2b, 0x0a, + 0x68, 0x4c, 0xa9, 0x57, 0xd8, 0xf7, 0xe0, 0x5e, 0x2c, 0x82, 0x58, 0x82, 0xa0, 0x42, 0xd4, 0x18, + 0x17, 0xf5, 0x12, 0x07, 0x1e, 0x11, 0x76, 0xaa, 0xbd, 0x82, 0x2a, 0x30, 0x1f, 0xb3, 0xe2, 0xfd, + 0xa1, 0x45, 0x02, 0x2e, 0xaf, 0x90, 0xe7, 0x7b, 0x67, 0xc5, 0x1a, 0xef, 0x17, 0xdf, 0x0e, 0x78, + 0xf2, 0x6d, 0xc1, 0x42, 0x76, 0x83, 0x18, 0x17, 0xc6, 0xf9, 0x96, 0xb9, 0xd4, 0x16, 0xe1, 0x0c, + 0x6d, 0x03, 0x6e, 0x67, 0x37, 0x71, 0x56, 0xa2, 0xa5, 0x34, 0xb5, 0xd4, 0x1e, 0x6e, 0x32, 0x7b, + 0x8e, 0x75, 0x5b, 0xdd, 0xee, 0x86, 0x09, 0xf1, 0x1c, 0x93, 0x8d, 0x6f, 0x07, 0xfe, 0x0a, 0x68, + 0x69, 0x38, 0xb7, 0x42, 0xf4, 0xd7, 0xd3, 0x09, 0x34, 0xb7, 0xe1, 0x0e, 0x8c, 0x35, 0x09, 0xe1, + 0x3e, 0x9a, 0x12, 0x17, 0x13, 0x1b, 0x56, 0x1d, 0x6d, 0x1b, 0x74, 0xd6, 0xf2, 0x21, 0xcf, 0x23, + 0x27, 0xd8, 0xb1, 0xe8, 0x09, 0x6a, 0x5a, 0x1e, 0xa1, 0x34, 0xd1, 0xf9, 0xf1, 0xc7, 0xff, 0x8e, + 0x00, 0x1c, 0x9e, 0xa0, 0xe6, 0x03, 0x42, 0x29, 0xaf, 0x92, 0xef, 0xc2, 0x34, 0x6b, 0x4e, 0xf9, + 0x9e, 0xb8, 0x08, 0x4d, 0x5f, 0xa9, 0x08, 0x4d, 0xf9, 0x6e, 0xc0, 0x24, 0xef, 0x88, 0xd7, 0x0d, + 0x93, 0x8b, 0xda, 0x29, 0xb9, 0x33, 0x57, 0x94, 0x8b, 0xda, 0x5d, 0xb9, 0xdb, 0x5f, 0xff, 0xe9, + 0x67, 0x1f, 0xae, 0x75, 0x93, 0xf2, 0x17, 0x9f, 0x7d, 0xb8, 0xf6, 0x72, 0xfc, 0xad, 0xaa, 0xdd, + 0xfd, 0x5a, 0xa5, 0x48, 0xfb, 0xb8, 0xcf, 0xcc, 0x4e, 0xcb, 0x6a, 0xf1, 0xb7, 0x1c, 0xaf, 0x16, + 0xe2, 0xde, 0xbc, 0x86, 0x6a, 0x71, 0x0f, 0x26, 0x93, 0xc1, 0xd3, 0x29, 0x16, 0x89, 0x98, 0x19, + 0xf0, 0x55, 0xe3, 0xe2, 0xa6, 0x66, 0x39, 0xc7, 0xa6, 0x66, 0xa7, 0xa5, 0xa9, 0xff, 0x18, 0xe6, + 0xa6, 0x8a, 0xbb, 0xec, 0xff, 0xc1, 0xd4, 0x64, 0x68, 0x8f, 0x5c, 0x22, 0xb4, 0x6f, 0x5e, 0x36, + 0xb4, 0x47, 0xbf, 0xa0, 0xd0, 0x1e, 0x7b, 0xa1, 0xa1, 0x9d, 0x3d, 0xb8, 0xf8, 0xbc, 0xb3, 0xd3, + 0x9d, 0xf3, 0xde, 0xfc, 0xdd, 0x0c, 0x0c, 0x1f, 0xd0, 0xba, 0xf6, 0x10, 0x26, 0x92, 0x1f, 0xa7, + 0x4a, 0x3d, 0x4d, 0x7b, 0xfa, 0x1b, 0x9a, 0xfe, 0xe5, 0x01, 0x00, 0xf9, 0xe1, 0xe8, 0x47, 0x70, + 0x2b, 0xf3, 0xe1, 0xcb, 0x50, 0x6e, 0x4d, 0x61, 0xf4, 0xb5, 0xc1, 0x18, 0xa9, 0xe1, 0x21, 0x4c, + 0x24, 0xbf, 0xce, 0x28, 0xa9, 0x27, 0x00, 0x6a, 0xea, 0x8a, 0x4f, 0x26, 0xda, 0x63, 0x98, 0xe9, + 0xf9, 0x5c, 0x72, 0x5f, 0xbd, 0x39, 0x8d, 0xd2, 0x5f, 0xbd, 0x08, 0x4a, 0xea, 0x69, 0xc3, 0x42, + 0x9f, 0x27, 0xac, 0xd2, 0x0d, 0x6a, 0xac, 0xbe, 0x79, 0x71, 0xac, 0xd4, 0x4c, 0x60, 0x4e, 0xf5, + 0x20, 0xed, 0xe3, 0xa1, 0x1e, 0xa0, 0x5e, 0xb9, 0x20, 0x50, 0x2a, 0xfc, 0x21, 0x4c, 0xa5, 0x1f, + 0x9a, 0xf7, 0x54, 0x12, 0x52, 0x10, 0xfd, 0x2b, 0x03, 0x21, 0x52, 0x7c, 0x0b, 0x6e, 0xab, 0xdf, + 0x88, 0x4a, 0x19, 0x4a, 0xa8, 0xbe, 0x71, 0x61, 0xa8, 0x54, 0x6b, 0xc3, 0x74, 0xf6, 0x55, 0xb7, + 0xa2, 0x92, 0x92, 0x01, 0xe9, 0xaf, 0x5c, 0x00, 0x24, 0x95, 0xfc, 0x04, 0x0a, 0x7d, 0x5f, 0x66, + 0x7d, 0xe2, 0x4d, 0x8d, 0xd6, 0x5f, 0xbb, 0x0c, 0x5a, 0xea, 0xff, 0x55, 0x0e, 0x96, 0xce, 0x7f, + 0x55, 0x29, 0x3d, 0x77, 0xee, 0x16, 0xfd, 0x1b, 0x97, 0xde, 0x92, 0x8c, 0x5d, 0xd5, 0x8b, 0x45, + 0x19, 0xbb, 0x0a, 0xa0, 0x3a, 0x76, 0xcf, 0x79, 0x9a, 0x68, 0x8f, 0x60, 0x32, 0xf5, 0x2d, 0x7b, + 0x59, 0x9d, 0x70, 0x5d, 0x84, 0xbe, 0x3a, 0x08, 0x91, 0xac, 0x92, 0x99, 0x27, 0xa1, 0xb2, 0x4a, + 0xa6, 0x31, 0xea, 0x2a, 0xa9, 0x7e, 0xe3, 0x69, 0xbf, 0xcd, 0x41, 0x69, 0xd0, 0x3f, 0xc5, 0xb6, + 0xfa, 0x9f, 0x46, 0xdf, 0x4d, 0xfa, 0x37, 0xaf, 0xb0, 0x29, 0x69, 0x77, 0xe6, 0xad, 0x67, 0xf4, + 0x09, 0xce, 0x04, 0x46, 0x6d, 0xb7, 0xfa, 0xa5, 0xc7, 0x8a, 0x78, 0xcf, 0x2b, 0x4f, 0x59, 0xc4, + 0xb3, 0x28, 0x75, 0x11, 0xef, 0xd7, 0x23, 0x32, 0x3d, 0x3d, 0xfd, 0xe1, 0xfd, 0xfe, 0xf9, 0x3d, + 0x48, 0x4f, 0xbf, 0x06, 0x8d, 0xe9, 0xe9, 0x69, 0xce, 0xee, 0xf7, 0x3f, 0x82, 0x41, 0x7a, 0xfa, + 0x35, 0x06, 0xbb, 0x0f, 0x3e, 0x7e, 0x56, 0xcc, 0x7d, 0xf2, 0xac, 0x98, 0xfb, 0xcf, 0xb3, 0x62, + 0xee, 0xd7, 0xcf, 0x8b, 0x43, 0x9f, 0x3c, 0x2f, 0x0e, 0xfd, 0xf3, 0x79, 0x71, 0xe8, 0xd1, 0x66, + 0xa2, 0x85, 0x39, 0xe4, 0x12, 0xd7, 0x1f, 0xa0, 0x1a, 0xad, 0xc4, 0xfd, 0xc8, 0xf1, 0xc6, 0xeb, + 0xc9, 0x9e, 0x84, 0xb7, 0x34, 0xb5, 0x51, 0xfe, 0xcf, 0xd9, 0xad, 0xff, 0x05, 0x00, 0x00, 0xff, + 0xff, 0x9f, 0x21, 0x36, 0x14, 0x67, 0x1e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1720,6 +2201,9 @@ type MsgClient interface { UndelegateHost(ctx context.Context, in *MsgUndelegateHost, opts ...grpc.CallOption) (*MsgUndelegateHostResponse, error) UpdateInnerRedemptionRateBounds(ctx context.Context, in *MsgUpdateInnerRedemptionRateBounds, opts ...grpc.CallOption) (*MsgUpdateInnerRedemptionRateBoundsResponse, error) ResumeHostZone(ctx context.Context, in *MsgResumeHostZone, opts ...grpc.CallOption) (*MsgResumeHostZoneResponse, error) + CreateTradeRoute(ctx context.Context, in *MsgCreateTradeRoute, opts ...grpc.CallOption) (*MsgCreateTradeRouteResponse, error) + DeleteTradeRoute(ctx context.Context, in *MsgDeleteTradeRoute, opts ...grpc.CallOption) (*MsgDeleteTradeRouteResponse, error) + UpdateTradeRoute(ctx context.Context, in *MsgUpdateTradeRoute, opts ...grpc.CallOption) (*MsgUpdateTradeRouteResponse, error) } type msgClient struct { @@ -1874,6 +2358,33 @@ func (c *msgClient) ResumeHostZone(ctx context.Context, in *MsgResumeHostZone, o return out, nil } +func (c *msgClient) CreateTradeRoute(ctx context.Context, in *MsgCreateTradeRoute, opts ...grpc.CallOption) (*MsgCreateTradeRouteResponse, error) { + out := new(MsgCreateTradeRouteResponse) + err := c.cc.Invoke(ctx, "/stride.stakeibc.Msg/CreateTradeRoute", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) DeleteTradeRoute(ctx context.Context, in *MsgDeleteTradeRoute, opts ...grpc.CallOption) (*MsgDeleteTradeRouteResponse, error) { + out := new(MsgDeleteTradeRouteResponse) + err := c.cc.Invoke(ctx, "/stride.stakeibc.Msg/DeleteTradeRoute", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateTradeRoute(ctx context.Context, in *MsgUpdateTradeRoute, opts ...grpc.CallOption) (*MsgUpdateTradeRouteResponse, error) { + out := new(MsgUpdateTradeRouteResponse) + err := c.cc.Invoke(ctx, "/stride.stakeibc.Msg/UpdateTradeRoute", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // MsgServer is the server API for Msg service. type MsgServer interface { LiquidStake(context.Context, *MsgLiquidStake) (*MsgLiquidStakeResponse, error) @@ -1892,6 +2403,9 @@ type MsgServer interface { UndelegateHost(context.Context, *MsgUndelegateHost) (*MsgUndelegateHostResponse, error) UpdateInnerRedemptionRateBounds(context.Context, *MsgUpdateInnerRedemptionRateBounds) (*MsgUpdateInnerRedemptionRateBoundsResponse, error) ResumeHostZone(context.Context, *MsgResumeHostZone) (*MsgResumeHostZoneResponse, error) + CreateTradeRoute(context.Context, *MsgCreateTradeRoute) (*MsgCreateTradeRouteResponse, error) + DeleteTradeRoute(context.Context, *MsgDeleteTradeRoute) (*MsgDeleteTradeRouteResponse, error) + UpdateTradeRoute(context.Context, *MsgUpdateTradeRoute) (*MsgUpdateTradeRouteResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -1946,8 +2460,17 @@ func (*UnimplementedMsgServer) UpdateInnerRedemptionRateBounds(ctx context.Conte func (*UnimplementedMsgServer) ResumeHostZone(ctx context.Context, req *MsgResumeHostZone) (*MsgResumeHostZoneResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ResumeHostZone not implemented") } - -func RegisterMsgServer(s grpc1.Server, srv MsgServer) { +func (*UnimplementedMsgServer) CreateTradeRoute(ctx context.Context, req *MsgCreateTradeRoute) (*MsgCreateTradeRouteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateTradeRoute not implemented") +} +func (*UnimplementedMsgServer) DeleteTradeRoute(ctx context.Context, req *MsgDeleteTradeRoute) (*MsgDeleteTradeRouteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteTradeRoute not implemented") +} +func (*UnimplementedMsgServer) UpdateTradeRoute(ctx context.Context, req *MsgUpdateTradeRoute) (*MsgUpdateTradeRouteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateTradeRoute not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } @@ -2239,6 +2762,60 @@ func _Msg_ResumeHostZone_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _Msg_CreateTradeRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgCreateTradeRoute) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).CreateTradeRoute(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakeibc.Msg/CreateTradeRoute", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).CreateTradeRoute(ctx, req.(*MsgCreateTradeRoute)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_DeleteTradeRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgDeleteTradeRoute) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).DeleteTradeRoute(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakeibc.Msg/DeleteTradeRoute", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).DeleteTradeRoute(ctx, req.(*MsgDeleteTradeRoute)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateTradeRoute_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateTradeRoute) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateTradeRoute(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/stride.stakeibc.Msg/UpdateTradeRoute", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateTradeRoute(ctx, req.(*MsgUpdateTradeRoute)) + } + return interceptor(ctx, in, info, handler) +} + var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "stride.stakeibc.Msg", HandlerType: (*MsgServer)(nil), @@ -2307,6 +2884,18 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "ResumeHostZone", Handler: _Msg_ResumeHostZone_Handler, }, + { + MethodName: "CreateTradeRoute", + Handler: _Msg_CreateTradeRoute_Handler, + }, + { + MethodName: "DeleteTradeRoute", + Handler: _Msg_DeleteTradeRoute_Handler, + }, + { + MethodName: "UpdateTradeRoute", + Handler: _Msg_UpdateTradeRoute_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "stride/stakeibc/tx.proto", @@ -3199,10 +3788,19 @@ func (m *MsgRestoreInterchainAccount) MarshalToSizedBuffer(dAtA []byte) (int, er _ = i var l int _ = l - if m.AccountType != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.AccountType)) + if len(m.AccountOwner) > 0 { + i -= len(m.AccountOwner) + copy(dAtA[i:], m.AccountOwner) + i = encodeVarintTx(dAtA, i, uint64(len(m.AccountOwner))) i-- - dAtA[i] = 0x18 + dAtA[i] = 0x22 + } + if len(m.ConnectionId) > 0 { + i -= len(m.ConnectionId) + copy(dAtA[i:], m.ConnectionId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ConnectionId))) + i-- + dAtA[i] = 0x1a } if len(m.ChainId) > 0 { i -= len(m.ChainId) @@ -3501,225 +4099,348 @@ func (m *MsgResumeHostZoneResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *MsgCreateTradeRoute) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *MsgUpdateInnerRedemptionRateBounds) Size() (n int) { - if m == nil { - return 0 - } + +func (m *MsgCreateTradeRoute) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgCreateTradeRoute) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + { + size := m.MaxSwapAmount.Size() + i -= size + if _, err := m.MaxSwapAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = len(m.ChainId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + { + size := m.MinSwapAmount.Size() + i -= size + if _, err := m.MinSwapAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = m.MinInnerRedemptionRate.Size() - n += 1 + l + sovTx(uint64(l)) - l = m.MaxInnerRedemptionRate.Size() - n += 1 + l + sovTx(uint64(l)) - return n -} - -func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Size() (n int) { - if m == nil { - return 0 + i-- + dAtA[i] = 0x7a + if len(m.MaxAllowedSwapLossRate) > 0 { + i -= len(m.MaxAllowedSwapLossRate) + copy(dAtA[i:], m.MaxAllowedSwapLossRate) + i = encodeVarintTx(dAtA, i, uint64(len(m.MaxAllowedSwapLossRate))) + i-- + dAtA[i] = 0x72 } - var l int - _ = l - return n -} - -func (m *MsgLiquidStake) Size() (n int) { - if m == nil { - return 0 + if m.PoolId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x68 } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.HostDenomOnHost) > 0 { + i -= len(m.HostDenomOnHost) + copy(dAtA[i:], m.HostDenomOnHost) + i = encodeVarintTx(dAtA, i, uint64(len(m.HostDenomOnHost))) + i-- + dAtA[i] = 0x62 } - l = m.Amount.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.HostDenom) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.HostDenomOnTrade) > 0 { + i -= len(m.HostDenomOnTrade) + copy(dAtA[i:], m.HostDenomOnTrade) + i = encodeVarintTx(dAtA, i, uint64(len(m.HostDenomOnTrade))) + i-- + dAtA[i] = 0x5a } - return n -} - -func (m *MsgLiquidStakeResponse) Size() (n int) { - if m == nil { - return 0 + if len(m.RewardDenomOnTrade) > 0 { + i -= len(m.RewardDenomOnTrade) + copy(dAtA[i:], m.RewardDenomOnTrade) + i = encodeVarintTx(dAtA, i, uint64(len(m.RewardDenomOnTrade))) + i-- + dAtA[i] = 0x52 } - var l int - _ = l - l = m.StToken.Size() - n += 1 + l + sovTx(uint64(l)) - return n -} - -func (m *MsgLSMLiquidStake) Size() (n int) { - if m == nil { - return 0 + if len(m.RewardDenomOnReward) > 0 { + i -= len(m.RewardDenomOnReward) + copy(dAtA[i:], m.RewardDenomOnReward) + i = encodeVarintTx(dAtA, i, uint64(len(m.RewardDenomOnReward))) + i-- + dAtA[i] = 0x4a } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.RewardDenomOnHost) > 0 { + i -= len(m.RewardDenomOnHost) + copy(dAtA[i:], m.RewardDenomOnHost) + i = encodeVarintTx(dAtA, i, uint64(len(m.RewardDenomOnHost))) + i-- + dAtA[i] = 0x42 } - l = m.Amount.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.LsmTokenIbcDenom) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.TradeToHostTransferChannelId) > 0 { + i -= len(m.TradeToHostTransferChannelId) + copy(dAtA[i:], m.TradeToHostTransferChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.TradeToHostTransferChannelId))) + i-- + dAtA[i] = 0x3a } - return n -} - -func (m *MsgLSMLiquidStakeResponse) Size() (n int) { - if m == nil { - return 0 + if len(m.RewardToTradeTransferChannelId) > 0 { + i -= len(m.RewardToTradeTransferChannelId) + copy(dAtA[i:], m.RewardToTradeTransferChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.RewardToTradeTransferChannelId))) + i-- + dAtA[i] = 0x32 } - var l int - _ = l - if m.TransactionComplete { - n += 2 + if len(m.HostToRewardTransferChannelId) > 0 { + i -= len(m.HostToRewardTransferChannelId) + copy(dAtA[i:], m.HostToRewardTransferChannelId) + i = encodeVarintTx(dAtA, i, uint64(len(m.HostToRewardTransferChannelId))) + i-- + dAtA[i] = 0x2a } - return n -} - -func (m *MsgClearBalance) Size() (n int) { - if m == nil { - return 0 + if len(m.StrideToTradeConnectionId) > 0 { + i -= len(m.StrideToTradeConnectionId) + copy(dAtA[i:], m.StrideToTradeConnectionId) + i = encodeVarintTx(dAtA, i, uint64(len(m.StrideToTradeConnectionId))) + i-- + dAtA[i] = 0x22 } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.StrideToRewardConnectionId) > 0 { + i -= len(m.StrideToRewardConnectionId) + copy(dAtA[i:], m.StrideToRewardConnectionId) + i = encodeVarintTx(dAtA, i, uint64(len(m.StrideToRewardConnectionId))) + i-- + dAtA[i] = 0x1a } - l = len(m.ChainId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.HostChainId) > 0 { + i -= len(m.HostChainId) + copy(dAtA[i:], m.HostChainId) + i = encodeVarintTx(dAtA, i, uint64(len(m.HostChainId))) + i-- + dAtA[i] = 0x12 } - l = m.Amount.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.Channel) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa } - return n + return len(dAtA) - i, nil } -func (m *MsgClearBalanceResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgCreateTradeRouteResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - var l int - _ = l - return n + return dAtA[:n], nil } -func (m *MsgRedeemStake) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = m.Amount.Size() - n += 1 + l + sovTx(uint64(l)) - l = len(m.HostZone) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Receiver) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n +func (m *MsgCreateTradeRouteResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgRedeemStakeResponse) Size() (n int) { - if m == nil { - return 0 - } +func (m *MsgCreateTradeRouteResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - return n + return len(dAtA) - i, nil } -func (m *MsgRegisterHostZone) Size() (n int) { - if m == nil { - return 0 +func (m *MsgDeleteTradeRoute) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } + return dAtA[:n], nil +} + +func (m *MsgDeleteTradeRoute) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDeleteTradeRoute) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.ConnectionId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.HostDenom) > 0 { + i -= len(m.HostDenom) + copy(dAtA[i:], m.HostDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.HostDenom))) + i-- + dAtA[i] = 0x1a } - l = len(m.HostDenom) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.RewardDenom) > 0 { + i -= len(m.RewardDenom) + copy(dAtA[i:], m.RewardDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.RewardDenom))) + i-- + dAtA[i] = 0x12 } - l = len(m.IbcDenom) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa } - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + return len(dAtA) - i, nil +} + +func (m *MsgDeleteTradeRouteResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - l = len(m.TransferChannelId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + return dAtA[:n], nil +} + +func (m *MsgDeleteTradeRouteResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgDeleteTradeRouteResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateTradeRoute) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - if m.UnbondingPeriod != 0 { - n += 1 + sovTx(uint64(m.UnbondingPeriod)) + return dAtA[:n], nil +} + +func (m *MsgUpdateTradeRoute) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateTradeRoute) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.MaxSwapAmount.Size() + i -= size + if _, err := m.MaxSwapAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = len(m.Bech32Prefix) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + i-- + dAtA[i] = 0x3a + { + size := m.MinSwapAmount.Size() + i -= size + if _, err := m.MinSwapAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) } - l = m.MinRedemptionRate.Size() - n += 1 + l + sovTx(uint64(l)) - l = m.MaxRedemptionRate.Size() - n += 1 + l + sovTx(uint64(l)) - if m.LsmLiquidStakeEnabled { - n += 2 + i-- + dAtA[i] = 0x32 + if len(m.MaxAllowedSwapLossRate) > 0 { + i -= len(m.MaxAllowedSwapLossRate) + copy(dAtA[i:], m.MaxAllowedSwapLossRate) + i = encodeVarintTx(dAtA, i, uint64(len(m.MaxAllowedSwapLossRate))) + i-- + dAtA[i] = 0x2a } - return n + if m.PoolId != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.PoolId)) + i-- + dAtA[i] = 0x20 + } + if len(m.HostDenom) > 0 { + i -= len(m.HostDenom) + copy(dAtA[i:], m.HostDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.HostDenom))) + i-- + dAtA[i] = 0x1a + } + if len(m.RewardDenom) > 0 { + i -= len(m.RewardDenom) + copy(dAtA[i:], m.RewardDenom) + i = encodeVarintTx(dAtA, i, uint64(len(m.RewardDenom))) + i-- + dAtA[i] = 0x12 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } -func (m *MsgRegisterHostZoneResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgUpdateTradeRouteResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } + return dAtA[:n], nil +} + +func (m *MsgUpdateTradeRouteResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateTradeRouteResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - return n + return len(dAtA) - i, nil } -func (m *MsgClaimUndelegatedTokens) Size() (n int) { +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgUpdateInnerRedemptionRateBounds) Size() (n int) { if m == nil { return 0 } @@ -3729,21 +4450,18 @@ func (m *MsgClaimUndelegatedTokens) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.HostZoneId) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if m.Epoch != 0 { - n += 1 + sovTx(uint64(m.Epoch)) - } - l = len(m.Sender) + l = len(m.ChainId) if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = m.MinInnerRedemptionRate.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.MaxInnerRedemptionRate.Size() + n += 1 + l + sovTx(uint64(l)) return n } -func (m *MsgClaimUndelegatedTokensResponse) Size() (n int) { +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Size() (n int) { if m == nil { return 0 } @@ -3752,7 +4470,7 @@ func (m *MsgClaimUndelegatedTokensResponse) Size() (n int) { return n } -func (m *MsgRebalanceValidators) Size() (n int) { +func (m *MsgLiquidStake) Size() (n int) { if m == nil { return 0 } @@ -3762,26 +4480,27 @@ func (m *MsgRebalanceValidators) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.HostZone) + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.HostDenom) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.NumRebalance != 0 { - n += 1 + sovTx(uint64(m.NumRebalance)) - } return n } -func (m *MsgRebalanceValidatorsResponse) Size() (n int) { +func (m *MsgLiquidStakeResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l + l = m.StToken.Size() + n += 1 + l + sovTx(uint64(l)) return n } -func (m *MsgAddValidators) Size() (n int) { +func (m *MsgLSMLiquidStake) Size() (n int) { if m == nil { return 0 } @@ -3791,29 +4510,28 @@ func (m *MsgAddValidators) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.HostZone) + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.LsmTokenIbcDenom) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if len(m.Validators) > 0 { - for _, e := range m.Validators { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } return n } -func (m *MsgAddValidatorsResponse) Size() (n int) { +func (m *MsgLSMLiquidStakeResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l + if m.TransactionComplete { + n += 2 + } return n } -func (m *MsgChangeValidatorWeight) Size() (n int) { +func (m *MsgClearBalance) Size() (n int) { if m == nil { return 0 } @@ -3823,21 +4541,20 @@ func (m *MsgChangeValidatorWeight) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.HostZone) + l = len(m.ChainId) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ValAddr) + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + l = len(m.Channel) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.Weight != 0 { - n += 1 + sovTx(uint64(m.Weight)) - } return n } -func (m *MsgChangeValidatorWeightResponse) Size() (n int) { +func (m *MsgClearBalanceResponse) Size() (n int) { if m == nil { return 0 } @@ -3846,7 +4563,7 @@ func (m *MsgChangeValidatorWeightResponse) Size() (n int) { return n } -func (m *MsgDeleteValidator) Size() (n int) { +func (m *MsgRedeemStake) Size() (n int) { if m == nil { return 0 } @@ -3856,18 +4573,20 @@ func (m *MsgDeleteValidator) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) l = len(m.HostZone) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ValAddr) + l = len(m.Receiver) if l > 0 { n += 1 + l + sovTx(uint64(l)) } return n } -func (m *MsgDeleteValidatorResponse) Size() (n int) { +func (m *MsgRedeemStakeResponse) Size() (n int) { if m == nil { return 0 } @@ -3876,27 +4595,50 @@ func (m *MsgDeleteValidatorResponse) Size() (n int) { return n } -func (m *MsgRestoreInterchainAccount) Size() (n int) { +func (m *MsgRegisterHostZone) Size() (n int) { if m == nil { return 0 } var l int _ = l + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.IbcDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } l = len(m.Creator) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ChainId) + l = len(m.TransferChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.UnbondingPeriod != 0 { + n += 1 + sovTx(uint64(m.UnbondingPeriod)) + } + l = len(m.Bech32Prefix) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - if m.AccountType != 0 { - n += 1 + sovTx(uint64(m.AccountType)) + l = m.MinRedemptionRate.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.MaxRedemptionRate.Size() + n += 1 + l + sovTx(uint64(l)) + if m.LsmLiquidStakeEnabled { + n += 2 } return n } -func (m *MsgRestoreInterchainAccountResponse) Size() (n int) { +func (m *MsgRegisterHostZoneResponse) Size() (n int) { if m == nil { return 0 } @@ -3905,7 +4647,7 @@ func (m *MsgRestoreInterchainAccountResponse) Size() (n int) { return n } -func (m *MsgUpdateValidatorSharesExchRate) Size() (n int) { +func (m *MsgClaimUndelegatedTokens) Size() (n int) { if m == nil { return 0 } @@ -3915,12 +4657,203 @@ func (m *MsgUpdateValidatorSharesExchRate) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.ChainId) + l = len(m.HostZoneId) if l > 0 { n += 1 + l + sovTx(uint64(l)) } - l = len(m.Valoper) - if l > 0 { + if m.Epoch != 0 { + n += 1 + sovTx(uint64(m.Epoch)) + } + l = len(m.Sender) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgClaimUndelegatedTokensResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRebalanceValidators) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostZone) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.NumRebalance != 0 { + n += 1 + sovTx(uint64(m.NumRebalance)) + } + return n +} + +func (m *MsgRebalanceValidatorsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgAddValidators) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostZone) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if len(m.Validators) > 0 { + for _, e := range m.Validators { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + return n +} + +func (m *MsgAddValidatorsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgChangeValidatorWeight) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostZone) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ValAddr) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Weight != 0 { + n += 1 + sovTx(uint64(m.Weight)) + } + return n +} + +func (m *MsgChangeValidatorWeightResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgDeleteValidator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostZone) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ValAddr) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgDeleteValidatorResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRestoreInterchainAccount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ConnectionId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.AccountOwner) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRestoreInterchainAccountResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateValidatorSharesExchRate) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Valoper) + if l > 0 { n += 1 + l + sovTx(uint64(l)) } return n @@ -4015,18 +4948,166 @@ func (m *MsgResumeHostZoneResponse) Size() (n int) { return n } -func sovTx(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *MsgCreateTradeRoute) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostChainId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.StrideToRewardConnectionId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.StrideToTradeConnectionId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostToRewardTransferChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RewardToTradeTransferChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.TradeToHostTransferChannelId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RewardDenomOnHost) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RewardDenomOnReward) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RewardDenomOnTrade) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostDenomOnTrade) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostDenomOnHost) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PoolId != 0 { + n += 1 + sovTx(uint64(m.PoolId)) + } + l = len(m.MaxAllowedSwapLossRate) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.MinSwapAmount.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.MaxSwapAmount.Size() + n += 2 + l + sovTx(uint64(l)) + return n } -func sozTx(x uint64) (n int) { - return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *MsgCreateTradeRouteResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n } -func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 + +func (m *MsgDeleteTradeRoute) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RewardDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgDeleteTradeRouteResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateTradeRoute) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.RewardDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.HostDenom) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.PoolId != 0 { + n += 1 + sovTx(uint64(m.PoolId)) + } + l = len(m.MaxAllowedSwapLossRate) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.MinSwapAmount.Size() + n += 1 + l + sovTx(uint64(l)) + l = m.MaxSwapAmount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateTradeRouteResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4052,7 +5133,1327 @@ func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinInnerRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MinInnerRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxInnerRedemptionRate", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.MaxInnerRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateInnerRedemptionRateBoundsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateInnerRedemptionRateBoundsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgLiquidStake) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgLiquidStake: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgLiquidStake: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgLiquidStakeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgLiquidStakeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgLiquidStakeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StToken", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.StToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgLSMLiquidStake) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgLSMLiquidStake: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgLSMLiquidStake: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field LsmTokenIbcDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.LsmTokenIbcDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgLSMLiquidStakeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgLSMLiquidStakeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgLSMLiquidStakeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TransactionComplete", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.TransactionComplete = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgClearBalance) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgClearBalance: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgClearBalance: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Channel = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgClearBalanceResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgClearBalanceResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgClearBalanceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRedeemStake: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRedeemStake: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostZone = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Receiver = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRedeemStakeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRedeemStakeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRedeemStakeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRegisterHostZone: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRegisterHostZone: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field IbcDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.IbcDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TransferChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TransferChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UnbondingPeriod", wireType) + } + m.UnbondingPeriod = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UnbondingPeriod |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Bech32Prefix", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4080,11 +6481,11 @@ func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + m.Bech32Prefix = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 13: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MinRedemptionRate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4112,11 +6513,13 @@ func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainId = string(dAtA[iNdEx:postIndex]) + if err := m.MinRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 3: + case 14: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MinInnerRedemptionRate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxRedemptionRate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4144,15 +6547,15 @@ func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MinInnerRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.MaxRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxInnerRedemptionRate", wireType) + case 15: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LsmLiquidStakeEnabled", wireType) } - var stringLen uint64 + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4162,26 +6565,12 @@ func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.MaxInnerRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex + m.LsmLiquidStakeEnabled = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4203,7 +6592,7 @@ func (m *MsgUpdateInnerRedemptionRateBounds) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Unmarshal(dAtA []byte) error { +func (m *MsgRegisterHostZoneResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4226,10 +6615,10 @@ func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Unmarshal(dAtA []byte) erro fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateInnerRedemptionRateBoundsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRegisterHostZoneResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateInnerRedemptionRateBoundsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRegisterHostZoneResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -4253,7 +6642,7 @@ func (m *MsgUpdateInnerRedemptionRateBoundsResponse) Unmarshal(dAtA []byte) erro } return nil } -func (m *MsgLiquidStake) Unmarshal(dAtA []byte) error { +func (m *MsgClaimUndelegatedTokens) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4276,10 +6665,10 @@ func (m *MsgLiquidStake) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgLiquidStake: wiretype end group for non-group") + return fmt.Errorf("proto: MsgClaimUndelegatedTokens: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgLiquidStake: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgClaimUndelegatedTokens: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -4316,7 +6705,7 @@ func (m *MsgLiquidStake) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HostZoneId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4344,13 +6733,30 @@ func (m *MsgLiquidStake) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.HostZoneId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Epoch", wireType) + } + m.Epoch = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Epoch |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HostDenom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4378,7 +6784,7 @@ func (m *MsgLiquidStake) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.HostDenom = string(dAtA[iNdEx:postIndex]) + m.Sender = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -4401,7 +6807,7 @@ func (m *MsgLiquidStake) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgLiquidStakeResponse) Unmarshal(dAtA []byte) error { +func (m *MsgClaimUndelegatedTokensResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4424,45 +6830,12 @@ func (m *MsgLiquidStakeResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgLiquidStakeResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgClaimUndelegatedTokensResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgLiquidStakeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgClaimUndelegatedTokensResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field StToken", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.StToken.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4484,7 +6857,7 @@ func (m *MsgLiquidStakeResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgLSMLiquidStake) Unmarshal(dAtA []byte) error { +func (m *MsgRebalanceValidators) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4507,10 +6880,10 @@ func (m *MsgLSMLiquidStake) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgLSMLiquidStake: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRebalanceValidators: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgLSMLiquidStake: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRebalanceValidators: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -4547,7 +6920,7 @@ func (m *MsgLSMLiquidStake) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4575,15 +6948,13 @@ func (m *MsgLSMLiquidStake) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.HostZone = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LsmTokenIbcDenom", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumRebalance", wireType) } - var stringLen uint64 + m.NumRebalance = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4593,24 +6964,11 @@ func (m *MsgLSMLiquidStake) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.NumRebalance |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.LsmTokenIbcDenom = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4632,7 +6990,7 @@ func (m *MsgLSMLiquidStake) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgLSMLiquidStakeResponse) Unmarshal(dAtA []byte) error { +func (m *MsgRebalanceValidatorsResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4655,32 +7013,12 @@ func (m *MsgLSMLiquidStakeResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgLSMLiquidStakeResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRebalanceValidatorsResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgLSMLiquidStakeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRebalanceValidatorsResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TransactionComplete", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.TransactionComplete = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4702,7 +7040,7 @@ func (m *MsgLSMLiquidStakeResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgClearBalance) Unmarshal(dAtA []byte) error { +func (m *MsgAddValidators) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4725,10 +7063,10 @@ func (m *MsgClearBalance) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgClearBalance: wiretype end group for non-group") + return fmt.Errorf("proto: MsgAddValidators: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgClearBalance: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgAddValidators: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -4765,7 +7103,7 @@ func (m *MsgClearBalance) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -4793,13 +7131,13 @@ func (m *MsgClearBalance) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainId = string(dAtA[iNdEx:postIndex]) + m.HostZone = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Validators", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -4809,58 +7147,26 @@ func (m *MsgClearBalance) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.Validators = append(m.Validators, &Validator{}) + if err := m.Validators[len(m.Validators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Channel", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - 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 ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Channel = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4882,7 +7188,7 @@ func (m *MsgClearBalance) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgClearBalanceResponse) Unmarshal(dAtA []byte) error { +func (m *MsgAddValidatorsResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4905,10 +7211,10 @@ func (m *MsgClearBalanceResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgClearBalanceResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgAddValidatorsResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgClearBalanceResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgAddValidatorsResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -4932,7 +7238,7 @@ func (m *MsgClearBalanceResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { +func (m *MsgChangeValidatorWeight) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4955,10 +7261,10 @@ func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRedeemStake: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChangeValidatorWeight: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRedeemStake: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChangeValidatorWeight: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -4995,7 +7301,7 @@ func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5023,13 +7329,11 @@ func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.HostZone = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ValAddr", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5057,13 +7361,13 @@ func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.HostZone = string(dAtA[iNdEx:postIndex]) + m.ValAddr = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Weight", wireType) } - var stringLen uint64 + m.Weight = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -5073,24 +7377,11 @@ func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.Weight |= uint64(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Receiver = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -5112,7 +7403,7 @@ func (m *MsgRedeemStake) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRedeemStakeResponse) Unmarshal(dAtA []byte) error { +func (m *MsgChangeValidatorWeightResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5135,10 +7426,10 @@ func (m *MsgRedeemStakeResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRedeemStakeResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgChangeValidatorWeightResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRedeemStakeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgChangeValidatorWeightResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -5162,7 +7453,7 @@ func (m *MsgRedeemStakeResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { +func (m *MsgDeleteValidator) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5185,15 +7476,15 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterHostZone: wiretype end group for non-group") + return fmt.Errorf("proto: MsgDeleteValidator: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterHostZone: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgDeleteValidator: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 2: + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5221,11 +7512,11 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ConnectionId = string(dAtA[iNdEx:postIndex]) + m.Creator = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HostDenom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5253,11 +7544,11 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.HostDenom = string(dAtA[iNdEx:postIndex]) + m.HostZone = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 5: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IbcDenom", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ValAddr", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5285,43 +7576,111 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.IbcDenom = string(dAtA[iNdEx:postIndex]) + m.ValAddr = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err } - intStringLen := int(stringLen) - if intStringLen < 0 { + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + intStringLen - if postIndex < 0 { + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgDeleteValidatorResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgDeleteValidatorResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgDeleteValidatorResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { return ErrInvalidLengthTx } - if postIndex > l { + if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 10: + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRestoreInterchainAccount) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRestoreInterchainAccount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRestoreInterchainAccount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TransferChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5349,30 +7708,11 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.TransferChannelId = string(dAtA[iNdEx:postIndex]) + m.Creator = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 11: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondingPeriod", wireType) - } - m.UnbondingPeriod = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.UnbondingPeriod |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 12: + case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Bech32Prefix", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5400,11 +7740,11 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Bech32Prefix = string(dAtA[iNdEx:postIndex]) + m.ChainId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 13: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MinRedemptionRate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ConnectionId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5432,13 +7772,11 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MinRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ConnectionId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 14: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field MaxRedemptionRate", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AccountOwner", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5466,30 +7804,8 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.MaxRedemptionRate.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.AccountOwner = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 15: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LsmLiquidStakeEnabled", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.LsmLiquidStakeEnabled = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -5511,7 +7827,7 @@ func (m *MsgRegisterHostZone) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRegisterHostZoneResponse) Unmarshal(dAtA []byte) error { +func (m *MsgRestoreInterchainAccountResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5534,10 +7850,10 @@ func (m *MsgRegisterHostZoneResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRegisterHostZoneResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgRestoreInterchainAccountResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRegisterHostZoneResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgRestoreInterchainAccountResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -5561,7 +7877,7 @@ func (m *MsgRegisterHostZoneResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgClaimUndelegatedTokens) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateValidatorSharesExchRate) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5584,10 +7900,10 @@ func (m *MsgClaimUndelegatedTokens) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgClaimUndelegatedTokens: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateValidatorSharesExchRate: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgClaimUndelegatedTokens: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateValidatorSharesExchRate: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -5624,7 +7940,7 @@ func (m *MsgClaimUndelegatedTokens) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HostZoneId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5652,30 +7968,11 @@ func (m *MsgClaimUndelegatedTokens) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.HostZoneId = string(dAtA[iNdEx:postIndex]) + m.ChainId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Epoch", wireType) - } - m.Epoch = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Epoch |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Valoper", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5703,7 +8000,7 @@ func (m *MsgClaimUndelegatedTokens) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Sender = string(dAtA[iNdEx:postIndex]) + m.Valoper = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -5726,7 +8023,7 @@ func (m *MsgClaimUndelegatedTokens) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgClaimUndelegatedTokensResponse) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateValidatorSharesExchRateResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5749,10 +8046,10 @@ func (m *MsgClaimUndelegatedTokensResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgClaimUndelegatedTokensResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateValidatorSharesExchRateResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgClaimUndelegatedTokensResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateValidatorSharesExchRateResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -5776,7 +8073,7 @@ func (m *MsgClaimUndelegatedTokensResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRebalanceValidators) Unmarshal(dAtA []byte) error { +func (m *MsgUndelegateHost) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5799,10 +8096,10 @@ func (m *MsgRebalanceValidators) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRebalanceValidators: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUndelegateHost: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRebalanceValidators: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUndelegateHost: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -5839,7 +8136,7 @@ func (m *MsgRebalanceValidators) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -5867,27 +8164,10 @@ func (m *MsgRebalanceValidators) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.HostZone = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field NumRebalance", wireType) - } - m.NumRebalance = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.NumRebalance |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -5909,7 +8189,7 @@ func (m *MsgRebalanceValidators) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgRebalanceValidatorsResponse) Unmarshal(dAtA []byte) error { +func (m *MsgUndelegateHostResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5932,10 +8212,10 @@ func (m *MsgRebalanceValidatorsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgRebalanceValidatorsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUndelegateHostResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRebalanceValidatorsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUndelegateHostResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -5959,7 +8239,7 @@ func (m *MsgRebalanceValidatorsResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgAddValidators) Unmarshal(dAtA []byte) error { +func (m *MsgCalibrateDelegation) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -5982,10 +8262,10 @@ func (m *MsgAddValidators) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgAddValidators: wiretype end group for non-group") + return fmt.Errorf("proto: MsgCalibrateDelegation: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAddValidators: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgCalibrateDelegation: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -6022,7 +8302,7 @@ func (m *MsgAddValidators) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6050,13 +8330,13 @@ func (m *MsgAddValidators) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.HostZone = string(dAtA[iNdEx:postIndex]) + m.ChainId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Validators", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Valoper", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -6066,25 +8346,23 @@ func (m *MsgAddValidators) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - m.Validators = append(m.Validators, &Validator{}) - if err := m.Validators[len(m.Validators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Valoper = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -6107,7 +8385,7 @@ func (m *MsgAddValidators) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgAddValidatorsResponse) Unmarshal(dAtA []byte) error { +func (m *MsgCalibrateDelegationResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6130,10 +8408,10 @@ func (m *MsgAddValidatorsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgAddValidatorsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgCalibrateDelegationResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAddValidatorsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgCalibrateDelegationResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -6157,7 +8435,7 @@ func (m *MsgAddValidatorsResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChangeValidatorWeight) Unmarshal(dAtA []byte) error { +func (m *MsgResumeHostZone) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6180,10 +8458,10 @@ func (m *MsgChangeValidatorWeight) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChangeValidatorWeight: wiretype end group for non-group") + return fmt.Errorf("proto: MsgResumeHostZone: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChangeValidatorWeight: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgResumeHostZone: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -6220,39 +8498,7 @@ func (m *MsgChangeValidatorWeight) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - 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 ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.HostZone = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ValAddr", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6280,27 +8526,8 @@ func (m *MsgChangeValidatorWeight) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ValAddr = string(dAtA[iNdEx:postIndex]) + m.ChainId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Weight", wireType) - } - m.Weight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Weight |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -6322,7 +8549,7 @@ func (m *MsgChangeValidatorWeight) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgChangeValidatorWeightResponse) Unmarshal(dAtA []byte) error { +func (m *MsgResumeHostZoneResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6345,10 +8572,10 @@ func (m *MsgChangeValidatorWeightResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgChangeValidatorWeightResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgResumeHostZoneResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgChangeValidatorWeightResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgResumeHostZoneResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -6372,7 +8599,7 @@ func (m *MsgChangeValidatorWeightResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgDeleteValidator) Unmarshal(dAtA []byte) error { +func (m *MsgCreateTradeRoute) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6395,15 +8622,111 @@ func (m *MsgDeleteValidator) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgDeleteValidator: wiretype end group for non-group") + return fmt.Errorf("proto: MsgCreateTradeRoute: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgDeleteValidator: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgCreateTradeRoute: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StrideToRewardConnectionId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StrideToRewardConnectionId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StrideToTradeConnectionId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6431,11 +8754,11 @@ func (m *MsgDeleteValidator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + m.StrideToTradeConnectionId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 5: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field HostZone", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HostToRewardTransferChannelId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6463,11 +8786,11 @@ func (m *MsgDeleteValidator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.HostZone = string(dAtA[iNdEx:postIndex]) + m.HostToRewardTransferChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ValAddr", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RewardToTradeTransferChannelId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6495,111 +8818,43 @@ func (m *MsgDeleteValidator) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ValAddr = string(dAtA[iNdEx:postIndex]) + m.RewardToTradeTransferChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgDeleteValidatorResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TradeToHostTransferChannelId", wireType) } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgDeleteValidatorResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgDeleteValidatorResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - if (skippy < 0) || (iNdEx+skippy) < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRestoreInterchainAccount) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRestoreInterchainAccount: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRestoreInterchainAccount: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.TradeToHostTransferChannelId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenomOnHost", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6627,11 +8882,11 @@ func (m *MsgRestoreInterchainAccount) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + m.RewardDenomOnHost = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 9: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenomOnReward", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6659,13 +8914,13 @@ func (m *MsgRestoreInterchainAccount) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainId = string(dAtA[iNdEx:postIndex]) + m.RewardDenomOnReward = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field AccountType", wireType) + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenomOnTrade", wireType) } - m.AccountType = 0 + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -6675,114 +8930,110 @@ func (m *MsgRestoreInterchainAccount) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.AccountType |= ICAAccountType(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx } - if (skippy < 0) || (iNdEx+skippy) < 0 { + postIndex := iNdEx + intStringLen + if postIndex < 0 { return ErrInvalidLengthTx } - if (iNdEx + skippy) > l { + if postIndex > l { return io.ErrUnexpectedEOF } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRestoreInterchainAccountResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF + m.RewardDenomOnTrade = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostDenomOnTrade", wireType) } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRestoreInterchainAccountResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRestoreInterchainAccountResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx } - if (skippy < 0) || (iNdEx+skippy) < 0 { + postIndex := iNdEx + intStringLen + if postIndex < 0 { return ErrInvalidLengthTx } - if (iNdEx + skippy) > l { + if postIndex > l { return io.ErrUnexpectedEOF } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgUpdateValidatorSharesExchRate) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx + m.HostDenomOnTrade = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostDenomOnHost", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - if iNdEx >= l { + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + m.HostDenomOnHost = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateValidatorSharesExchRate: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateValidatorSharesExchRate: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 14: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxAllowedSwapLossRate", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6810,11 +9061,11 @@ func (m *MsgUpdateValidatorSharesExchRate) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + m.MaxAllowedSwapLossRate = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 2: + case 15: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MinSwapAmount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6842,11 +9093,13 @@ func (m *MsgUpdateValidatorSharesExchRate) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainId = string(dAtA[iNdEx:postIndex]) + if err := m.MinSwapAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 3: + case 16: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Valoper", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxSwapAmount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -6874,7 +9127,9 @@ func (m *MsgUpdateValidatorSharesExchRate) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Valoper = string(dAtA[iNdEx:postIndex]) + if err := m.MaxSwapAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -6897,7 +9152,7 @@ func (m *MsgUpdateValidatorSharesExchRate) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUpdateValidatorSharesExchRateResponse) Unmarshal(dAtA []byte) error { +func (m *MsgCreateTradeRouteResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6920,10 +9175,10 @@ func (m *MsgUpdateValidatorSharesExchRateResponse) Unmarshal(dAtA []byte) error fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUpdateValidatorSharesExchRateResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgCreateTradeRouteResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUpdateValidatorSharesExchRateResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgCreateTradeRouteResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -6947,7 +9202,7 @@ func (m *MsgUpdateValidatorSharesExchRateResponse) Unmarshal(dAtA []byte) error } return nil } -func (m *MsgUndelegateHost) Unmarshal(dAtA []byte) error { +func (m *MsgDeleteTradeRoute) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -6970,15 +9225,15 @@ func (m *MsgUndelegateHost) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUndelegateHost: wiretype end group for non-group") + return fmt.Errorf("proto: MsgDeleteTradeRoute: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUndelegateHost: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgDeleteTradeRoute: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -7006,11 +9261,11 @@ func (m *MsgUndelegateHost) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + m.Authority = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenom", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -7038,9 +9293,39 @@ func (m *MsgUndelegateHost) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.RewardDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HostDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HostDenom = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -7063,7 +9348,7 @@ func (m *MsgUndelegateHost) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUndelegateHostResponse) Unmarshal(dAtA []byte) error { +func (m *MsgDeleteTradeRouteResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -7086,10 +9371,10 @@ func (m *MsgUndelegateHostResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUndelegateHostResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgDeleteTradeRouteResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUndelegateHostResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgDeleteTradeRouteResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: @@ -7113,7 +9398,7 @@ func (m *MsgUndelegateHostResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgCalibrateDelegation) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateTradeRoute) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -7136,15 +9421,15 @@ func (m *MsgCalibrateDelegation) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgCalibrateDelegation: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateTradeRoute: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgCalibrateDelegation: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateTradeRoute: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -7172,11 +9457,11 @@ func (m *MsgCalibrateDelegation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + m.Authority = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RewardDenom", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -7204,11 +9489,11 @@ func (m *MsgCalibrateDelegation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainId = string(dAtA[iNdEx:postIndex]) + m.RewardDenom = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Valoper", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HostDenom", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -7236,111 +9521,62 @@ func (m *MsgCalibrateDelegation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Valoper = string(dAtA[iNdEx:postIndex]) + m.HostDenom = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgCalibrateDelegationResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PoolId", wireType) } - if iNdEx >= l { - return io.ErrUnexpectedEOF + m.PoolId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PoolId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxAllowedSwapLossRate", wireType) } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgCalibrateDelegationResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgCalibrateDelegationResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - if (skippy < 0) || (iNdEx+skippy) < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgResumeHostZone) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx } - if iNdEx >= l { + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgResumeHostZone: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgResumeHostZone: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + m.MaxAllowedSwapLossRate = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MinSwapAmount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -7368,11 +9604,13 @@ func (m *MsgResumeHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + if err := m.MinSwapAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 2: + case 7: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field MaxSwapAmount", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -7400,7 +9638,9 @@ func (m *MsgResumeHostZone) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainId = string(dAtA[iNdEx:postIndex]) + if err := m.MaxSwapAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -7423,7 +9663,7 @@ func (m *MsgResumeHostZone) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgResumeHostZoneResponse) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateTradeRouteResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -7446,10 +9686,10 @@ func (m *MsgResumeHostZoneResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgResumeHostZoneResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateTradeRouteResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgResumeHostZoneResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateTradeRouteResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: