diff --git a/docs/proto/proto-docs.md b/docs/proto/proto-docs.md
index b5fc4f31..dcd66663 100644
--- a/docs/proto/proto-docs.md
+++ b/docs/proto/proto-docs.md
@@ -5,6 +5,7 @@
## Table of Contents
- [osmosis/meshsecurity/v1beta1/meshsecurity.proto](#osmosis/meshsecurity/v1beta1/meshsecurity.proto)
+ - [Delegation](#osmosis.meshsecurity.v1beta1.Delegation)
- [Params](#osmosis.meshsecurity.v1beta1.Params)
- [VirtualStakingMaxCapInfo](#osmosis.meshsecurity.v1beta1.VirtualStakingMaxCapInfo)
@@ -41,6 +42,23 @@
+
+
+### Delegation
+Delegation represents the bond with tokens held by an account.
+
+
+| Field | Type | Label | Description |
+| ----- | ---- | ----- | ----------- |
+| `delegator_address` | [string](#string) | | delegator_address is the bech32-encoded address of the delegator. |
+| `validator_address` | [string](#string) | | validator_address is the bech32-encoded address of the validator. |
+| `amount` | [string](#string) | | amount define the delegation amount. |
+
+
+
+
+
+
### Params
diff --git a/note.json b/note.json
new file mode 100644
index 00000000..24d852c5
--- /dev/null
+++ b/note.json
@@ -0,0 +1,155 @@
+{
+ "stake": {
+ "delegator": "cosmos1ph3tq3s5afcg6z4c4mpd9kdklt9a8j7gw8sygn",
+ "validator": "cosmosvaloper1gtnfjqp6pgkdu6szu5rzk4h5z5d54fadcfsv90",
+ "stake": {
+ "denom": "stake",
+ "amount": "20000000"
+ },
+ "tx_id": 2
+ }
+}
+
+[
+ Execute {
+ contract_addr: "cosmos1qg5ega6dykkxc307y25pecuufrjkxkaggkkxh7nad0vhyhtuhw3s6ufdm4",
+ msg: {
+ "internal_unstake":{
+ "delegator":"cosmos1whqnmupfwm3gfmvjegy0j69z42mfngmg2q8emj",
+ "validator":"cosmosvaloper1jgaec5l7glsy2l37n25kmqj7p9hrfzsh43df3u",
+ "amount":{"denom":"stake","amount":"22500000"}}
+ },
+ funds: []
+ },
+ Execute {
+ contract_addr: "cosmos1qg5ega6dykkxc307y25pecuufrjkxkaggkkxh7nad0vhyhtuhw3s6ufdm4",
+ msg: {
+ "internal_unstake":{
+ "delegator":"cosmos1whqnmupfwm3gfmvjegy0j69z42mfngmg2q8emj",
+ "validator":"cosmosvaloper1mt78w786v2qz24skefvv6x3xulq4495egj33yc",
+ "amount":{"denom":"stake","amount":"9000000"}}}, funds: [] }]
+
+panic:
+failed to execute scheduled task for contract
+"cosmos1xr3rq8yvd7qplsw5yx90ftsr2zdhg4e9z60h5duusgxpv72hud3s493rn8":
+execution: {Loading CosmWasm module: execute}: panic [recovered]
+
+routes: map[
+ /cosmos.auth.v1beta1.MsgUpdateParams:0x10378c850
+ /cosmos.authz.v1beta1.MsgExec:0x10378c850
+ /cosmos.authz.v1beta1.MsgGrant:0x10378c850
+ /cosmos.authz.v1beta1.MsgRevoke:0x10378c850
+ /cosmos.bank.v1beta1.MsgMultiSend:0x10378c850
+ /cosmos.bank.v1beta1.MsgSend:0x10378c850
+ /cosmos.bank.v1beta1.MsgSetSendEnabled:0x10378c850
+ /cosmos.bank.v1beta1.MsgUpdateParams:0x10378c850
+ /cosmos.consensus.v1.MsgUpdateParams:0x10378c850
+ /cosmos.crisis.v1beta1.MsgUpdateParams:0x10378c850
+ /cosmos.crisis.v1beta1.MsgVerifyInvariant:0x10378c850
+ /cosmos.distribution.v1beta1.MsgCommunityPoolSpend:0x10378c850
+ /cosmos.distribution.v1beta1.MsgFundCommunityPool:0x10378c850
+ /cosmos.distribution.v1beta1.MsgSetWithdrawAddress:0x10378c850
+ /cosmos.distribution.v1beta1.MsgUpdateParams:0x10378c850
+ /cosmos.distribution.v1beta1.MsgWithdrawDelegatorReward:0x10378c850 /
+ cosmos.distribution.v1beta1.MsgWithdrawValidatorCommission:0x10378c850
+ /cosmos.evidence.v1beta1.MsgSubmitEvidence:0x10378c850
+ /cosmos.feegrant.v1beta1.MsgGrantAllowance:0x10378c8
+50 /cosmos.feegrant.v1beta1.MsgRevokeAllowance:0x10378c850
+ /cosmos.gov.v1.MsgDeposit:0x10378c850
+ /cosmos.gov.v1.MsgExecLegacyContent:0x10378c850
+ /cosmos.gov.v1.MsgSubmitProposal:0x10378c850
+ /cosmos.gov.v1.MsgUpdateParams:0x10378c850
+ /cosmos.gov.v1.MsgVote:0x10378c850
+ /cosmos.gov.v1.MsgVoteWeighted:0x10378c850
+ /cosmos.gov.v1beta1.MsgDeposit:0x10378c850
+ /cosmos.gov.v1beta1.MsgSubmitProposal:0x10378c850
+ /cosmos.gov.v1beta1.MsgVote:0x10378c850
+ /cosmos.gov.v1beta1.MsgVoteWeighted:0x10378c850
+ /cosmos.group.v1.MsgCreateGroup:0x10378c850
+ /cosmos.group.v1.MsgCreateGroupPolicy:0x10378c850
+ /cosmos.group.v1.MsgCreateGroupWithPolicy:0x10378c850
+ /cosmos.group.v1.MsgExec:0x10378c850
+ /cosmos.group.v1.MsgLeaveGroup:0x10378c850
+ /cosmos.group.v1.MsgSubmitProposal:0x10378c850
+ /cosmos.group.v1.MsgUpdateGroupAdmin:0x10378c850
+ /cosmos.group.v1.MsgUpdateGroupMembers:0x10378c850
+ /cosmos.group.v1.MsgUpdateGroupMetadata:0x10378c850
+ /cosmos.group.v1.MsgUpdateGroupPolicyAdmin:0x10378c850
+ /cosmos.group.v1.MsgUpdateGroupPolicyDecisionPolicy:0x10378c850
+ /cosmos.group.v1.MsgUpdateGroupPolicyMetadata:0x10378c850
+ /cosmos.group.v1.MsgVote:0x10378c850
+ /cosmos.group.v1.MsgWithdrawProposal:0x10378c850
+ /cosmos.mint.v1beta1.MsgUpdateParams:0x10378c850
+ /cosmos.nft.v1beta1.MsgSend:0x10378c850
+ /cosmos.slashing.v1beta1.MsgUnjail:0x10378c850
+ /cosmos.slashing.v1beta1.MsgUpdateParams:0x10378c850
+ /cosmos.staking.v1beta1.MsgBeginRedelegate:0x10378c850
+ /cosmos.staking.v1beta1.MsgCancelUnbondingDelegation:0x10378c850
+ /cosmos.staking.v1beta1.MsgCreateValidator:0x10378c850
+ /cosmos.staking.v1beta1.MsgDelegate:0x10378c850
+ /cosmos.staking.v1beta1.MsgEditValidator:0x10378c850
+ /cosmos.staking.v1beta1.MsgUndelegate:0x10378c850
+ /cosmos.staking.v1beta1.MsgUpdateParams:0x10378c850
+ /cosmos.upgrade.v1beta1.MsgCancelUpgrade:0x10378c850
+ /cosmos.upgrade.v1beta1.MsgSoftwareUpgrade:0x10378c850
+ /cosmos.vesting.v1beta1.MsgCreatePeriodicVestingAccount:0x10378c850
+ /cosmos.vesting.v1beta1.MsgCreatePermanentLockedAccount:0x10378c850
+ /cosmos.vesting.v1beta1.MsgCreateVestingAccount:0x10378c850
+ /cosmwasm.wasm.v1.MsgAddCodeUploadParamsAddresses:0x10378c850
+ /cosmwasm.wasm.v1.MsgClearAdmin:0x10378c850
+ /cosmwasm.wasm.v1.MsgExecuteContract:0x10378c850
+ /cosmwasm.wasm.v1.MsgInstantiateContract:0x10378c850
+ /cosmwasm.wasm.v1.MsgInstantiateContract2:0x10378c850
+ /cosmwasm.wasm.v1.MsgMigrateContract:0x10378c850
+ /cosmwasm.wasm.v1.MsgPinCodes:0x10378c850
+ /cosmwasm.wasm.v1.MsgRemoveCodeUploadParamsAddresses:0x10378c850
+ /cosmwasm.wasm.v1.MsgStoreAndInstantiateContract:0x10378c850
+ /cosmwasm.wasm.v1.MsgStoreAndMigrateContract:0x10378c850
+ /cosmwasm.wasm.v1.MsgStoreCode:0x10378c850
+ /cosmwasm.wasm.v1.MsgSudoContract:0x10378c850
+ /cosmwasm.wasm.v1.MsgUnpinCodes:0x10378c850
+ /cosmwasm.wasm.v1.MsgUpdateAdmin:0x10378c850
+ /cosmwasm.wasm.v1.MsgUpdateContractLabel:0x10378c850
+ /cosmwasm.wasm.v1.MsgUpdateInstantiateConfig:0x10378c850
+ /cosmwasm.wasm.v1.MsgUpdateParams:0x10378c850
+ /ibc.applications.fee.v1.MsgPayPacketFee:0x10378c850
+ /ibc.applications.fee.v1.MsgPayPacketFeeAsync:0x10378c850
+ /ibc.applications.fee.v1.MsgRegisterCounterpartyPayee:0x10378c850
+ /ibc.applications.fee.v1.MsgRegisterPayee:0x10378c850
+ /ibc.applications.interchain_accounts.controller.v1.MsgRegisterInterchainAccount:0x10378c850
+ /ibc.applications.interchain_accounts.controller.v1.MsgSendTx:0x10378c850
+ /ibc.applications.transfer.v1.MsgTransfer:0x10378c850
+ /ibc.core.channel.v1.MsgAcknowledgement:0x10378c850
+ /ibc.core.channel.v1.MsgChannelCloseConfirm:0x10378c850
+ /ibc.core.channel.v1.MsgChannelCloseInit:0x10378c850
+ /ibc.core.channel.v1.MsgChannelOpenAck:0x10378c850
+ /ibc.core.channel.v1.MsgChannelOpenConfirm:0x10378c850
+ /ibc.core.channel.v1.MsgChannelOpenInit:0x10378c850
+ /ibc.core.channel.v1.MsgChannelOpenTry:0x10378c850
+ /ibc.core.channel.v1.MsgRecvPacket:0x10378c850
+ /ibc.core.channel.v1.MsgTimeout:0x10378c850
+ /ibc.core.channel.v1.MsgTimeoutOnClose:0x10378c850
+ /ibc.core.client.v1.MsgCreateClient:0x10378c850
+ /ibc.core.client.v1.MsgSubmitMisbehaviour:0x10378c850
+ /ibc.core.client.v1.MsgUpdateClient:0x10378c850
+ /ibc.core.client.v1.MsgUpgradeClient:0x10378c850
+ /ibc.core.connection.v1.MsgConnectionOpenAck:0x10378c850
+ /ibc.core.connection.v1.MsgConnectionOpenConfirm:0x10378c850
+ /ibc.core.connection.v1.MsgConnectionOpenInit:0x10378c850
+ /ibc.core.connection.v1.MsgConnectionOpenTry:0x10378c850
+ /osmosis.meshsecurity.v1beta1.MsgSetVirtualStakingMaxCap:0x10378c850]
+
+
+ Cannot unbond 49999999 tokens from validator cosmosvaloper1fhm5lj9wcvxwdxmgtz36mnjuhwtk7ly93c3rqg, not enough staked
+
+ data: {
+ "internal_unstake":{
+ "delegator":"cosmos1yw0saxm7nkwl0e8r3kqpar2a0vusdzcaku8mys",
+ "validator":"cosmosvaloper1szy96jnddalx7s686e4ylres02uv6a5dyxj82c",
+ "normalize_amount":{"denom":"stake","amount":"9000000"},
+ "inverted_amount":{"denom":"stake","amount":"19999999"}
+ }
+ }
+
+ failed to execute message; message index: 0: acknowledge packet callback failed: on ack: submessages: Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError:
+ Aborted: panicked at contracts/consumer/virtual-staking/src/contract.rs:519:9:
\ No newline at end of file
diff --git a/proto/osmosis/meshsecurity/v1beta1/meshsecurity.proto b/proto/osmosis/meshsecurity/v1beta1/meshsecurity.proto
index 02cfc51e..0d6504ce 100644
--- a/proto/osmosis/meshsecurity/v1beta1/meshsecurity.proto
+++ b/proto/osmosis/meshsecurity/v1beta1/meshsecurity.proto
@@ -22,6 +22,21 @@ message VirtualStakingMaxCapInfo {
cosmos.base.v1beta1.Coin cap = 3 [ (gogoproto.nullable) = false ];
}
+// Delegation represents the bond with tokens held by an account.
+message Delegation {
+ option (gogoproto.equal) = false;
+
+ // delegator_address is the bech32-encoded address of the delegator.
+ string delegator_address = 1;
+ // validator_address is the bech32-encoded address of the validator.
+ string validator_address = 2;
+ // amount define the delegation amount.
+ string amount = 3 [
+ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
+ (gogoproto.nullable) = false
+ ];
+}
+
// Params defines the parameters for the x/meshsecurity module.
message Params {
option (amino.name) = "meshsecurity/Params";
diff --git a/tests/e2e/README.md b/tests/e2e/README.md
index ed722b52..3abfe82d 100644
--- a/tests/e2e/README.md
+++ b/tests/e2e/README.md
@@ -1,10 +1,9 @@
# End-To-End Tests
+
Multi-chain system tests that run against the demo app.
+Run them with:
-Run them with:
```shell
make test
-```
-
-
+```
diff --git a/tests/e2e/e2e.go b/tests/e2e/e2e.go
index a8d24ff9..0aca4a83 100644
--- a/tests/e2e/e2e.go
+++ b/tests/e2e/e2e.go
@@ -104,6 +104,7 @@ type example struct {
ProviderDenom string
ConsumerDenom string
MyProvChainActor string
+ MaxRetrieve uint16
}
func setupExampleChains(t *testing.T) example {
@@ -120,6 +121,7 @@ func setupExampleChains(t *testing.T) example {
ProviderDenom: sdk.DefaultBondDenom,
ConsumerDenom: sdk.DefaultBondDenom,
MyProvChainActor: provChain.SenderAccount.GetAddress().String(),
+ MaxRetrieve: 50,
}
}
@@ -128,7 +130,7 @@ func setupMeshSecurity(t *testing.T, x example) (*TestConsumerClient, ConsumerCo
// setup contracts on both chains
consumerCli := NewConsumerClient(t, x.ConsumerChain)
- consumerContracts := consumerCli.BootstrapContracts()
+ consumerContracts := consumerCli.BootstrapContracts(x)
converterPortID := wasmkeeper.PortIDForContract(consumerContracts.converter)
// add some fees so that we can distribute something
x.ConsumerChain.DefaultMsgFees = sdk.NewCoins(sdk.NewCoin(x.ConsumerDenom, math.NewInt(1_000_000)))
diff --git a/tests/e2e/mvp_test.go b/tests/e2e/mvp_test.go
index 06981fe3..aa89b92c 100644
--- a/tests/e2e/mvp_test.go
+++ b/tests/e2e/mvp_test.go
@@ -36,7 +36,6 @@ func TestMVP(t *testing.T) {
// ...
x := setupExampleChains(t)
consumerCli, consumerContracts, providerCli := setupMeshSecurity(t, x)
-
// then the active set should be stored in the ext staking contract
// and contain all active validator addresses
qRsp := providerCli.QueryExtStaking(Query{"list_active_validators": {}})
diff --git a/tests/e2e/slashing_test.go b/tests/e2e/slashing_test.go
index f9abdbab..31bcba4b 100644
--- a/tests/e2e/slashing_test.go
+++ b/tests/e2e/slashing_test.go
@@ -1,13 +1,14 @@
package e2e
import (
- "cosmossdk.io/math"
"encoding/base64"
"fmt"
+ "testing"
+
+ "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "testing"
)
func TestSlashingScenario1(t *testing.T) {
@@ -17,7 +18,6 @@ func TestSlashingScenario1(t *testing.T) {
// - We use millions instead of unit tokens.
x := setupExampleChains(t)
consumerCli, _, providerCli := setupMeshSecurity(t, x)
-
// Provider chain
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
@@ -91,6 +91,7 @@ func TestSlashingScenario1(t *testing.T) {
// Assert that the validator's stake has been slashed
// and that the validator has been jailed
validator1, found = x.ConsumerApp.StakingKeeper.GetValidator(ctx, myExtValidator1)
+ require.True(t, found)
require.True(t, validator1.IsJailed())
require.Equal(t, validator1.GetTokens(), sdk.NewInt(41_400_000)) // 10% slash
@@ -117,7 +118,6 @@ func TestSlashingScenario2(t *testing.T) {
// - We use millions instead of unit tokens.
x := setupExampleChains(t)
consumerCli, _, providerCli := setupMeshSecurity(t, x)
-
// Provider chain
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
@@ -178,6 +178,7 @@ func TestSlashingScenario2(t *testing.T) {
// Assert that the validator's stake has been slashed
// and that the validator has been jailed
validator1, found = x.ConsumerApp.StakingKeeper.GetValidator(ctx, myExtValidator1)
+ require.True(t, found)
require.True(t, validator1.IsJailed())
require.Equal(t, validator1.GetTokens(), sdk.NewInt(81_900_000)) // 10% slash
@@ -204,7 +205,6 @@ func TestSlashingScenario3(t *testing.T) {
// - We use millions instead of unit tokens.
x := setupExampleChains(t)
consumerCli, _, providerCli := setupMeshSecurity(t, x)
-
// Provider chain
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
@@ -265,6 +265,7 @@ func TestSlashingScenario3(t *testing.T) {
// Assert that the validator's stake has been slashed
// and that the validator has been jailed
validator1, found = x.ConsumerApp.StakingKeeper.GetValidator(ctx, myExtValidator1)
+ require.True(t, found)
require.True(t, validator1.IsJailed())
require.Equal(t, validator1.GetTokens(), sdk.NewInt(61_700_000)) // 10% slash (plus 50_000 rounding)
diff --git a/tests/e2e/test_client.go b/tests/e2e/test_client.go
index 56045e91..cf3d7e26 100644
--- a/tests/e2e/test_client.go
+++ b/tests/e2e/test_client.go
@@ -1,6 +1,7 @@
package e2e
import (
+ "context"
"encoding/base64"
"fmt"
"strconv"
@@ -20,9 +21,11 @@ import (
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
+ govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/osmosis-labs/mesh-security-sdk/demo/app"
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity"
+ "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/keeper"
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types"
)
@@ -353,7 +356,7 @@ type ConsumerContract struct {
converter sdk.AccAddress
}
-func (p *TestConsumerClient) BootstrapContracts() ConsumerContract {
+func (p *TestConsumerClient) BootstrapContracts(x example) ConsumerContract {
// modify end-blocker to fail fast in tests
msModule := p.app.ModuleManager.Modules[types.ModuleName].(*meshsecurity.AppModule)
msModule.SetAsyncTaskRspHandler(meshsecurity.PanicOnErrorExecutionResponseHandler())
@@ -370,8 +373,8 @@ func (p *TestConsumerClient) BootstrapContracts() ConsumerContract {
virtStakeCodeID := p.chain.StoreCodeFile(buildPathToWasm("mesh_virtual_staking.wasm")).CodeID
// instantiate converter
codeID = p.chain.StoreCodeFile(buildPathToWasm("mesh_converter.wasm")).CodeID
- initMsg = []byte(fmt.Sprintf(`{"price_feed": %q, "discount": %q, "remote_denom": %q,"virtual_staking_code_id": %d}`,
- priceFeedContract.String(), discount, remoteDenom, virtStakeCodeID))
+ initMsg = []byte(fmt.Sprintf(`{"price_feed": %q, "discount": %q, "remote_denom": %q,"virtual_staking_code_id": %d, "max_retrieve": %d}`,
+ priceFeedContract.String(), discount, remoteDenom, virtStakeCodeID, x.MaxRetrieve))
converterContract := InstantiateContract(p.t, p.chain, codeID, initMsg)
staking := Querier(p.t, p.chain)(converterContract.String(), Query{"config": {}})["virtual_staking"]
@@ -404,6 +407,15 @@ func (p *TestConsumerClient) ExecNewEpoch() {
}
}
+func (p *TestConsumerClient) ExecSetMaxCap(cap sdk.Coin) {
+ msgServer := keeper.NewMsgServer(p.app.MeshSecKeeper)
+ msgServer.SetVirtualStakingMaxCap(p.chain.GetContext(), &types.MsgSetVirtualStakingMaxCap{
+ Authority: authtypes.NewModuleAddress(govtypes.ModuleName).String(),
+ Contract: p.contracts.staking.String(),
+ MaxCap: cap,
+ })
+}
+
// MustEnableVirtualStaking add authority to mint/burn virtual tokens gov proposal
func (p *TestConsumerClient) MustEnableVirtualStaking(maxCap sdk.Coin) {
govProposal := &types.MsgSetVirtualStakingMaxCap{
@@ -423,7 +435,7 @@ func (p *TestConsumerClient) MustExecGovProposal(msg *types.MsgSetVirtualStaking
func (p *TestConsumerClient) QueryMaxCap() types.QueryVirtualStakingMaxCapLimitResponse {
q := baseapp.QueryServiceTestHelper{GRPCQueryRouter: p.app.GRPCQueryRouter(), Ctx: p.chain.GetContext()}
var rsp types.QueryVirtualStakingMaxCapLimitResponse
- err := q.Invoke(nil, "/osmosis.meshsecurity.v1beta1.Query/VirtualStakingMaxCapLimit", &types.QueryVirtualStakingMaxCapLimitRequest{Address: p.contracts.staking.String()}, &rsp)
+ err := q.Invoke(context.TODO(), "/osmosis.meshsecurity.v1beta1.Query/VirtualStakingMaxCapLimit", &types.QueryVirtualStakingMaxCapLimitRequest{Address: p.contracts.staking.String()}, &rsp)
require.NoError(p.t, err)
return rsp
}
diff --git a/tests/e2e/zero_max_cap_test.go b/tests/e2e/zero_max_cap_test.go
new file mode 100644
index 00000000..60d0d13a
--- /dev/null
+++ b/tests/e2e/zero_max_cap_test.go
@@ -0,0 +1,106 @@
+package e2e
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "cosmossdk.io/math"
+
+ sdk "github.com/cosmos/cosmos-sdk/types"
+)
+
+func TestZeroMaxCapScenario1(t *testing.T) {
+ // scenario:
+ // given a provider chain P and a consumer chain C
+ // some amount has been "cross stake" on chain C
+ // a proposal is created to change max cap to zero
+ // all delegations will be unstake in one epoch
+
+ x := setupExampleChains(t)
+ consumerCli, consumerContracts, providerCli := setupMeshSecurity(t, x)
+
+ // the active set should be stored in the ext staking contract
+ // and contain all active validator addresses
+ qRsp := providerCli.QueryExtStaking(Query{"list_active_validators": {}})
+ require.Len(t, qRsp["validators"], 4, qRsp)
+ for _, v := range x.ConsumerChain.Vals.Validators {
+ require.Contains(t, qRsp["validators"], sdk.ValAddress(v.Address).String())
+ }
+
+ // ----------------------------
+ // ensure nothing staked by the virtual staking contract yet
+ extValidator1 := sdk.ValAddress(x.ConsumerChain.Vals.Validators[1].Address)
+ extValidator1Addr := extValidator1.String()
+
+ extValidator2 := sdk.ValAddress(x.ConsumerChain.Vals.Validators[2].Address)
+ extValidator2Addr := extValidator2.String()
+
+ _, found := x.ConsumerApp.StakingKeeper.GetDelegation(x.ConsumerChain.GetContext(), consumerContracts.staking, extValidator1)
+ require.False(t, found)
+
+ // the max cap limit is persisted
+ rsp := consumerCli.QueryMaxCap()
+ assert.Equal(t, sdk.NewInt64Coin(x.ConsumerDenom, 1_000_000_000), rsp.Cap)
+
+ // provider chain
+ // ==============
+ // Deposit - A user deposits the vault denom to provide some collateral to their account
+ execMsg := fmt.Sprintf(`{"bond":{"amount":{"denom":"%s", "amount":"100000000"}}}`, x.ProviderDenom)
+ providerCli.MustExecVault(execMsg)
+
+ // then query contract state
+ assert.Equal(t, 100_000_000, providerCli.QueryVaultFreeBalance())
+
+ // Cross Stake
+ err := providerCli.ExecStakeRemote(extValidator1Addr, sdk.NewInt64Coin(x.ProviderDenom, 50_000_000))
+ require.NoError(t, err)
+
+ require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))
+ require.Equal(t, 50_000_000, providerCli.QueryVaultFreeBalance())
+
+ err = providerCli.ExecStakeRemote(extValidator2Addr, sdk.NewInt64Coin(x.ProviderDenom, 20_000_000))
+ require.NoError(t, err)
+
+ require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))
+ require.Equal(t, 30_000_000, providerCli.QueryVaultFreeBalance())
+
+ // consumer chain
+ // ====================
+ //
+ // then delegated amount is not updated before the epoch
+ consumerCli.assertTotalDelegated(math.ZeroInt()) // ensure nothing cross staked yet
+
+ // when an epoch ends, the delegation rebalance is triggered
+ consumerCli.ExecNewEpoch()
+
+ // then the total delegated amount is updated
+ consumerCli.assertTotalDelegated(math.NewInt(31_500_000)) // 70_000_000 /2 * (1 -0.1)
+
+ // and the delegated amount is updated for the validator
+ consumerCli.assertShare(extValidator1, math.LegacyMustNewDecFromStr("22.5")) // 50_000_000 /2 * (1 -0.1) / 1_000_000 # default sdk factor
+ consumerCli.assertShare(extValidator2, math.LegacyNewDec(9)) // 20_000_000 /2 * (1 -0.1) / 1_000_000 # default sdk factor
+
+ // Zero max cap
+ consumerCli.ExecSetMaxCap(sdk.NewInt64Coin(x.ConsumerDenom, 0))
+
+ // the max cap limit is persisted
+ rsp = consumerCli.QueryMaxCap()
+ assert.Equal(t, sdk.NewInt64Coin(x.ConsumerDenom, 0), rsp.Cap)
+
+ // when an epoch ends, the unstaking msgs is triggered
+ consumerCli.ExecNewEpoch()
+
+ // 2 internal unstake msg, 1 distribute batch msg
+ require.Len(t, x.IbcPath.EndpointA.Chain.PendingSendPackets, 3)
+ require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))
+
+ consumerCli.assertTotalDelegated(math.ZeroInt())
+
+ x.ProviderChain.NextBlock()
+ providerCli.MustExecExtStaking(`{"withdraw_unbonded":{}}`)
+ // When calculate inverted price, 50_000_000 will become 49_999_999, 20_000_000 will be 19_999_999
+ assert.Equal(t, 99_999_998, providerCli.QueryVaultFreeBalance())
+}
diff --git a/tests/starship/README.md b/tests/starship/README.md
index 0ea5e5f0..4995e428 100644
--- a/tests/starship/README.md
+++ b/tests/starship/README.md
@@ -1,11 +1,14 @@
# Starship Tests
+
Multi-chain e2e tests that run against any chain, using chain binaries, relayers
and deploying Mesh-Security contracts.
Starship runs by separating out the infra from the tests that are run against the infra.
## Getting Started
+
### Setup script
+
In the `tests/starship` dir, run
```bash
@@ -13,33 +16,42 @@ make setup-deps ## Installs dependencies for Starship
```
### Manul install (alternate)
+
Alternatively to the setup script one can just install the deps directly:
-* docker: https://docs.docker.com/get-docker/
-* kubectl: https://kubernetes.io/docs/tasks/tools/
-* kind: https://kind.sigs.k8s.io/docs/user/quick-start/#installation
-* helm: https://helm.sh/docs/intro/install/
-* yq: https://github.com/mikefarah/yq/#install
+
+* docker:
+* kubectl:
+* kind:
+* helm:
+* yq:
## Connect to a kubernetes cluster
+
### Spinup local cluster
+
On Linux:
+
```bash
make setup-kind
```
On Mac:
-Use Docker Desktop to setup kubernetes cluster: https://docs.docker.com/desktop/kubernetes/#turn-on-kubernetes
+Use Docker Desktop to setup kubernetes cluster:
### Connect to a remote cluster (alternate)
+
If one has access to a k8s cluster via a `kubeconfig` file one can run Starship directly on the remote cluster.
## Check connection with cluster
+
Run
+
```bash
kubectl get nodes
```
## Run Tests
+
Once the initial connection and setup is done, then one can spin up starship infra with
```bash
@@ -50,41 +62,45 @@ make install FILE=configs/devnet.yaml
Once the helm chart is installed, you will have to wait for pods to be in a `Running` state. Usually takes 3-5 mins depending on the resources available.
Can check with
+
```bash
kubectl get pods
```
When all pods are in `Running` state, run port-forwarding to access the nodes on localhost
+
```bash
make port-forward
# All exposed endpoints would be printed by this command
```
Now you can run the tests with:
+
```bash
make test
```
Once done, cleanup with:
+
```bash
make stop
```
-
## Configs
+
Starship configs is the definition of the infra we want to spin up.
Present in `test/starship/configs`, are multiple versions of the similar infra, tweaked to be able to run in different environments
+
* `configs/local.yaml`: Config file to be able to run locally
* `configs/devnet.yaml`: Supposed to be run on a larger k8s cluster, with more resources and number of validators
* `configs/ci.yaml`: Limited resources on the GH-Action runner, can be adapted for with reducing cpu,memory allocated
All the config files are similar topology, but different resources allocated.
Topology:
+
* 2 chains: `mesh-1` and `mesh-2` (both running `mesh-security-sdk` demo app)
* 1 hermes relayer: running between the chains, in pull mode (1.6.0)
* Registry service: analogous to cosmos chain-registry, but for only our infra
* Optionally explorer: ping-pub explorer for the mini cosmos
Details of each of arguments in the config file can be found [here](https://starship.cosmology.tech/config/chains)
-
-
diff --git a/tests/starship/configs/local.yaml b/tests/starship/configs/local.yaml
index 71d3c17d..90ec28f0 100644
--- a/tests/starship/configs/local.yaml
+++ b/tests/starship/configs/local.yaml
@@ -2,7 +2,7 @@ chains:
- name: mesh-1
type: custom
numValidators: 1
- image: ghcr.io/osmosis-labs/meshd:anmol-restart-starship@sha256:a2d44df58adf71dabecb9c03ae4eb5fdf460843de72b04ee49b91d55705005c9
+ image: ghcr.io/decentrio/meshd:debug
home: /root/.meshd
binary: meshd
prefix: mesh
@@ -10,7 +10,6 @@ chains:
coins: 100000000000000stake
hdPath: m/44'/118'/0'/0/0
coinType: 118
- repo: https://github.com/osmosis/mesh-security-sdk
genesis:
app_state:
meshsecurity:
@@ -24,8 +23,8 @@ chains:
rpc: 26653
faucet: 8003
resources:
- cpu: "0.5"
- memory: 1Gi
+ cpu: "1"
+ memory: 2Gi
faucet:
enabled: true
type: starship
@@ -36,7 +35,7 @@ chains:
- name: mesh-2
type: custom
numValidators: 1
- image: ghcr.io/osmosis-labs/meshd:anmol-restart-starship@sha256:a2d44df58adf71dabecb9c03ae4eb5fdf460843de72b04ee49b91d55705005c9
+ image: ghcr.io/decentrio/meshd:debug
home: /root/.meshd
binary: meshd
prefix: mesh
@@ -44,7 +43,6 @@ chains:
coins: 100000000000000stake
hdPath: m/44'/118'/0'/0/0
coinType: 118
- repo: https://github.com/osmosis/mesh-security-sdk
genesis:
app_state:
meshsecurity:
@@ -58,8 +56,8 @@ chains:
rpc: 26657
faucet: 8007
resources:
- cpu: "0.5"
- memory: 1Gi
+ cpu: "1"
+ memory: 2Gi
faucet:
enabled: true
type: starship
diff --git a/tests/starship/mvp_test.go b/tests/starship/mvp_test.go
index a0e29634..0dd90e62 100644
--- a/tests/starship/mvp_test.go
+++ b/tests/starship/mvp_test.go
@@ -10,7 +10,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/osmosis-labs/mesh-security-sdk/tests/starship/setup"
@@ -24,9 +23,11 @@ import (
// require.NoError(t, err)
//}
+var maxRetrieve = uint16(50)
+
func Test2WayContract(t *testing.T) {
// create clients for provider and consumer
- providerClient1, consumerClient1, err := setup.MeshSecurity(providerChain, consumerChain, configFile, wasmContractPath, wasmContractGZipped)
+ providerClient1, consumerClient1, err := setup.MeshSecurity(providerChain, consumerChain, configFile, wasmContractPath, wasmContractGZipped, 50)
require.NoError(t, err)
require.NotEmpty(t, providerClient1)
require.NotEmpty(t, consumerClient1)
@@ -37,10 +38,7 @@ func Test2WayContract(t *testing.T) {
func() bool {
qRsp = providerClient1.QueryExtStaking(setup.Query{"list_active_validators": {}})
v := qRsp["validators"].([]interface{})
- if len(v) > 0 {
- return true
- }
- return false
+ return len(v) > 0
},
120*time.Second,
2*time.Second,
@@ -92,7 +90,8 @@ func Test2WayContract(t *testing.T) {
require.NoError(t, err)
// require.NoError(t, coord.RelayAndAckPendingPackets(ibcPath))
- require.Equal(t, 20_000_000, providerClient1.QueryVaultFreeBalance()) // = 70 (free) + 30 (local) - 80 (remote staked)
+ providerClient1.QueryVaultFreeBalance() // = 70 (free) + 30 (local) - 80 (remote staked)
+ providerClient1.QueryVaultActiveExtStaking()
// then
fmt.Println("provider chain: query ext staking")
@@ -106,7 +105,7 @@ func Test2WayContract(t *testing.T) {
assert.Empty(t, qRsp["pending_unbonds"])
// create opposite clients
- providerClient2, consumerClient2, err := setup.MeshSecurity(consumerChain, providerChain, configFile, wasmContractPath, wasmContractGZipped)
+ providerClient2, consumerClient2, err := setup.MeshSecurity(consumerChain, providerChain, configFile, wasmContractPath, wasmContractGZipped, maxRetrieve)
require.NoError(t, err)
require.NotEmpty(t, providerClient2)
require.NotEmpty(t, consumerClient2)
@@ -115,10 +114,7 @@ func Test2WayContract(t *testing.T) {
func() bool {
qRsp = providerClient2.QueryExtStaking(setup.Query{"list_active_validators": {}})
v := qRsp["validators"].([]interface{})
- if len(v) > 0 {
- return true
- }
- return false
+ return len(v) > 0
},
120*time.Second,
2*time.Second,
diff --git a/tests/starship/setup/client.go b/tests/starship/setup/client.go
index c28c63a4..332f2fee 100644
--- a/tests/starship/setup/client.go
+++ b/tests/starship/setup/client.go
@@ -194,10 +194,7 @@ func (c *Client) WaitForHeight(t *testing.T, height int64) {
func() bool {
curHeight, err := c.GetHeight()
assert.NoError(t, err)
- if curHeight >= height {
- return true
- }
- return false
+ return curHeight >= height
},
300*time.Second,
2*time.Second,
diff --git a/tests/starship/setup/cmd/main.go b/tests/starship/setup/cmd/main.go
index e2cc4a92..95ba86df 100644
--- a/tests/starship/setup/cmd/main.go
+++ b/tests/starship/setup/cmd/main.go
@@ -12,6 +12,7 @@ var (
ConfigFile string
ProviderChain string
ConsumerChain string
+ maxRetrieve = uint16(50)
)
func main() {
@@ -22,7 +23,7 @@ func main() {
flag.StringVar(&ConsumerChain, "consumer-chain", "mesh-juno-1", "consumer chain name, from config file")
flag.Parse()
- _, _, err := setup.MeshSecurity(ProviderChain, ConsumerChain, ConfigFile, WasmContractPath, WasmContractGZipped)
+ _, _, err := setup.MeshSecurity(ProviderChain, ConsumerChain, ConfigFile, WasmContractPath, WasmContractGZipped, maxRetrieve)
if err != nil {
panic(err)
}
diff --git a/tests/starship/setup/main.go b/tests/starship/setup/main.go
index e91a92bb..00a6ad18 100644
--- a/tests/starship/setup/main.go
+++ b/tests/starship/setup/main.go
@@ -76,7 +76,7 @@ func JustContracts(provider, consumer, configFile, wasmContractPath string, wasm
return nil
}
-func MeshSecurity(provider, consumer, configFile, wasmContractPath string, wasmContractGZipped bool) (*ProviderClient, *ConsumerClient, error) {
+func MeshSecurity(provider, consumer, configFile, wasmContractPath string, wasmContractGZipped bool, maxRetrieve uint16) (*ProviderClient, *ConsumerClient, error) {
// read config file from yaml
yamlFile, err := os.ReadFile(configFile)
if err != nil {
@@ -137,7 +137,7 @@ func MeshSecurity(provider, consumer, configFile, wasmContractPath string, wasmC
// setup Contracts on both chains
consumerCli := NewConsumerClient(consumerClient, wasmContractPath, wasmContractGZipped)
- consumerContracts, err := consumerCli.BootstrapContracts(providerClient.Denom)
+ consumerContracts, err := consumerCli.BootstrapContracts(providerClient.Denom, maxRetrieve)
if err != nil {
return nil, nil, err
}
@@ -198,10 +198,7 @@ func MeshSecurity(provider, consumer, configFile, wasmContractPath string, wasmC
func() bool {
qRsp = providerCli.QueryExtStaking(Query{"list_active_validators": {}})
v := qRsp["validators"].([]interface{})
- if len(v) > 0 {
- return true
- }
- return false
+ return len(v) > 0
},
300*time.Second,
2*time.Second,
@@ -221,6 +218,9 @@ func MeshSecurity(provider, consumer, configFile, wasmContractPath string, wasmC
return nil, nil, err
}
authAddrStr, err := bech32.ConvertAndEncode(*registry.Bech32Prefix, authAddr)
+ if err != nil {
+ return nil, nil, err
+ }
govProposal := &types.MsgSetVirtualStakingMaxCap{
Authority: authAddrStr,
Contract: consumerContracts.Staking,
diff --git a/tests/starship/setup/setup.go b/tests/starship/setup/setup.go
index 17ab8daf..f0046762 100644
--- a/tests/starship/setup/setup.go
+++ b/tests/starship/setup/setup.go
@@ -34,10 +34,7 @@ func Querier(chain *Client) func(contract string, query Query) map[string]any {
panic(fmt.Sprintf("error in query: %s\n. Stopping early...", err))
}
_, ok := qRsp["locked"]
- if ok {
- return false
- }
- return true
+ return !ok
},
300*time.Second,
2*time.Second,
@@ -84,6 +81,9 @@ func (p *ProviderClient) StoreContracts() ([]uint64, error) {
time.Sleep(1 * time.Second)
nativeStakingCodeResp, err := StoreCodeFile(p.Chain, buildPathToWasm(p.wasmContractPath, "mesh_native_staking.wasm", p.wasmContractGZipped))
+ if err != nil {
+ return nil, err
+ }
nativeStakingCodeID := nativeStakingCodeResp.CodeID
// external Staking
@@ -118,6 +118,9 @@ func (p *ProviderClient) BootstrapContracts(connId, portID, rewardDenom string)
//time.Sleep(time.Second)
proxyCodeID := proxyCodeResp.CodeID
nativeStakingCodeResp, err := StoreCodeFile(p.Chain, buildPathToWasm(p.wasmContractPath, "mesh_native_staking.wasm", p.wasmContractGZipped))
+ if err != nil {
+ return nil, err
+ }
nativeStakingCodeID := nativeStakingCodeResp.CodeID
//time.Sleep(time.Second)
@@ -223,10 +226,7 @@ func (p ProviderClient) QueryVaultFreeBalance() int {
"account": {"account": p.Chain.Address},
})
_, ok := qRsp["locked"]
- if ok {
- return false
- }
- return true
+ return !ok
},
300*time.Second,
2*time.Second,
@@ -239,6 +239,27 @@ func (p ProviderClient) QueryVaultFreeBalance() int {
return ParseHighLow(qRsp["free"]).Low
}
+func (p ProviderClient) QueryVaultActiveExtStaking() {
+ qRsp := map[string]any{}
+ err := Eventually(
+ func() bool {
+ qRsp = p.QueryVault(Query{
+ "active_external_staking": {},
+ })
+ _, ok := qRsp["contracts"]
+ return ok
+ },
+ 300*time.Second,
+ 2*time.Second,
+ "vault token locked for too long: %v",
+ qRsp,
+ )
+ if err != nil {
+ panic(err)
+ }
+ fmt.Println("contracts: ", qRsp["contracts"])
+}
+
type HighLowType struct {
High, Low int
}
@@ -303,7 +324,7 @@ func (p *ConsumerClient) StoreContracts() ([]uint64, error) {
return []uint64{codeID, virtStakeCodeID, converterCodeID}, nil
}
-func (p *ConsumerClient) BootstrapContracts(remoteDenom string) (*ConsumerContract, error) {
+func (p *ConsumerClient) BootstrapContracts(remoteDenom string, maxRetrieve uint16) (*ConsumerContract, error) {
// what does this do????
// modify end-blocker to fail fast in tests
// msModule := p.app.ModuleManager.Modules[types.ModuleName].(*meshsecurity.AppModule)
@@ -341,8 +362,8 @@ func (p *ConsumerClient) BootstrapContracts(remoteDenom string) (*ConsumerContra
//time.Sleep(time.Second)
discount := "0.1" // todo: configure price
- initMsg = []byte(fmt.Sprintf(`{"price_feed": %q, "discount": %q, "remote_denom": %q,"virtual_staking_code_id": %d}`,
- priceFeedContract, discount, remoteDenom, virtStakeCodeID))
+ initMsg = []byte(fmt.Sprintf(`{"price_feed": %q, "discount": %q, "remote_denom": %q,"virtual_staking_code_id": %d, "max_retrieve": %d}`,
+ priceFeedContract, discount, remoteDenom, virtStakeCodeID, maxRetrieve))
// bug in lens that returns second contract instantiated
contracts, err := InstantiateContract(p.Chain, codeID, "consumer-converter-contract", initMsg)
if err != nil {
diff --git a/tests/testdata/copy_local_wasm.sh b/tests/testdata/copy_local_wasm.sh
index b85023cd..1e47a731 100755
--- a/tests/testdata/copy_local_wasm.sh
+++ b/tests/testdata/copy_local_wasm.sh
@@ -4,7 +4,7 @@ command -v shellcheck > /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_simple_price_feed \
+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 \
mesh_vault mesh_virtual_staking ; do
cp -f ../../../mesh-security/artifacts/${contract}.wasm .
gzip -fk ${contract}.wasm
diff --git a/tests/testdata/copy_local_wasm_aarch64.sh b/tests/testdata/copy_local_wasm_aarch64.sh
new file mode 100755
index 00000000..8b8ea926
--- /dev/null
+++ b/tests/testdata/copy_local_wasm_aarch64.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+set -o errexit -o nounset -o pipefail
+command -v shellcheck > /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 \
+mesh_vault mesh_virtual_staking ; do
+cp -f ../../../mesh-security/artifacts/${contract}-aarch64.wasm .
+gzip -fk ${contract}-aarch64.wasm
+rm -f ${contract}.wasm.gz
+mv ${contract}-aarch64.wasm.gz ${contract}.wasm.gz
+rm -f ${contract}-aarch64.wasm
+done
+
+cd ../../../mesh-security
+tag=$(git rev-parse HEAD)
+cd -
+rm -f version.txt
+echo "$tag" >version.txt
\ No newline at end of file
diff --git a/tests/testdata/mesh_converter.wasm.gz b/tests/testdata/mesh_converter.wasm.gz
index 72a0e716..61821da4 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 63319fa2..4ba8bf8b 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 6f4a87c3..1670dbf4 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 e56378bf..04f30997 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_provider.wasm.gz b/tests/testdata/mesh_osmosis_price_provider.wasm.gz
index ced15230..0cdd504d 100644
Binary files a/tests/testdata/mesh_osmosis_price_provider.wasm.gz and b/tests/testdata/mesh_osmosis_price_provider.wasm.gz differ
diff --git a/tests/testdata/mesh_remote_price_feed.wasm.gz b/tests/testdata/mesh_remote_price_feed.wasm.gz
index f9e82d16..b5be67c2 100644
Binary files a/tests/testdata/mesh_remote_price_feed.wasm.gz and b/tests/testdata/mesh_remote_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 31a9944c..97a29e25 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 117a1eab..8ff46c34 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 c2977a7f..d2ffc9f4 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 d7bfc037..7228d975 100644
--- a/tests/testdata/version.txt
+++ b/tests/testdata/version.txt
@@ -1 +1 @@
-34284a38601ff132e8d7b5594a87794faa71bbed
+ef0e3840b092ed66cd0968e2b9b253ae243ffe52
diff --git a/x/meshsecurity/contract/in_message.go b/x/meshsecurity/contract/in_message.go
index 873b8638..6eddb2ce 100644
--- a/x/meshsecurity/contract/in_message.go
+++ b/x/meshsecurity/contract/in_message.go
@@ -7,8 +7,10 @@ type (
VirtualStake *VirtualStakeMsg `json:"virtual_stake,omitempty"`
}
VirtualStakeMsg struct {
- Bond *BondMsg `json:"bond,omitempty"`
- Unbond *UnbondMsg `json:"unbond,omitempty"`
+ Bond *BondMsg `json:"bond,omitempty"`
+ Unbond *UnbondMsg `json:"unbond,omitempty"`
+ UpdateDelegation *UpdateDelegationMsg `json:"update_delegation,omitempty"`
+ DeleteAllScheduledTasks *DeleteAllScheduledTasksMsg `json:"delete_all_scheduled_tasks,omitempty"`
}
BondMsg struct {
Amount wasmvmtypes.Coin `json:"amount"`
@@ -18,4 +20,12 @@ type (
Amount wasmvmtypes.Coin `json:"amount"`
Validator string `json:"validator"`
}
+ UpdateDelegationMsg struct {
+ Amount wasmvmtypes.Coin `json:"amount"`
+ IsDeduct bool `json:"is_deduct"`
+ Delegator string `json:"delegator"`
+ Validator string `json:"validator"`
+ }
+
+ DeleteAllScheduledTasksMsg struct{}
)
diff --git a/x/meshsecurity/contract/out_message.go b/x/meshsecurity/contract/out_message.go
index 224bd694..9077f6ca 100644
--- a/x/meshsecurity/contract/out_message.go
+++ b/x/meshsecurity/contract/out_message.go
@@ -6,8 +6,8 @@ import (
type (
SudoMsg struct {
- HandleEpoch *struct{} `json:"handle_epoch,omitempty"`
- ValsetUpdate *ValsetUpdate `json:"handle_valset_update,omitempty"`
+ HandleEpoch *struct{} `json:"handle_epoch,omitempty"`
+ HandleValsetUpdate *HandleValsetUpdate `json:"handle_valset_update,omitempty"`
}
// Validator alias to wasmVM type
@@ -27,7 +27,7 @@ type (
}
// ValsetUpdate updates to the active validator set
- ValsetUpdate struct {
+ HandleValsetUpdate struct {
Additions []Validator `json:"additions"`
Removals []ValidatorAddr `json:"removals"`
Updated []Validator `json:"updated"`
diff --git a/x/meshsecurity/contract/query.go b/x/meshsecurity/contract/query.go
index 5d1032c3..3010e3c0 100644
--- a/x/meshsecurity/contract/query.go
+++ b/x/meshsecurity/contract/query.go
@@ -1,14 +1,18 @@
package contract
-import wasmvmtypes "github.com/CosmWasm/wasmvm/types"
+import (
+ wasmvmtypes "github.com/CosmWasm/wasmvm/types"
+ "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types"
+)
type (
CustomQuery struct {
VirtualStake *VirtualStakeQuery `json:"virtual_stake,omitempty"`
}
VirtualStakeQuery struct {
- BondStatus *BondStatusQuery `json:"bond_status,omitempty"`
- SlashRatio *struct{} `json:"slash_ratio,omitempty"`
+ BondStatus *BondStatusQuery `json:"bond_status,omitempty"`
+ AllDelegations *AllDelegationsQuery `json:"all_delegations,omitempty"`
+ SlashRatio *struct{} `json:"slash_ratio,omitempty"`
}
BondStatusQuery struct {
Contract string `json:"contract"`
@@ -19,8 +23,32 @@ type (
// Delegated is the used amount of the max cap
Delegated wasmvmtypes.Coin `json:"delegated"`
}
+ AllDelegationsQuery struct {
+ Contract string `json:"contract"`
+ MaxRetrieve uint16 `json:"max_retrieve"`
+ }
+ AllDelegationsResponse struct {
+ Delegations []Delegation `json:"delegations"`
+ }
+ Delegation struct {
+ Delegator string `json:"delegator"`
+ Validator string `json:"validator"`
+ Amount string `json:"amount"`
+ }
SlashRatioResponse struct {
SlashFractionDowntime string `json:"slash_fraction_downtime"`
SlashFractionDoubleSign string `json:"slash_fraction_double_sign"`
}
)
+
+func ConvertDelegationsToWasm(delegations []types.Delegation) (newDelegations []Delegation) {
+ for _, del := range delegations {
+ delegation := Delegation{
+ Delegator: del.DelegatorAddress,
+ Validator: del.ValidatorAddress,
+ Amount: del.Amount.String(),
+ }
+ newDelegations = append(newDelegations, delegation)
+ }
+ return
+}
\ No newline at end of file
diff --git a/x/meshsecurity/keeper/handler_plugin.go b/x/meshsecurity/keeper/handler_plugin.go
index 80e84c3e..6e0c9d0c 100644
--- a/x/meshsecurity/keeper/handler_plugin.go
+++ b/x/meshsecurity/keeper/handler_plugin.go
@@ -23,8 +23,10 @@ type AuthSource interface {
// abstract keeper
type msKeeper interface {
- Delegate(ctx sdk.Context, actor sdk.AccAddress, addr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error)
- Undelegate(ctx sdk.Context, actor sdk.AccAddress, addr sdk.ValAddress, coin sdk.Coin) error
+ Delegate(ctx sdk.Context, actor sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error)
+ Undelegate(ctx sdk.Context, actor sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) error
+ UpdateDelegation(ctx sdk.Context, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin, isDeduct bool)
+ DeleteAllScheduledTasks(ctx sdk.Context, tp types.SchedulerTaskType, contract sdk.AccAddress) error
}
type CustomMsgHandler struct {
@@ -75,6 +77,10 @@ func (h CustomMsgHandler) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddre
return h.handleBondMsg(ctx, contractAddr, customMsg.VirtualStake.Bond)
case customMsg.VirtualStake.Unbond != nil:
return h.handleUnbondMsg(ctx, contractAddr, customMsg.VirtualStake.Unbond)
+ case customMsg.VirtualStake.UpdateDelegation != nil:
+ return h.handleUpdateDelegationMsg(ctx, contractAddr, customMsg.VirtualStake.UpdateDelegation)
+ case customMsg.VirtualStake.DeleteAllScheduledTasks != nil:
+ return nil, nil, h.k.DeleteAllScheduledTasks(ctx, types.SchedulerTaskHandleEpoch, contractAddr)
}
return nil, nil, wasmtypes.ErrUnknownMsg
}
@@ -125,6 +131,31 @@ func (h CustomMsgHandler) handleUnbondMsg(ctx sdk.Context, actor sdk.AccAddress,
)}, nil, nil
}
+func (h CustomMsgHandler) handleUpdateDelegationMsg(ctx sdk.Context, actor sdk.AccAddress, updateDelegationMsg *contract.UpdateDelegationMsg) ([]sdk.Event, [][]byte, error) {
+ coin, err := wasmkeeper.ConvertWasmCoinToSdkCoin(updateDelegationMsg.Amount)
+ if err != nil {
+ return nil, nil, err
+ }
+ delAddr, err := sdk.AccAddressFromBech32(updateDelegationMsg.Delegator)
+ if err != nil {
+ return nil, nil, err
+ }
+ valAddr, err := sdk.ValAddressFromBech32(updateDelegationMsg.Validator)
+ if err != nil {
+ return nil, nil, err
+ }
+ h.k.UpdateDelegation(ctx, actor, delAddr, valAddr, coin, updateDelegationMsg.IsDeduct)
+
+ return []sdk.Event{sdk.NewEvent(
+ types.EventTypeUpdateDelegation,
+ sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
+ sdk.NewAttribute(types.AttributeKeyDelegator, delAddr.String()),
+ sdk.NewAttribute(types.AttributeKeyValidator, valAddr.String()),
+ sdk.NewAttribute(sdk.AttributeKeyAmount, coin.String()),
+ sdk.NewAttribute(sdk.AttributeKeySender, actor.String()),
+ )}, nil, nil
+}
+
// AuthSourceFn is helper for simple AuthSource types
type AuthSourceFn func(ctx sdk.Context, contractAddr sdk.AccAddress) bool
diff --git a/x/meshsecurity/keeper/handler_plugin_test.go b/x/meshsecurity/keeper/handler_plugin_test.go
index 95bd947e..e578a7f6 100644
--- a/x/meshsecurity/keeper/handler_plugin_test.go
+++ b/x/meshsecurity/keeper/handler_plugin_test.go
@@ -25,16 +25,18 @@ func TestCustomMeshSecDispatchMsg(t *testing.T) {
)
var (
myContractAddr = sdk.AccAddress(rand.Bytes(32))
+ myDelegatorAddr = sdk.AccAddress(rand.Bytes(32))
myValidatorAddr = sdk.ValAddress(rand.Bytes(20))
myAmount = sdk.NewInt64Coin("ALX", 1234)
myErr = errors.New("testing")
)
validBondMsg := []byte(fmt.Sprintf(
- `{"virtual_stake":{"bond":{"amount":{"denom":"ALX", "amount":"1234"},"validator":%q}}}`,
- myValidatorAddr.String()))
+ `{"virtual_stake":{"bond":{"amount":{"denom":"ALX", "amount":"1234"},"delegator":%q,"validator":%q}}}`,
+ myDelegatorAddr.String(), myValidatorAddr.String()))
validUnbondMsg := []byte(fmt.Sprintf(
- `{"virtual_stake":{"unbond":{"amount":{"denom":"ALX", "amount":"1234"},"validator":%q}}}`,
- myValidatorAddr.String()))
+ `{"virtual_stake":{"unbond":{"amount":{"denom":"ALX", "amount":"1234"},"delegator":%q,"validator":%q}}}`,
+ myDelegatorAddr.String(), myValidatorAddr.String()))
+ validDeleteScheduledTasks := []byte(`{"virtual_stake":{"delete_all_scheduled_tasks":{}}}`)
specs := map[string]struct {
src wasmvmtypes.CosmosMsg
@@ -62,7 +64,7 @@ func TestCustomMeshSecDispatchMsg(t *testing.T) {
src: wasmvmtypes.CosmosMsg{Custom: validBondMsg},
auth: allAuthZ,
setup: func(t *testing.T) (msKeeper, func()) {
- m := msKeeperMock{DelegateFn: func(_ sdk.Context, actor sdk.AccAddress, addr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error) {
+ m := msKeeperMock{DelegateFn: func(_ sdk.Context, actor sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error) {
return sdk.ZeroDec(), myErr
}}
return &m, t.FailNow
@@ -87,7 +89,18 @@ func TestCustomMeshSecDispatchMsg(t *testing.T) {
src: wasmvmtypes.CosmosMsg{Custom: validUnbondMsg},
auth: allAuthZ,
setup: func(t *testing.T) (msKeeper, func()) {
- m := msKeeperMock{UndelegateFn: func(_ sdk.Context, actor sdk.AccAddress, addr sdk.ValAddress, coin sdk.Coin) error {
+ m := msKeeperMock{UndelegateFn: func(_ sdk.Context, actor sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) error {
+ return myErr
+ }}
+ return &m, t.FailNow
+ },
+ expErr: myErr,
+ },
+ "handle delete tasks": {
+ src: wasmvmtypes.CosmosMsg{Custom: validDeleteScheduledTasks},
+ auth: allAuthZ,
+ setup: func(t *testing.T) (msKeeper, func()) {
+ m := msKeeperMock{DeleteAllScheduledTasksFn: func(_ sdk.Context, tp types.SchedulerTaskType, contract sdk.AccAddress) error {
return myErr
}}
return &m, t.FailNow
@@ -181,22 +194,38 @@ func captureCall(t *testing.T, myContractAddr sdk.AccAddress, myValidatorAddr sd
var _ msKeeper = msKeeperMock{}
type msKeeperMock struct {
- DelegateFn func(ctx sdk.Context, actor sdk.AccAddress, addr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error)
- UndelegateFn func(ctx sdk.Context, actor sdk.AccAddress, addr sdk.ValAddress, coin sdk.Coin) error
+ DelegateFn func(ctx sdk.Context, actor sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error)
+ UndelegateFn func(ctx sdk.Context, actor sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) error
+ UpdateDelegationFn func(ctx sdk.Context, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin, isDeduct bool)
+ DeleteAllScheduledTasksFn func(ctx sdk.Context, tp types.SchedulerTaskType, contract sdk.AccAddress) error
}
-func (m msKeeperMock) Delegate(ctx sdk.Context, actor sdk.AccAddress, addr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error) {
+func (m msKeeperMock) Delegate(ctx sdk.Context, actor sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error) {
if m.DelegateFn == nil {
panic("not expected to be called")
}
- return m.DelegateFn(ctx, actor, addr, coin)
+ return m.DelegateFn(ctx, actor, valAddr, coin)
}
-func (m msKeeperMock) Undelegate(ctx sdk.Context, actor sdk.AccAddress, addr sdk.ValAddress, coin sdk.Coin) error {
+func (m msKeeperMock) Undelegate(ctx sdk.Context, actor sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) error {
if m.UndelegateFn == nil {
panic("not expected to be called")
}
- return m.UndelegateFn(ctx, actor, addr, coin)
+ return m.UndelegateFn(ctx, actor, valAddr, coin)
+}
+
+func (m msKeeperMock) UpdateDelegation(ctx sdk.Context, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin, isDeduct bool) {
+ if m.UpdateDelegationFn == nil {
+ panic("not expected to be called")
+ }
+ m.UpdateDelegationFn(ctx, actor, delAddr, valAddr, coin, isDeduct)
+}
+
+func (m msKeeperMock) DeleteAllScheduledTasks(ctx sdk.Context, tp types.SchedulerTaskType, contract sdk.AccAddress) error {
+ if m.DeleteAllScheduledTasksFn == nil {
+ panic("not expected to be called")
+ }
+ return m.DeleteAllScheduledTasksFn(ctx, tp, contract)
}
func TestIntegrityHandler(t *testing.T) {
diff --git a/x/meshsecurity/keeper/keeper.go b/x/meshsecurity/keeper/keeper.go
index a9117790..9577ee42 100644
--- a/x/meshsecurity/keeper/keeper.go
+++ b/x/meshsecurity/keeper/keeper.go
@@ -147,6 +147,66 @@ func (k Keeper) setTotalDelegated(ctx sdk.Context, actor sdk.AccAddress, newAmou
store.Set(types.BuildTotalDelegatedAmountKey(actor), bz)
}
+// GetDelegation returns contract delegation for a specified delegator bond with validator.
+func (k Keeper) GetDelegation(ctx sdk.Context, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress) types.Delegation {
+ store := ctx.KVStore(k.storeKey)
+ key := types.BuildDelegationKey(actor, delAddr, valAddr)
+ bz := store.Get(key)
+ if bz == nil {
+ return types.Delegation{
+ DelegatorAddress: delAddr.String(),
+ ValidatorAddress: valAddr.String(),
+ Amount: math.ZeroInt(),
+ }
+ }
+ var del types.Delegation
+ if err := del.Unmarshal(bz); err != nil {
+ panic(err)
+ }
+ return del
+}
+
+// GetAllDelegations returns all delegations for a specific contract
+func (k Keeper) GetAllDelegations(ctx sdk.Context, actor sdk.AccAddress, maxRetrieve uint16) (delegations []types.Delegation) {
+ delegations = make([]types.Delegation, maxRetrieve)
+ store := ctx.KVStore(k.storeKey)
+ contractPrefixKey := types.BuildDelegationsKey(actor)
+
+ iterator := sdk.KVStorePrefixIterator(store, contractPrefixKey)
+ defer iterator.Close()
+
+ i := 0
+ for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() {
+ var del types.Delegation
+ if err := del.Unmarshal(iterator.Value()); err != nil {
+ panic(err)
+ }
+
+ delegations[i] = del
+ i++
+ }
+
+ return delegations[:i] // trim if the array length < maxRetrieve
+}
+
+// setDelegation store the delegation of a given delegator bond with validator
+func (k Keeper) setDelegation(ctx sdk.Context, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress, changeAmount math.Int) {
+ store := ctx.KVStore(k.storeKey)
+
+ newDelegation := k.GetDelegation(ctx, actor, delAddr, valAddr)
+ newDelegation.Amount = newDelegation.Amount.Add(changeAmount)
+ if newDelegation.Amount.IsZero() {
+ store.Delete(types.BuildDelegationKey(actor, delAddr, valAddr))
+ return
+ }
+
+ bz, err := newDelegation.Marshal()
+ if err != nil { // always nil
+ panic(err)
+ }
+ store.Set(types.BuildDelegationKey(actor, delAddr, valAddr), bz)
+}
+
// helper to deserialize a math.Int from store. Returns zero when key does not exist.
// Panics when Unmarshal fails
func (k Keeper) mustLoadInt(ctx sdk.Context, storeKey storetypes.StoreKey, key []byte) math.Int {
diff --git a/x/meshsecurity/keeper/keeper_test.go b/x/meshsecurity/keeper/keeper_test.go
index 18d6a6c8..2ac49820 100644
--- a/x/meshsecurity/keeper/keeper_test.go
+++ b/x/meshsecurity/keeper/keeper_test.go
@@ -123,3 +123,26 @@ func TestSetMaxCapLimit(t *testing.T) {
})
}
}
+
+func TestSetDelegation(t *testing.T) {
+ pCtx, keepers := CreateDefaultTestInput(t)
+ k := keepers.MeshKeeper
+ var (
+ myContractAddr = sdk.AccAddress(rand.Bytes(32))
+ myAccAddr = sdk.AccAddress(rand.Bytes(32))
+ myValAddr = sdk.ValAddress(rand.Bytes(32))
+ oneStakeCoin = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)
+ )
+
+ ctx, _ := pCtx.CacheContext()
+
+ k.UpdateDelegation(ctx, myContractAddr, myAccAddr, myValAddr, oneStakeCoin, false)
+
+ allDels := k.GetAllDelegations(ctx, myContractAddr, 10)
+ assert.Len(t, allDels, 1)
+ assert.Equal(t, allDels[0].Amount, oneStakeCoin.Amount)
+
+ k.UpdateDelegation(ctx, myContractAddr, myAccAddr, myValAddr, oneStakeCoin, true)
+ allDels = k.GetAllDelegations(ctx, myContractAddr, 10)
+ assert.Len(t, allDels, 0)
+}
diff --git a/x/meshsecurity/keeper/msg_server.go b/x/meshsecurity/keeper/msg_server.go
index 7e709793..1d81decb 100644
--- a/x/meshsecurity/keeper/msg_server.go
+++ b/x/meshsecurity/keeper/msg_server.go
@@ -47,16 +47,5 @@ func (m msgServer) SetVirtualStakingMaxCap(goCtx context.Context, req *types.Msg
}
return &types.MsgSetVirtualStakingMaxCapResponse{}, nil
}
- if req.MaxCap.IsZero() {
- // no need to run regular rebalances with a new limit of 0
- if err := m.k.DeleteAllScheduledTasks(ctx, types.SchedulerTaskHandleEpoch, acc); err != nil {
- return nil, err
- }
- }
-
- // schedule last rebalance callback to let the contract do undelegates and housekeeping
- if err := m.k.ScheduleOneShotTask(ctx, types.SchedulerTaskHandleEpoch, acc, uint64(ctx.BlockHeight())); err != nil {
- return nil, errorsmod.Wrap(err, "schedule one shot rebalance task")
- }
return &types.MsgSetVirtualStakingMaxCapResponse{}, nil
}
diff --git a/x/meshsecurity/keeper/msg_server_test.go b/x/meshsecurity/keeper/msg_server_test.go
index 30c81c04..74bd70e8 100644
--- a/x/meshsecurity/keeper/msg_server_test.go
+++ b/x/meshsecurity/keeper/msg_server_test.go
@@ -43,50 +43,6 @@ func TestSetVirtualStakingMaxCap(t *testing.T) {
assert.True(t, k.HasScheduledTask(ctx, types.SchedulerTaskHandleEpoch, myContract, true))
},
},
- "existing limit updated": {
- setup: func(ctx sdk.Context) {
- _, err := m.SetVirtualStakingMaxCap(sdk.WrapSDKContext(ctx), &types.MsgSetVirtualStakingMaxCap{
- Authority: k.GetAuthority(),
- Contract: myContract.String(),
- MaxCap: sdk.NewInt64Coin(denom, 456),
- })
- require.NoError(t, err)
- },
- src: types.MsgSetVirtualStakingMaxCap{
- Authority: k.GetAuthority(),
- Contract: myContract.String(),
- MaxCap: myAmount,
- },
- expLimit: myAmount,
- expSchedule: func(t *testing.T, ctx sdk.Context) {
- repeat, exists := k.getScheduledTaskAt(ctx, types.SchedulerTaskHandleEpoch, myContract, uint64(ctx.BlockHeight()))
- require.True(t, exists)
- assert.False(t, repeat)
- assert.True(t, k.HasScheduledTask(ctx, types.SchedulerTaskHandleEpoch, myContract, true))
- },
- },
- "existing limit set to empty value": {
- setup: func(ctx sdk.Context) {
- _, err := m.SetVirtualStakingMaxCap(sdk.WrapSDKContext(ctx), &types.MsgSetVirtualStakingMaxCap{
- Authority: k.GetAuthority(),
- Contract: myContract.String(),
- MaxCap: myAmount,
- })
- require.NoError(t, err)
- },
- src: types.MsgSetVirtualStakingMaxCap{
- Authority: k.GetAuthority(),
- Contract: myContract.String(),
- MaxCap: sdk.NewInt64Coin(denom, 0),
- },
- expLimit: sdk.NewInt64Coin(denom, 0),
- expSchedule: func(t *testing.T, ctx sdk.Context) {
- repeat, exists := k.getScheduledTaskAt(ctx, types.SchedulerTaskHandleEpoch, myContract, uint64(ctx.BlockHeight()))
- require.True(t, exists)
- assert.False(t, repeat)
- assert.False(t, k.HasScheduledTask(ctx, types.SchedulerTaskHandleEpoch, myContract, true))
- },
- },
"fails for non existing contract": {
setup: func(ctx sdk.Context) {},
src: types.MsgSetVirtualStakingMaxCap{
diff --git a/x/meshsecurity/keeper/query_plugin.go b/x/meshsecurity/keeper/query_plugin.go
index 2d5f784d..05e86e71 100644
--- a/x/meshsecurity/keeper/query_plugin.go
+++ b/x/meshsecurity/keeper/query_plugin.go
@@ -12,6 +12,7 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/contract"
+ "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types"
)
type (
@@ -19,6 +20,7 @@ type (
viewKeeper interface {
GetMaxCapLimit(ctx sdk.Context, actor sdk.AccAddress) sdk.Coin
GetTotalDelegated(ctx sdk.Context, actor sdk.AccAddress) sdk.Coin
+ GetAllDelegations(ctx sdk.Context, actor sdk.AccAddress, maxRetrieve uint16) []types.Delegation
}
slashingKeeper interface {
SlashFractionDoubleSign(ctx sdk.Context) (res sdk.Dec)
@@ -83,6 +85,16 @@ func ChainedCustomQuerier(k viewKeeper, sk slashingKeeper, next wasmkeeper.WasmV
SlashFractionDowntime: sk.SlashFractionDowntime(ctx).String(),
SlashFractionDoubleSign: sk.SlashFractionDoubleSign(ctx).String(),
}
+ case query.AllDelegations != nil:
+ contractAddr, err := sdk.AccAddressFromBech32(query.AllDelegations.Contract)
+ if err != nil {
+ return nil, sdkerrors.ErrInvalidAddress.Wrap(query.AllDelegations.Contract)
+ }
+ delegations := k.GetAllDelegations(ctx, contractAddr, query.AllDelegations.MaxRetrieve)
+
+ res = contract.AllDelegationsResponse{
+ Delegations: contract.ConvertDelegationsToWasm(delegations),
+ }
default:
return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown virtual_stake query variant"}
}
diff --git a/x/meshsecurity/keeper/query_plugin_test.go b/x/meshsecurity/keeper/query_plugin_test.go
index fd439eae..05e9a160 100644
--- a/x/meshsecurity/keeper/query_plugin_test.go
+++ b/x/meshsecurity/keeper/query_plugin_test.go
@@ -6,6 +6,7 @@ import (
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
"github.com/cometbft/cometbft/libs/rand"
+ "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -36,6 +37,9 @@ func TestChainedCustomQuerier(t *testing.T) {
GetTotalDelegatedFn: func(ctx sdk.Context, actor sdk.AccAddress) sdk.Coin {
return sdk.NewCoin("ALX", math.NewInt(456))
},
+ GetAllDelegationsFn: func(ctx sdk.Context, actor sdk.AccAddress, maxRetrieve uint16) []types.Delegation {
+ return []types.Delegation{}
+ },
},
expData: []byte(`{"cap":{"denom":"ALX","amount":"123"},"delegated":{"denom":"ALX","amount":"456"}}`),
},
@@ -87,6 +91,7 @@ var _ viewKeeper = &MockViewKeeper{}
type MockViewKeeper struct {
GetMaxCapLimitFn func(ctx sdk.Context, actor sdk.AccAddress) sdk.Coin
GetTotalDelegatedFn func(ctx sdk.Context, actor sdk.AccAddress) sdk.Coin
+ GetAllDelegationsFn func(ctx sdk.Context, actor sdk.AccAddress, maxRetrieve uint16) []types.Delegation
}
func (m MockViewKeeper) GetMaxCapLimit(ctx sdk.Context, actor sdk.AccAddress) sdk.Coin {
@@ -102,3 +107,10 @@ func (m MockViewKeeper) GetTotalDelegated(ctx sdk.Context, actor sdk.AccAddress)
}
return m.GetTotalDelegatedFn(ctx, actor)
}
+
+func (m MockViewKeeper) GetAllDelegations(ctx sdk.Context, actor sdk.AccAddress, maxRetrieve uint16) []types.Delegation {
+ if m.GetAllDelegationsFn == nil {
+ panic("not expected to be called")
+ }
+ return m.GetAllDelegationsFn(ctx, actor, maxRetrieve)
+}
diff --git a/x/meshsecurity/keeper/stake.go b/x/meshsecurity/keeper/stake.go
index a1fcfb41..d9b1234f 100644
--- a/x/meshsecurity/keeper/stake.go
+++ b/x/meshsecurity/keeper/stake.go
@@ -60,6 +60,7 @@ func (k Keeper) Delegate(pCtx sdk.Context, actor sdk.AccAddress, valAddr sdk.Val
// and update our records
k.setTotalDelegated(cacheCtx, actor, newTotalDelegatedAmount)
+
done()
return newShares, err
}
@@ -115,3 +116,12 @@ func (k Keeper) Undelegate(pCtx sdk.Context, actor sdk.AccAddress, valAddr sdk.V
done()
return nil
}
+
+func (k Keeper) UpdateDelegation(pCtx sdk.Context, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt sdk.Coin, isDeduct bool) {
+ cacheCtx, done := pCtx.CacheContext() // work in a cached store (safety net?)
+ if isDeduct {
+ amt.Amount = amt.Amount.Neg()
+ }
+ k.setDelegation(cacheCtx, actor, delAddr, valAddr, amt.Amount)
+ done()
+}
diff --git a/x/meshsecurity/keeper/valset_updates.go b/x/meshsecurity/keeper/valset_updates.go
index 50101d1a..992f3d79 100644
--- a/x/meshsecurity/keeper/valset_updates.go
+++ b/x/meshsecurity/keeper/valset_updates.go
@@ -10,8 +10,6 @@ import (
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/contract"
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types"
-
- outmessage "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/contract"
)
// ScheduleBonded store a validator update to bonded status for the valset update report
@@ -77,7 +75,7 @@ func (k Keeper) sendAsync(ctx sdk.Context, op types.PipedValsetOperation, valAdd
// ValsetUpdateReport aggregate all stored changes of the current block. Should be called by an end-blocker.
// The events reported are categorized by type and not time. Conflicting events as Bonded/ Unbonded
// are not supposed to happen within the same block
-func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (contract.ValsetUpdate, error) {
+func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (contract.HandleValsetUpdate, error) {
var innerErr error
appendValidator := func(set *[]wasmvmtypes.Validator, valAddr sdk.ValAddress) bool {
val, ok := k.Staking.GetValidator(ctx, valAddr)
@@ -88,9 +86,9 @@ func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (contract.ValsetUpdate, erro
*set = append(*set, ConvertSdkValidatorToWasm(val))
return false
}
- slashValidator := func(set *[]outmessage.ValidatorSlash, valAddr sdk.ValAddress, power int64, infractionHeight int64,
+ slashValidator := func(set *[]contract.ValidatorSlash, valAddr sdk.ValAddress, power int64, infractionHeight int64,
infractionTime int64, slashAmount string, slashRatio string) bool {
- valSlash := outmessage.ValidatorSlash{
+ valSlash := contract.ValidatorSlash{
ValidatorAddr: valAddr.String(),
Power: power,
InfractionHeight: infractionHeight,
@@ -103,7 +101,7 @@ func (k Keeper) ValsetUpdateReport(ctx sdk.Context) (contract.ValsetUpdate, erro
*set = append(*set, valSlash)
return false
}
- r := contract.ValsetUpdate{ // init with empty slices for contract that does not handle null or omitted fields
+ r := contract.HandleValsetUpdate{ // init with empty slices for contract that does not handle null or omitted fields
Additions: make([]contract.Validator, 0),
Removals: make([]contract.ValidatorAddr, 0),
Updated: make([]contract.Validator, 0),
diff --git a/x/meshsecurity/keeper/valset_updates_test.go b/x/meshsecurity/keeper/valset_updates_test.go
index 5d794593..e48daa2b 100644
--- a/x/meshsecurity/keeper/valset_updates_test.go
+++ b/x/meshsecurity/keeper/valset_updates_test.go
@@ -148,7 +148,7 @@ func TestBuildValsetUpdateReport(t *testing.T) {
got, err := k.ValsetUpdateReport(ctx)
// then
require.NoError(t, err)
- exp := contract.ValsetUpdate{
+ exp := contract.HandleValsetUpdate{
Additions: []contract.Validator{
{
Address: val4.String(),
diff --git a/x/meshsecurity/keeper/wasm.go b/x/meshsecurity/keeper/wasm.go
index 8ee4c4f6..33fe9d19 100644
--- a/x/meshsecurity/keeper/wasm.go
+++ b/x/meshsecurity/keeper/wasm.go
@@ -5,6 +5,7 @@ import (
errorsmod "cosmossdk.io/errors"
+ storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/contract"
@@ -15,13 +16,14 @@ func (k Keeper) SendHandleEpoch(ctx sdk.Context, contractAddr sdk.AccAddress) er
msg := contract.SudoMsg{
HandleEpoch: &struct{}{},
}
+ ctx = ctx.WithGasMeter(storetypes.NewInfiniteGasMeter())
return k.doSudoCall(ctx, contractAddr, msg)
}
// SendValsetUpdate submit the valset update report to the virtual staking contract via sudo
-func (k Keeper) SendValsetUpdate(ctx sdk.Context, contractAddr sdk.AccAddress, v contract.ValsetUpdate) error {
+func (k Keeper) SendValsetUpdate(ctx sdk.Context, contractAddr sdk.AccAddress, v contract.HandleValsetUpdate) error {
msg := contract.SudoMsg{
- ValsetUpdate: &v,
+ HandleValsetUpdate: &v,
}
return k.doSudoCall(ctx, contractAddr, msg)
}
diff --git a/x/meshsecurity/types/events.go b/x/meshsecurity/types/events.go
index 3343914e..20b2a370 100644
--- a/x/meshsecurity/types/events.go
+++ b/x/meshsecurity/types/events.go
@@ -11,6 +11,7 @@ const (
EventTypeSchedulerRegistered = "scheduler_registered"
EventTypeMaxCapLimitUpdated = "max_cap_limit_updated"
EventTypeUnbond = "instant_unbond"
+ EventTypeUpdateDelegation = "update_delegation"
EventTypeDelegate = "instant_delegate"
)
diff --git a/x/meshsecurity/types/keys.go b/x/meshsecurity/types/keys.go
index fa21f06c..1534c089 100644
--- a/x/meshsecurity/types/keys.go
+++ b/x/meshsecurity/types/keys.go
@@ -2,6 +2,7 @@ package types
import (
"encoding/binary"
+
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
@@ -31,6 +32,8 @@ var (
SchedulerKeyPrefix = []byte{0x4}
PipedValsetPrefix = []byte{0x5}
+
+ DelegationKey = []byte{0x6}
)
type PipedValsetOperation byte
@@ -119,3 +122,15 @@ func BuildPipedValsetOpKey(op PipedValsetOperation, val sdk.ValAddress, slashInf
}
return r
}
+
+// BuildDelegationsKey build the delegations's prefix for a contract
+func BuildDelegationsKey(actor sdk.AccAddress) []byte {
+ return append(DelegationKey, address.MustLengthPrefix(actor)...)
+}
+
+// BuildDelegationKey build the prefix for a delegator bond with validator
+func BuildDelegationKey(actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte {
+ key := append(BuildDelegationsKey(actor), address.MustLengthPrefix(delAddr)...)
+ key = append(key, address.MustLengthPrefix(valAddr)...)
+ return key
+}
diff --git a/x/meshsecurity/types/meshsecurity.pb.go b/x/meshsecurity/types/meshsecurity.pb.go
index 6abc9723..bf28bcdb 100644
--- a/x/meshsecurity/types/meshsecurity.pb.go
+++ b/x/meshsecurity/types/meshsecurity.pb.go
@@ -5,6 +5,7 @@ package types
import (
fmt "fmt"
+ 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/tx/amino"
_ "github.com/cosmos/gogoproto/gogoproto"
@@ -69,6 +70,49 @@ func (m *VirtualStakingMaxCapInfo) XXX_DiscardUnknown() {
var xxx_messageInfo_VirtualStakingMaxCapInfo proto.InternalMessageInfo
+// Delegation represents the bond with tokens held by an account.
+type Delegation struct {
+ // delegator_address is the bech32-encoded address of the delegator.
+ DelegatorAddress string `protobuf:"bytes,1,opt,name=delegator_address,json=delegatorAddress,proto3" json:"delegator_address,omitempty"`
+ // validator_address is the bech32-encoded address of the validator.
+ ValidatorAddress string `protobuf:"bytes,2,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"`
+ // amount define the delegation amount.
+ Amount github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=amount,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount"`
+}
+
+func (m *Delegation) Reset() { *m = Delegation{} }
+func (m *Delegation) String() string { return proto.CompactTextString(m) }
+func (*Delegation) ProtoMessage() {}
+func (*Delegation) Descriptor() ([]byte, []int) {
+ return fileDescriptor_53771980e3e4256c, []int{1}
+}
+func (m *Delegation) XXX_Unmarshal(b []byte) error {
+ return m.Unmarshal(b)
+}
+func (m *Delegation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ if deterministic {
+ return xxx_messageInfo_Delegation.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 *Delegation) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Delegation.Merge(m, src)
+}
+func (m *Delegation) XXX_Size() int {
+ return m.Size()
+}
+func (m *Delegation) XXX_DiscardUnknown() {
+ xxx_messageInfo_Delegation.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Delegation proto.InternalMessageInfo
+
// Params defines the parameters for the x/meshsecurity module.
type Params struct {
// TotalContractsMaxCap is the maximum that the sum of all contract max caps
@@ -85,7 +129,7 @@ func (m *Params) Reset() { *m = Params{} }
func (m *Params) String() string { return proto.CompactTextString(m) }
func (*Params) ProtoMessage() {}
func (*Params) Descriptor() ([]byte, []int) {
- return fileDescriptor_53771980e3e4256c, []int{1}
+ return fileDescriptor_53771980e3e4256c, []int{2}
}
func (m *Params) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -116,6 +160,7 @@ var xxx_messageInfo_Params proto.InternalMessageInfo
func init() {
proto.RegisterType((*VirtualStakingMaxCapInfo)(nil), "osmosis.meshsecurity.v1beta1.VirtualStakingMaxCapInfo")
+ proto.RegisterType((*Delegation)(nil), "osmosis.meshsecurity.v1beta1.Delegation")
proto.RegisterType((*Params)(nil), "osmosis.meshsecurity.v1beta1.Params")
}
@@ -124,33 +169,39 @@ func init() {
}
var fileDescriptor_53771980e3e4256c = []byte{
- // 416 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x41, 0x8b, 0xd3, 0x40,
- 0x14, 0xce, 0xb8, 0xcb, 0xe2, 0xce, 0xba, 0xa0, 0xd9, 0x05, 0x63, 0x59, 0x66, 0xd7, 0x9e, 0x8a,
- 0x90, 0x84, 0xea, 0xad, 0xa0, 0x87, 0x16, 0x11, 0x41, 0x41, 0x22, 0xf4, 0xe0, 0x25, 0xbe, 0x4c,
- 0xc6, 0x64, 0x68, 0x32, 0x13, 0x32, 0x53, 0x49, 0xff, 0x82, 0x27, 0x7f, 0x82, 0x47, 0x4f, 0xe2,
- 0xcf, 0xe8, 0xb1, 0x47, 0x4f, 0xa2, 0xe9, 0x41, 0x7f, 0x86, 0x64, 0xd2, 0x54, 0x72, 0xeb, 0x65,
- 0x78, 0xf3, 0xbd, 0xf9, 0xbe, 0xf9, 0x3e, 0xde, 0xc3, 0xbe, 0x54, 0xb9, 0x54, 0x5c, 0xf9, 0x39,
- 0x53, 0xa9, 0x62, 0x74, 0x59, 0x72, 0xbd, 0xf2, 0x3f, 0x8e, 0x23, 0xa6, 0x61, 0xdc, 0x03, 0xbd,
- 0xa2, 0x94, 0x5a, 0xda, 0x57, 0x3b, 0x82, 0xd7, 0xeb, 0xed, 0x08, 0x03, 0x42, 0x4d, 0xdb, 0x8f,
- 0x40, 0xb1, 0xbd, 0x0a, 0x95, 0x5c, 0xb4, 0xec, 0xc1, 0x65, 0x22, 0x13, 0x69, 0x4a, 0xbf, 0xa9,
- 0x76, 0xe8, 0x3d, 0xc8, 0xb9, 0x90, 0xbe, 0x39, 0x5b, 0x68, 0xf8, 0x0d, 0x61, 0x67, 0xce, 0x4b,
- 0xbd, 0x84, 0xec, 0xad, 0x86, 0x05, 0x17, 0xc9, 0x6b, 0xa8, 0x66, 0x50, 0xbc, 0x14, 0x1f, 0xa4,
- 0x3d, 0xc0, 0xb7, 0xa9, 0x14, 0xba, 0x04, 0xaa, 0x1d, 0x74, 0x83, 0x46, 0xa7, 0xc1, 0xfe, 0x6e,
- 0x3f, 0xc5, 0xa7, 0x31, 0xcb, 0x58, 0x02, 0x9a, 0xc5, 0xce, 0xad, 0x1b, 0x34, 0x3a, 0x7b, 0xfc,
- 0xc0, 0x6b, 0x5d, 0x79, 0x8d, 0xab, 0xce, 0xaa, 0x37, 0x93, 0x5c, 0x4c, 0x8f, 0xd7, 0x3f, 0xaf,
- 0xad, 0xe0, 0x3f, 0xc3, 0x1e, 0xe3, 0x23, 0x0a, 0x85, 0x73, 0x74, 0x18, 0xb1, 0x79, 0x3b, 0x39,
- 0xfe, 0xfb, 0xe5, 0x1a, 0x0d, 0x37, 0x08, 0x9f, 0xbc, 0x81, 0x12, 0x72, 0x65, 0xcf, 0xf1, 0x7d,
- 0x2d, 0x35, 0x64, 0x61, 0x67, 0x4a, 0x85, 0x39, 0x54, 0x61, 0xa3, 0x8b, 0x0e, 0xd3, 0xbd, 0x34,
- 0xfc, 0x59, 0x47, 0x6f, 0xa3, 0xdb, 0x0f, 0xf1, 0x1d, 0x56, 0x48, 0x9a, 0x86, 0x19, 0x13, 0x89,
- 0x4e, 0x4d, 0xba, 0xf3, 0xe0, 0xcc, 0x60, 0xaf, 0x0c, 0x64, 0xbb, 0xf8, 0xa2, 0xf9, 0x2a, 0x01,
- 0x15, 0x32, 0x11, 0x87, 0x51, 0x26, 0xe9, 0x82, 0x95, 0x26, 0xce, 0x79, 0x70, 0x37, 0x87, 0xea,
- 0x05, 0xa8, 0xe7, 0x22, 0x9e, 0xb6, 0xf8, 0xe4, 0xaa, 0xb1, 0xfe, 0xe9, 0xcf, 0xf7, 0x47, 0x17,
- 0xbd, 0xf1, 0xb7, 0x39, 0xa6, 0xef, 0xd7, 0xbf, 0x89, 0xf5, 0xb5, 0x26, 0xd6, 0xba, 0x26, 0x68,
- 0x53, 0x13, 0xf4, 0xab, 0x26, 0xe8, 0xf3, 0x96, 0x58, 0x9b, 0x2d, 0xb1, 0x7e, 0x6c, 0x89, 0xf5,
- 0xee, 0x59, 0xc2, 0x75, 0xba, 0x8c, 0x3c, 0x2a, 0xf3, 0x6e, 0x91, 0xdc, 0x0c, 0xa2, 0x76, 0x9b,
- 0xdc, 0x4e, 0xcf, 0x55, 0xf1, 0xc2, 0xaf, 0xfa, 0x1b, 0xa6, 0x57, 0x05, 0x53, 0xd1, 0x89, 0x19,
- 0xf6, 0x93, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x98, 0xcb, 0x62, 0xae, 0x86, 0x02, 0x00, 0x00,
+ // 501 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x53, 0x4d, 0x6f, 0xd3, 0x40,
+ 0x10, 0xf5, 0xb6, 0x55, 0x45, 0xb6, 0x54, 0x6a, 0xdd, 0x4a, 0x84, 0xa8, 0x72, 0x4a, 0x0e, 0xa8,
+ 0x02, 0xc5, 0x56, 0xe0, 0x56, 0x09, 0x24, 0x12, 0x3e, 0x54, 0x09, 0x24, 0x64, 0xa4, 0x1e, 0xb8,
+ 0x98, 0xb1, 0xbd, 0x38, 0xab, 0xd8, 0x3b, 0x96, 0x77, 0x53, 0xa5, 0x7f, 0x81, 0x13, 0x3f, 0x81,
+ 0x23, 0x27, 0xc4, 0x81, 0x1f, 0x91, 0x63, 0x8e, 0x88, 0x43, 0x05, 0xc9, 0x01, 0x7e, 0x06, 0xf2,
+ 0xae, 0x1d, 0xf0, 0xad, 0x17, 0x7b, 0xfd, 0xe6, 0xbd, 0xf1, 0xdb, 0xb7, 0xb3, 0xd4, 0x43, 0x99,
+ 0xa1, 0xe4, 0xd2, 0xcb, 0x98, 0x1c, 0x4b, 0x16, 0x4d, 0x0b, 0xae, 0x2e, 0xbd, 0x8b, 0x41, 0xc8,
+ 0x14, 0x0c, 0x1a, 0xa0, 0x9b, 0x17, 0xa8, 0xd0, 0x3e, 0xaa, 0x04, 0x6e, 0xa3, 0x56, 0x09, 0x3a,
+ 0x4e, 0xa4, 0xcb, 0x5e, 0x08, 0x92, 0xad, 0xbb, 0x44, 0xc8, 0x85, 0x51, 0x77, 0x0e, 0x13, 0x4c,
+ 0x50, 0x2f, 0xbd, 0x72, 0x55, 0xa1, 0xfb, 0x90, 0x71, 0x81, 0x9e, 0x7e, 0x1a, 0xa8, 0xf7, 0x85,
+ 0xd0, 0xf6, 0x39, 0x2f, 0xd4, 0x14, 0xd2, 0x37, 0x0a, 0x26, 0x5c, 0x24, 0xaf, 0x60, 0x36, 0x82,
+ 0xfc, 0x4c, 0xbc, 0x47, 0xbb, 0x43, 0x6f, 0x44, 0x28, 0x54, 0x01, 0x91, 0x6a, 0x93, 0x63, 0x72,
+ 0xd2, 0xf2, 0xd7, 0xdf, 0xf6, 0x23, 0xda, 0x8a, 0x59, 0xca, 0x12, 0x50, 0x2c, 0x6e, 0x6f, 0x1c,
+ 0x93, 0x93, 0x9d, 0x07, 0xb7, 0x5d, 0xe3, 0xca, 0x2d, 0x5d, 0xd5, 0x56, 0xdd, 0x11, 0x72, 0x31,
+ 0xdc, 0x9a, 0x5f, 0x75, 0x2d, 0xff, 0x9f, 0xc2, 0x1e, 0xd0, 0xcd, 0x08, 0xf2, 0xf6, 0xe6, 0xf5,
+ 0x84, 0x25, 0xf7, 0x74, 0xeb, 0xcf, 0xa7, 0x2e, 0xe9, 0x7d, 0x23, 0x94, 0x3e, 0x35, 0x6d, 0x38,
+ 0x0a, 0xfb, 0x3e, 0xdd, 0xaf, 0x9a, 0x62, 0x11, 0x40, 0x1c, 0x17, 0x4c, 0xca, 0xca, 0xeb, 0xde,
+ 0xba, 0xf0, 0xc4, 0xe0, 0x25, 0xf9, 0x02, 0x52, 0x1e, 0x37, 0xc8, 0x1b, 0x86, 0xbc, 0x2e, 0xd4,
+ 0xe4, 0xe7, 0x74, 0x1b, 0x32, 0x9c, 0x0a, 0xa5, 0x4d, 0xb6, 0x86, 0x6e, 0xe9, 0xe4, 0xc7, 0x55,
+ 0xf7, 0x6e, 0xc2, 0xd5, 0x78, 0x1a, 0xba, 0x11, 0x66, 0x5e, 0x75, 0x0a, 0xe6, 0xd5, 0x97, 0xf1,
+ 0xc4, 0x53, 0x97, 0x39, 0x93, 0xee, 0x99, 0x50, 0x7e, 0xa5, 0xd6, 0xb6, 0xad, 0xde, 0x82, 0xd0,
+ 0xed, 0xd7, 0x50, 0x40, 0x26, 0xed, 0x73, 0x7a, 0x4b, 0xa1, 0x82, 0x34, 0xa8, 0xb3, 0x94, 0x41,
+ 0x06, 0xb3, 0xa0, 0x8c, 0x83, 0x5c, 0x2f, 0x8e, 0x43, 0xad, 0x1f, 0xd5, 0x72, 0x73, 0x62, 0xf6,
+ 0x1d, 0x7a, 0x93, 0xe5, 0x18, 0x8d, 0x83, 0x94, 0x89, 0x44, 0x8d, 0xf5, 0xc6, 0x76, 0xfd, 0x1d,
+ 0x8d, 0xbd, 0xd4, 0x90, 0xdd, 0xa7, 0x07, 0xe5, 0xaf, 0x12, 0x90, 0x01, 0x13, 0x71, 0x10, 0xa6,
+ 0x18, 0x4d, 0x58, 0xa1, 0x37, 0xb8, 0xeb, 0xef, 0x65, 0x30, 0x7b, 0x01, 0xf2, 0x99, 0x88, 0x87,
+ 0x06, 0x3f, 0x3d, 0x2a, 0x13, 0xff, 0xf0, 0xfb, 0xeb, 0xbd, 0x83, 0xc6, 0xd4, 0x9a, 0x7d, 0x0c,
+ 0xdf, 0xcd, 0x7f, 0x39, 0xd6, 0xe7, 0xa5, 0x63, 0xcd, 0x97, 0x0e, 0x59, 0x2c, 0x1d, 0xf2, 0x73,
+ 0xe9, 0x90, 0x8f, 0x2b, 0xc7, 0x5a, 0xac, 0x1c, 0xeb, 0xfb, 0xca, 0xb1, 0xde, 0x3e, 0xfe, 0x2f,
+ 0xaa, 0x6a, 0x9c, 0xfb, 0x29, 0x84, 0xe6, 0x12, 0xf4, 0xeb, 0x7e, 0x3a, 0xb7, 0x59, 0xf3, 0x62,
+ 0xe8, 0x18, 0xc3, 0x6d, 0x3d, 0xa3, 0x0f, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xea, 0xe6, 0x72,
+ 0xce, 0x3d, 0x03, 0x00, 0x00,
}
func (this *VirtualStakingMaxCapInfo) Equal(that interface{}) bool {
@@ -263,6 +314,53 @@ func (m *VirtualStakingMaxCapInfo) MarshalToSizedBuffer(dAtA []byte) (int, error
return len(dAtA) - i, nil
}
+func (m *Delegation) 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 *Delegation) MarshalTo(dAtA []byte) (int, error) {
+ size := m.Size()
+ return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *Delegation) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+ i := len(dAtA)
+ _ = i
+ var l int
+ _ = l
+ {
+ size := m.Amount.Size()
+ i -= size
+ if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil {
+ return 0, err
+ }
+ i = encodeVarintMeshsecurity(dAtA, i, uint64(size))
+ }
+ i--
+ dAtA[i] = 0x1a
+ if len(m.ValidatorAddress) > 0 {
+ i -= len(m.ValidatorAddress)
+ copy(dAtA[i:], m.ValidatorAddress)
+ i = encodeVarintMeshsecurity(dAtA, i, uint64(len(m.ValidatorAddress)))
+ i--
+ dAtA[i] = 0x12
+ }
+ if len(m.DelegatorAddress) > 0 {
+ i -= len(m.DelegatorAddress)
+ copy(dAtA[i:], m.DelegatorAddress)
+ i = encodeVarintMeshsecurity(dAtA, i, uint64(len(m.DelegatorAddress)))
+ i--
+ dAtA[i] = 0xa
+ }
+ return len(dAtA) - i, nil
+}
+
func (m *Params) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -334,6 +432,25 @@ func (m *VirtualStakingMaxCapInfo) Size() (n int) {
return n
}
+func (m *Delegation) Size() (n int) {
+ if m == nil {
+ return 0
+ }
+ var l int
+ _ = l
+ l = len(m.DelegatorAddress)
+ if l > 0 {
+ n += 1 + l + sovMeshsecurity(uint64(l))
+ }
+ l = len(m.ValidatorAddress)
+ if l > 0 {
+ n += 1 + l + sovMeshsecurity(uint64(l))
+ }
+ l = m.Amount.Size()
+ n += 1 + l + sovMeshsecurity(uint64(l))
+ return n
+}
+
func (m *Params) Size() (n int) {
if m == nil {
return 0
@@ -505,6 +622,154 @@ func (m *VirtualStakingMaxCapInfo) Unmarshal(dAtA []byte) error {
}
return nil
}
+func (m *Delegation) 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 ErrIntOverflowMeshsecurity
+ }
+ 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: Delegation: wiretype end group for non-group")
+ }
+ if fieldNum <= 0 {
+ return fmt.Errorf("proto: Delegation: illegal tag %d (wire type %d)", fieldNum, wire)
+ }
+ switch fieldNum {
+ case 1:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field DelegatorAddress", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMeshsecurity
+ }
+ 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 ErrInvalidLengthMeshsecurity
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthMeshsecurity
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.DelegatorAddress = string(dAtA[iNdEx:postIndex])
+ iNdEx = postIndex
+ case 2:
+ if wireType != 2 {
+ return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType)
+ }
+ var stringLen uint64
+ for shift := uint(0); ; shift += 7 {
+ if shift >= 64 {
+ return ErrIntOverflowMeshsecurity
+ }
+ 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 ErrInvalidLengthMeshsecurity
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthMeshsecurity
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ m.ValidatorAddress = 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 ErrIntOverflowMeshsecurity
+ }
+ 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 ErrInvalidLengthMeshsecurity
+ }
+ postIndex := iNdEx + intStringLen
+ if postIndex < 0 {
+ return ErrInvalidLengthMeshsecurity
+ }
+ if postIndex > l {
+ return io.ErrUnexpectedEOF
+ }
+ if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+ return err
+ }
+ iNdEx = postIndex
+ default:
+ iNdEx = preIndex
+ skippy, err := skipMeshsecurity(dAtA[iNdEx:])
+ if err != nil {
+ return err
+ }
+ if (skippy < 0) || (iNdEx+skippy) < 0 {
+ return ErrInvalidLengthMeshsecurity
+ }
+ if (iNdEx + skippy) > l {
+ return io.ErrUnexpectedEOF
+ }
+ iNdEx += skippy
+ }
+ }
+
+ if iNdEx > l {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
func (m *Params) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0