diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md index dcd66663..ac8f77bc 100644 --- a/docs/proto/proto-docs.md +++ b/docs/proto/proto-docs.md @@ -26,6 +26,8 @@ - [ValidatorAddress](#osmosis.meshsecurity.v1beta1.ValidatorAddress) - [osmosis/meshsecurity/v1beta1/tx.proto](#osmosis/meshsecurity/v1beta1/tx.proto) + - [MsgSetPriceFeedContract](#osmosis.meshsecurity.v1beta1.MsgSetPriceFeedContract) + - [MsgSetPriceFeedContractResponse](#osmosis.meshsecurity.v1beta1.MsgSetPriceFeedContractResponse) - [MsgSetVirtualStakingMaxCap](#osmosis.meshsecurity.v1beta1.MsgSetVirtualStakingMaxCap) - [MsgSetVirtualStakingMaxCapResponse](#osmosis.meshsecurity.v1beta1.MsgSetVirtualStakingMaxCapResponse) @@ -287,6 +289,33 @@ ValidatorAddress payload data to be used with the scheduler + + +### MsgSetPriceFeedContract +MsgSetPriceFeedContract sets the price feed contract to the chain +to trigger handle epoch task + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `authority` | [string](#string) | | Authority is the address that controls the module (defaults to x/gov unless overwritten). | +| `contract` | [string](#string) | | Contract is the address of the price feed smart contract. | + + + + + + + + +### MsgSetPriceFeedContractResponse +MsgSetPriceFeedContractResponse returns result data. + + + + + + ### MsgSetVirtualStakingMaxCap @@ -329,6 +358,7 @@ Msg defines the wasm Msg service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `SetVirtualStakingMaxCap` | [MsgSetVirtualStakingMaxCap](#osmosis.meshsecurity.v1beta1.MsgSetVirtualStakingMaxCap) | [MsgSetVirtualStakingMaxCapResponse](#osmosis.meshsecurity.v1beta1.MsgSetVirtualStakingMaxCapResponse) | SetVirtualStakingMaxCap creates or updates a maximum cap limit for virtual staking coins | | +| `SetPriceFeedContract` | [MsgSetPriceFeedContract](#osmosis.meshsecurity.v1beta1.MsgSetPriceFeedContract) | [MsgSetPriceFeedContractResponse](#osmosis.meshsecurity.v1beta1.MsgSetPriceFeedContractResponse) | SetPriceFeedContract sets the price feed contract to the chain to trigger handle epoch task | | diff --git a/proto/osmosis/meshsecurity/v1beta1/tx.proto b/proto/osmosis/meshsecurity/v1beta1/tx.proto index 90434bb1..99f88966 100644 --- a/proto/osmosis/meshsecurity/v1beta1/tx.proto +++ b/proto/osmosis/meshsecurity/v1beta1/tx.proto @@ -15,6 +15,10 @@ service Msg { // staking coins rpc SetVirtualStakingMaxCap(MsgSetVirtualStakingMaxCap) returns (MsgSetVirtualStakingMaxCapResponse); + // SetPriceFeedContract sets the price feed contract to the chain + // to trigger handle epoch task + rpc SetPriceFeedContract(MsgSetPriceFeedContract) + returns (MsgSetPriceFeedContractResponse); } // MsgSetVirtualStakingMaxCap creates or updates a maximum cap limit for virtual @@ -37,3 +41,20 @@ message MsgSetVirtualStakingMaxCap { // MsgSetVirtualStakingMaxCap returns result data. message MsgSetVirtualStakingMaxCapResponse {} + +// MsgSetPriceFeedContract sets the price feed contract to the chain +// to trigger handle epoch task +message MsgSetPriceFeedContract { + option (amino.name) = "meshsecurity/MsgSetPriceFeedContract"; + option (cosmos.msg.v1.signer) = "authority"; + + // Authority is the address that controls the module (defaults to x/gov unless + // overwritten). + string authority = 1; + + // Contract is the address of the price feed smart contract. + string contract = 2; +} + +// MsgSetPriceFeedContractResponse returns result data. +message MsgSetPriceFeedContractResponse {} diff --git a/scripts/mesh/testibc/config_band.yaml b/scripts/mesh/testibc/config_band.yaml index 3bfc3dc8..e1f49fb1 100644 --- a/scripts/mesh/testibc/config_band.yaml +++ b/scripts/mesh/testibc/config_band.yaml @@ -1,5 +1,5 @@ global: - api-listen-addr: :5183 + api-listen-addr: :5184 timeout: 10s memo: "" light-cache-size: 20 diff --git a/scripts/mesh/testibc/config_osmosis_local.yaml b/scripts/mesh/testibc/config_osmosis_local.yaml new file mode 100644 index 00000000..697c40dd --- /dev/null +++ b/scripts/mesh/testibc/config_osmosis_local.yaml @@ -0,0 +1,57 @@ +global: + api-listen-addr: :5184 + timeout: 10s + memo: "" + light-cache-size: 20 +chains: + consumer: + type: cosmos + value: + key-directory: scripts/relayer/keys/chain-1 + key: key1 + chain-id: chain-1 + rpc-addr: http://localhost:26657 + account-prefix: mesh + keyring-backend: test + gas-adjustment: 1.2 + gas-prices: 0.01stake + min-gas-amount: 1000000 + max-gas-amount: 0 + debug: false + timeout: 20s + block-timeout: "" + output-format: json + sign-mode: direct + extra-codecs: [] + coin-type: 118 + signing-algorithm: "" + broadcast-mode: batch + min-loop-duration: 0s + extension-options: [] + feegrants: null + osmo: + type: cosmos + value: + key-directory: scripts/relayer/keys/osmo + key: testnet + chain-id: osmo + rpc-addr: http://localhost:26677 + account-prefix: osmo + keyring-backend: test + gas-adjustment: 1.2 + gas-prices: 0.005uosmo + min-gas-amount: 200000 + max-gas-amount: 0 + debug: false + timeout: 20s + block-timeout: "" + output-format: json + sign-mode: direct + extra-codecs: [] + coin-type: 118 + signing-algorithm: "" + broadcast-mode: batch + min-loop-duration: 0s + extension-options: [] + feegrants: null +paths: {} diff --git a/scripts/mesh/testibc/config_osmosis_testnet.yaml b/scripts/mesh/testibc/config_osmosis_testnet.yaml new file mode 100644 index 00000000..851acf32 --- /dev/null +++ b/scripts/mesh/testibc/config_osmosis_testnet.yaml @@ -0,0 +1,57 @@ +global: + api-listen-addr: :5184 + timeout: 10s + memo: "" + light-cache-size: 20 +chains: + consumer: + type: cosmos + value: + key-directory: scripts/relayer/keys/chain-1 + key: key1 + chain-id: chain-1 + rpc-addr: http://localhost:26657 + account-prefix: mesh + keyring-backend: test + gas-adjustment: 1.2 + gas-prices: 0.01stake + min-gas-amount: 1000000 + max-gas-amount: 0 + debug: false + timeout: 20s + block-timeout: "" + output-format: json + sign-mode: direct + extra-codecs: [] + coin-type: 118 + signing-algorithm: "" + broadcast-mode: batch + min-loop-duration: 0s + extension-options: [] + feegrants: null + osmo: + type: cosmos + value: + key-directory: scripts/relayer/keys/osmo-test-5 + key: testnet + chain-id: osmo-test-5 + rpc-addr: https://rpc.testnet.osmosis.zone:443 + account-prefix: osmo + keyring-backend: test + gas-adjustment: 1.2 + gas-prices: 0.005uosmo + min-gas-amount: 200000 + max-gas-amount: 0 + debug: false + timeout: 20s + block-timeout: "" + output-format: json + sign-mode: direct + extra-codecs: [] + coin-type: 118 + signing-algorithm: "" + broadcast-mode: batch + min-loop-duration: 0s + extension-options: [] + feegrants: null +paths: {} diff --git a/scripts/mesh/testibc/osmosis.sh b/scripts/mesh/testibc/osmosis.sh new file mode 100644 index 00000000..ba0a7352 --- /dev/null +++ b/scripts/mesh/testibc/osmosis.sh @@ -0,0 +1,84 @@ +set -xeu + +killall osmosisd || true +sleep 3 +rm -rf $HOME/.osmosisd +home=$HOME/.osmosisd +chainid=osmo + +osmosisd init localnet --chain-id $chainid --home $home + +# Create accounts +osmosisd keys add val1 --keyring-backend test --home $home +osmosisd keys add test1 --keyring-backend test --home $home + +cat $home/config/genesis.json | jq '.app_state["staking"]["params"]["bond_denom"]="uosmo"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +val1=$(osmosisd keys show val1 --keyring-backend test --home=$home -a) +test1=$(osmosisd keys show test1 --keyring-backend test --home=$home -a) +osmosisd add-genesis-account $val1 1000000000000uosmo,10000000000000000000stake --keyring-backend test --home=$home +osmosisd add-genesis-account $test1 1000000000uosmo --keyring-backend test --home=$home + +cat $home/config/genesis.json | jq '.app_state["gov"]["params"]["min_deposit"][0]["denom"]="uosmo"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["gov"]["params"]["voting_period"]="40s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["gov"]["params"]["expedited_voting_period"]="30s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["interchainquery"]["params"]["allow_queries"]=["/osmosis.twap.v1beta1.Query/ArithmeticTwapToNow"]' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +# update staking genesis +cat $home/config/genesis.json | jq '.app_state["staking"]["params"]["unbonding_time"]="240s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +# update crisis variable to uosmo +cat $home/config/genesis.json | jq '.app_state["crisis"]["constant_fee"]["denom"]="uosmo"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + + +# update epochs genesis +cat $home/config/genesis.json | jq '.app_state["epochs"]["epochs"][1]["duration"]="60s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +# update poolincentives genesis +cat $home/config/genesis.json | jq '.app_state["poolincentives"]["lockable_durations"][0]="120s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["poolincentives"]["lockable_durations"][1]="180s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["poolincentives"]["lockable_durations"][2]="240s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["poolincentives"]["params"]["minted_denom"]="uosmo"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +# update incentives genesis +cat $home/config/genesis.json | jq '.app_state["incentives"]["lockable_durations"][0]="1s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["incentives"]["lockable_durations"][1]="120s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["incentives"]["lockable_durations"][2]="180s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["incentives"]["lockable_durations"][3]="240s"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["incentives"]["params"]["distr_epoch_identifier"]="day"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +# update mint genesis +cat $home/config/genesis.json | jq '.app_state["mint"]["params"]["mint_denom"]="uosmo"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json +cat $home/config/genesis.json | jq '.app_state["mint"]["params"]["epoch_identifier"]="day"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +# update gamm genesis +cat $home/config/genesis.json | jq '.app_state["gamm"]["params"]["pool_creation_fee"][0]["denom"]="uosmo"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +# update cl genesis +cat $home/config/genesis.json | jq '.app_state["concentratedliquidity"]["params"]["is_permissionless_pool_creation_enabled"]=true' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +cat $home/config/genesis.json | jq '.app_state["txfees"]["basedenom"] = "uosmo"' > $home/config/tmp_genesis.json && mv $home/config/tmp_genesis.json $home/config/genesis.json + +osmosisd gentx val1 500000000000uosmo --keyring-backend test --chain-id $chainid --home=$home + +osmosisd collect-gentxs --home=$home + +VALIDATOR_APP_TOML=$home/config/app.toml + +sed -i -E 's|tcp://localhost:1317|tcp://localhost:1337|g' $VALIDATOR_APP_TOML +sed -i -E 's|localhost:9090|localhost:9290|g' $VALIDATOR_APP_TOML +sed -i -E 's|localhost:9091|localhost:9291|g' $VALIDATOR_APP_TOML +sed -i -E 's|tcp://0.0.0.0:10337|tcp://0.0.0.0:12337|g' $VALIDATOR_APP_TOML + +VALIDATOR_CONFIG=$home/config/config.toml +sed -i -E 's|tcp://127.0.0.1:26658|tcp://127.0.0.1:26678|g' $VALIDATOR_CONFIG +sed -i -E 's|tcp://127.0.0.1:26657|tcp://127.0.0.1:26677|g' $VALIDATOR_CONFIG +sed -i -E 's|tcp://0.0.0.0:26656|tcp://0.0.0.0:26676|g' $VALIDATOR_CONFIG +sed -i -E 's|allow_duplicate_ip = false|allow_duplicate_ip = true|g' $VALIDATOR_CONFIG + +screen -S osmosis -t osmosis -d -m osmosisd start --home=$home + +sleep 10 +osmosisd tx gamm create-pool --pool-file ./scripts/mesh/testibc/pool.json --from val1 --keyring-backend test --node http://localhost:26677 --chain-id osmo --fees 10000uosmo -y --gas auto --gas-adjustment 1.5 +sleep 7 +osmosisd q gamm num-pools --node http://localhost:26677 diff --git a/scripts/mesh/testibc/pool.json b/scripts/mesh/testibc/pool.json new file mode 100644 index 00000000..c7fc46fe --- /dev/null +++ b/scripts/mesh/testibc/pool.json @@ -0,0 +1,7 @@ +{ + "weights": "10uosmo,2stake", + "initial-deposit": "1000000uosmo,200000stake", + "swap-fee": "0.01", + "exit-fee": "0", + "future-governor": "" +} \ No newline at end of file diff --git a/scripts/mesh/testibc/rly.sh b/scripts/mesh/testibc/rly.sh index 5ee649a5..4a98b673 100755 --- a/scripts/mesh/testibc/rly.sh +++ b/scripts/mesh/testibc/rly.sh @@ -33,6 +33,5 @@ rly tx channel demo --src-port wasm.$converter --dst-port wasm.$ext_staking --or sleep 5 -echo "abcxyz" -# screen -S relayer -t relayer -d -m rly start demo +screen -S relayer -t relayer -d -m rly start demo sleep 5 \ No newline at end of file diff --git a/scripts/mesh/testibc/rly_band.sh b/scripts/mesh/testibc/rly_band.sh index ecdbd12a..b31c77de 100755 --- a/scripts/mesh/testibc/rly_band.sh +++ b/scripts/mesh/testibc/rly_band.sh @@ -53,6 +53,7 @@ init_band_price_feed=$(cat < /dev/null && shellcheck "$0" echo "DEV-only: copy from local built instead of downloading" -for contract in mesh_external_staking mesh_converter mesh_native_staking mesh_native_staking_proxy mesh_osmosis_price_provider mesh_remote_price_feed mesh_simple_price_feed \ +for contract in mesh_external_staking mesh_converter mesh_native_staking mesh_native_staking_proxy mesh_band_price_feed mesh_osmosis_price_feed mesh_simple_price_feed \ mesh_vault mesh_virtual_staking ; do cp -f ../../../mesh-security/artifacts/${contract}-aarch64.wasm . gzip -fk ${contract}-aarch64.wasm diff --git a/tests/testdata/crosschain_registry.wasm b/tests/testdata/crosschain_registry.wasm new file mode 100644 index 00000000..cb6a87b2 Binary files /dev/null and b/tests/testdata/crosschain_registry.wasm differ diff --git a/tests/testdata/mesh_band_price_feed.wasm.gz b/tests/testdata/mesh_band_price_feed.wasm.gz index 357ec578..2fcbbe12 100644 Binary files a/tests/testdata/mesh_band_price_feed.wasm.gz and b/tests/testdata/mesh_band_price_feed.wasm.gz differ diff --git a/tests/testdata/mesh_converter.wasm.gz b/tests/testdata/mesh_converter.wasm.gz index 85925eaf..c92116b6 100644 Binary files a/tests/testdata/mesh_converter.wasm.gz and b/tests/testdata/mesh_converter.wasm.gz differ diff --git a/tests/testdata/mesh_external_staking.wasm.gz b/tests/testdata/mesh_external_staking.wasm.gz index 292a1bc6..6e460d93 100644 Binary files a/tests/testdata/mesh_external_staking.wasm.gz and b/tests/testdata/mesh_external_staking.wasm.gz differ diff --git a/tests/testdata/mesh_native_staking.wasm.gz b/tests/testdata/mesh_native_staking.wasm.gz index 4ad4a956..9459baa8 100644 Binary files a/tests/testdata/mesh_native_staking.wasm.gz and b/tests/testdata/mesh_native_staking.wasm.gz differ diff --git a/tests/testdata/mesh_native_staking_proxy.wasm.gz b/tests/testdata/mesh_native_staking_proxy.wasm.gz index 4a272fcd..855a9501 100644 Binary files a/tests/testdata/mesh_native_staking_proxy.wasm.gz and b/tests/testdata/mesh_native_staking_proxy.wasm.gz differ diff --git a/tests/testdata/mesh_osmosis_price_feed.wasm.gz b/tests/testdata/mesh_osmosis_price_feed.wasm.gz index 2250359b..59e2684e 100644 Binary files a/tests/testdata/mesh_osmosis_price_feed.wasm.gz and b/tests/testdata/mesh_osmosis_price_feed.wasm.gz differ diff --git a/tests/testdata/mesh_osmosis_price_provider.wasm.gz b/tests/testdata/mesh_osmosis_price_provider.wasm.gz deleted file mode 100644 index cb369462..00000000 Binary files a/tests/testdata/mesh_osmosis_price_provider.wasm.gz and /dev/null differ diff --git a/tests/testdata/mesh_remote_price_feed.wasm.gz b/tests/testdata/mesh_remote_price_feed.wasm.gz deleted file mode 100644 index 3dd51fda..00000000 Binary files a/tests/testdata/mesh_remote_price_feed.wasm.gz and /dev/null differ diff --git a/tests/testdata/mesh_simple_price_feed.wasm.gz b/tests/testdata/mesh_simple_price_feed.wasm.gz index 6f99efaa..f9d75ebc 100644 Binary files a/tests/testdata/mesh_simple_price_feed.wasm.gz and b/tests/testdata/mesh_simple_price_feed.wasm.gz differ diff --git a/tests/testdata/mesh_vault.wasm.gz b/tests/testdata/mesh_vault.wasm.gz index 2a6e5725..8303570b 100644 Binary files a/tests/testdata/mesh_vault.wasm.gz and b/tests/testdata/mesh_vault.wasm.gz differ diff --git a/tests/testdata/mesh_virtual_staking.wasm.gz b/tests/testdata/mesh_virtual_staking.wasm.gz index 0bc19308..4e17c3f2 100644 Binary files a/tests/testdata/mesh_virtual_staking.wasm.gz and b/tests/testdata/mesh_virtual_staking.wasm.gz differ diff --git a/tests/testdata/version.txt b/tests/testdata/version.txt index 66a6ad6a..10142f3f 100644 --- a/tests/testdata/version.txt +++ b/tests/testdata/version.txt @@ -1 +1 @@ -da560f398b59d3a7430efbc1e71cbb0bcf62ad7a +44c6e65b581a08b5994a86792978f34ce9c51d5d diff --git a/x/go.mod b/x/go.mod index 2d1705a0..92a9e45f 100644 --- a/x/go.mod +++ b/x/go.mod @@ -37,7 +37,6 @@ require ( github.com/cometbft/cometbft v0.37.2 github.com/cometbft/cometbft-db v0.8.0 google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 - sigs.k8s.io/yaml v1.3.0 ) require ( @@ -184,6 +183,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect nhooyr.io/websocket v1.8.6 // indirect pgregory.net/rapid v0.5.5 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) replace ( diff --git a/x/meshsecurity/client/cli/gov_tx.go b/x/meshsecurity/client/cli/gov_tx.go index 22186946..2c660ee5 100644 --- a/x/meshsecurity/client/cli/gov_tx.go +++ b/x/meshsecurity/client/cli/gov_tx.go @@ -33,6 +33,7 @@ func SubmitProposalCmd() *cobra.Command { } cmd.AddCommand( ProposalSetVirtualStakingMaxCapCmd(), + ProposalSetPriceFeedContractCmd(), ) return cmd } @@ -86,6 +87,55 @@ $ %s tx meshsecurity submit-proposal set-virtual-staking-max-cap %s1l94ptufswr6v return cmd } +func ProposalSetPriceFeedContractCmd() *cobra.Command { + bech32Prefix := sdk.GetConfig().GetBech32AccountAddrPrefix() + cmd := &cobra.Command{ + Use: "set-price-feed [contract_addr_bech32] --title [text] --summary [text] --authority [address]", + Short: "Submit a set virtual staking max cap proposal", + Args: cobra.ExactArgs(1), + Long: strings.TrimSpace( + fmt.Sprintf(`Submit a proposal to set price feed contract to chain. + +Example: +$ %s tx meshsecurity submit-proposal set-price-feed %s1l94ptufswr6v7qntax4m7nvn3jgf6k4gn2rknq --title "a title" --summary "a summary" --authority %s +`, version.AppName, bech32Prefix, DefaultGovAuthority.String())), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, proposalTitle, summary, metadata, deposit, err := getProposalInfo(cmd) + if err != nil { + return err + } + authority, err := cmd.Flags().GetString(flagAuthority) + if err != nil { + return fmt.Errorf("authority: %s", err) + } + + if len(authority) == 0 { + return errors.New("authority address is required") + } + + src, err := parseSetPriceFeedContractArgs(args, authority) + if err != nil { + return err + } + + proposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&src}, deposit, clientCtx.GetFromAddress().String(), metadata, proposalTitle, summary) + if err != nil { + return err + } + if err = proposalMsg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), proposalMsg) + }, + SilenceUsage: true, + } + + // proposal flags + addCommonProposalFlags(cmd) + return cmd +} + func parseSetVirtualStakingMaxCapArgs(args []string, authority string) (types.MsgSetVirtualStakingMaxCap, error) { maxCap, err := sdk.ParseCoinNormalized(args[1]) if err != nil { @@ -100,6 +150,14 @@ func parseSetVirtualStakingMaxCapArgs(args []string, authority string) (types.Ms return msg, nil } +func parseSetPriceFeedContractArgs(args []string, authority string) (types.MsgSetPriceFeedContract, error) { + msg := types.MsgSetPriceFeedContract{ + Authority: authority, + Contract: args[0], + } + return msg, nil +} + func addCommonProposalFlags(cmd *cobra.Command) { flags.AddTxFlagsToCmd(cmd) cmd.Flags().String(cli.FlagTitle, "", "Title of proposal") diff --git a/x/meshsecurity/keeper/msg_server.go b/x/meshsecurity/keeper/msg_server.go index 1d81decb..412b5a12 100644 --- a/x/meshsecurity/keeper/msg_server.go +++ b/x/meshsecurity/keeper/msg_server.go @@ -42,10 +42,35 @@ func (m msgServer) SetVirtualStakingMaxCap(goCtx context.Context, req *types.Msg return nil, err } if !m.k.HasScheduledTask(ctx, types.SchedulerTaskHandleEpoch, acc, true) { - if err := m.k.ScheduleRegularRebalanceTask(ctx, acc); err != nil { + if err := m.k.ScheduleRegularHandleEpochTask(ctx, acc); err != nil { return nil, errorsmod.Wrap(err, "schedule regular rebalance task") } return &types.MsgSetVirtualStakingMaxCapResponse{}, nil } return &types.MsgSetVirtualStakingMaxCapResponse{}, nil } + +// SetPriceFeedContract sets the price feed contract to the chain to trigger handle epoch task +func (m msgServer) SetPriceFeedContract(goCtx context.Context, req *types.MsgSetPriceFeedContract) (*types.MsgSetPriceFeedContractResponse, error) { + if err := req.ValidateBasic(); err != nil { + return nil, err + } + + if authority := m.k.GetAuthority(); authority != req.Authority { + return nil, govtypes.ErrInvalidSigner.Wrapf("invalid authority; expected %s, got %s", authority, req.Authority) + } + + acc, err := sdk.AccAddressFromBech32(req.Contract) + if err != nil { + return nil, errorsmod.Wrap(err, "contract") + } + ctx := sdk.UnwrapSDKContext(goCtx) + if !m.k.HasScheduledTask(ctx, types.SchedulerTaskHandleEpoch, acc, true) { + if err := m.k.ScheduleRegularHandleEpochTask(ctx, acc); err != nil { + return nil, errorsmod.Wrap(err, "schedule regular rebalance task") + } + return &types.MsgSetPriceFeedContractResponse{}, nil + } else { + return nil, types.ErrDuplicate + } +} diff --git a/x/meshsecurity/keeper/msg_server_test.go b/x/meshsecurity/keeper/msg_server_test.go index 74bd70e8..c56107d4 100644 --- a/x/meshsecurity/keeper/msg_server_test.go +++ b/x/meshsecurity/keeper/msg_server_test.go @@ -89,3 +89,76 @@ func TestSetVirtualStakingMaxCap(t *testing.T) { }) } } + +func TestSetPriceFeedContract(t *testing.T) { + pCtx, keepers := CreateDefaultTestInput(t) + k := keepers.MeshKeeper + myContract := sdk.AccAddress(rand.Bytes(32)) + denom := keepers.StakingKeeper.BondDenom(pCtx) + myAmount := sdk.NewInt64Coin(denom, 123) + + k.wasm = MockWasmKeeper{HasContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) bool { + return contractAddress.Equals(myContract) + }} + m := NewMsgServer(k) + + specs := map[string]struct { + src types.MsgSetPriceFeedContract + setup func(ctx sdk.Context) + expErr bool + expLimit sdk.Coin + expSchedule func(t *testing.T, ctx sdk.Context) + }{ + "limit stored with scheduler for existing contract": { + setup: func(ctx sdk.Context) {}, + src: types.MsgSetPriceFeedContract{ + Authority: k.GetAuthority(), + Contract: myContract.String(), + }, + expLimit: myAmount, + expSchedule: func(t *testing.T, ctx sdk.Context) { + assert.True(t, k.HasScheduledTask(ctx, types.SchedulerTaskHandleEpoch, myContract, true)) + }, + }, + "fails for non existing contract": { + setup: func(ctx sdk.Context) {}, + src: types.MsgSetPriceFeedContract{ + Authority: k.GetAuthority(), + Contract: sdk.AccAddress(rand.Bytes(32)).String(), + }, + expErr: true, + }, + "unauthorized rejected": { + setup: func(ctx sdk.Context) {}, + src: types.MsgSetPriceFeedContract{ + Authority: myContract.String(), + Contract: myContract.String(), + }, + expErr: true, + }, + "invalid data rejected": { + setup: func(ctx sdk.Context) {}, + src: types.MsgSetPriceFeedContract{}, + expErr: true, + }, + } + for name, spec := range specs { + t.Run(name, func(t *testing.T) { + ctx, _ := pCtx.CacheContext() + spec.setup(ctx) + + // when + gotRsp, gotErr := m.SetPriceFeedContract(sdk.WrapSDKContext(ctx), &spec.src) + + // then + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + assert.NotNil(t, gotRsp) + // and scheduled + spec.expSchedule(t, ctx) + }) + } +} diff --git a/x/meshsecurity/keeper/scheduler.go b/x/meshsecurity/keeper/scheduler.go index 194058c2..6fe4ec6d 100644 --- a/x/meshsecurity/keeper/scheduler.go +++ b/x/meshsecurity/keeper/scheduler.go @@ -13,8 +13,8 @@ import ( "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types" ) -// ScheduleRegularRebalanceTask schedule a rebalance task for the given virtual staking contract using params defined epoch length -func (k Keeper) ScheduleRegularRebalanceTask(ctx sdk.Context, contract sdk.AccAddress) error { +// ScheduleRegularHandleEpochTask schedule a handle epoch task for the given virtual staking contract using params defined epoch length +func (k Keeper) ScheduleRegularHandleEpochTask(ctx sdk.Context, contract sdk.AccAddress) error { if !k.wasm.HasContractInfo(ctx, contract) { return types.ErrUnknown.Wrapf("contract: %s", contract.String()) }