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/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 dd860707..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_osmosis_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/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 8a550046..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 56865646..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 ed30a596..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 0edf24eb..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 b1c9d32c..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_simple_price_feed.wasm.gz b/tests/testdata/mesh_simple_price_feed.wasm.gz
index c2d9af91..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 607a76ab..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 f37871cd..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 7f1d16f4..10142f3f 100644
--- a/tests/testdata/version.txt
+++ b/tests/testdata/version.txt
@@ -1 +1 @@
-1c1f84d56570fda573ba3aa56263e2e01be12c57
+44c6e65b581a08b5994a86792978f34ce9c51d5d
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())
}