Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Handle zero max cap on chain logic #173

Merged
merged 14 commits into from
Sep 5, 2024
34 changes: 34 additions & 0 deletions docs/proto/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -22,6 +23,7 @@
- [Query](#osmosis.meshsecurity.v1beta1.Query)

- [osmosis/meshsecurity/v1beta1/scheduler.proto](#osmosis/meshsecurity/v1beta1/scheduler.proto)
- [ScheduledWork](#osmosis.meshsecurity.v1beta1.ScheduledWork)
- [ValidatorAddress](#osmosis.meshsecurity.v1beta1.ValidatorAddress)

- [osmosis/meshsecurity/v1beta1/tx.proto](#osmosis/meshsecurity/v1beta1/tx.proto)
Expand All @@ -41,6 +43,23 @@



<a name="osmosis.meshsecurity.v1beta1.Delegation"></a>

### 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. |






<a name="osmosis.meshsecurity.v1beta1.Params"></a>

### Params
Expand Down Expand Up @@ -238,6 +257,21 @@ Query provides defines the gRPC querier service



<a name="osmosis.meshsecurity.v1beta1.ScheduledWork"></a>

### ScheduledWork



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `repeat` | [bool](#bool) | | |
trinitys7 marked this conversation as resolved.
Show resolved Hide resolved






<a name="osmosis.meshsecurity.v1beta1.ValidatorAddress"></a>

### ValidatorAddress
Expand Down
15 changes: 15 additions & 0 deletions proto/osmosis/meshsecurity/v1beta1/meshsecurity.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
7 changes: 3 additions & 4 deletions tests/e2e/README.md
Original file line number Diff line number Diff line change
@@ -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
```


```
4 changes: 3 additions & 1 deletion tests/e2e/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ type example struct {
ProviderDenom string
ConsumerDenom string
MyProvChainActor string
MaxRetrieve uint16
}

func setupExampleChains(t *testing.T) example {
Expand All @@ -118,6 +119,7 @@ func setupExampleChains(t *testing.T) example {
ProviderDenom: sdk.DefaultBondDenom,
ConsumerDenom: sdk.DefaultBondDenom,
MyProvChainActor: provChain.SenderAccount.GetAddress().String(),
MaxRetrieve: 50,
}
}

Expand All @@ -126,7 +128,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)))
Expand Down
18 changes: 9 additions & 9 deletions tests/e2e/mvp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestMVP(t *testing.T) {
// ...
x := setupExampleChains(t)
consumerCli, consumerContracts, providerCli := setupMeshSecurity(t, x)

sender := x.ProviderChain.SenderAccount.GetAddress()
// 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": {}})
Expand All @@ -60,7 +60,7 @@ func TestMVP(t *testing.T) {
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
execMsg := `{"bond":{}}`
providerCli.MustExecVault(execMsg, sdk.NewInt64Coin(x.ProviderDenom, 100_000_000))
providerCli.MustExecVault(sender, execMsg, sdk.NewInt64Coin(x.ProviderDenom, 100_000_000))

// then query contract state
assert.Equal(t, 100_000_000, providerCli.QueryVaultFreeBalance())
Expand All @@ -70,18 +70,18 @@ func TestMVP(t *testing.T) {
execLocalStakingMsg := fmt.Sprintf(`{"stake_local":{"amount": {"denom":%q, "amount":"%d"}, "msg":%q}}`,
x.ProviderDenom, 30_000_000,
base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"validator": "%s"}`, myLocalValidatorAddr))))
providerCli.MustExecVault(execLocalStakingMsg)
providerCli.MustExecVault(sender, execLocalStakingMsg)

assert.Equal(t, 70_000_000, providerCli.QueryVaultFreeBalance())

// Failure mode of cross-stake... trying to stake to an unknown validator
err := providerCli.ExecStakeRemote("BAD-VALIDATOR", sdk.NewInt64Coin(x.ProviderDenom, 80_000_000))
err := providerCli.ExecStakeRemote(sender, "BAD-VALIDATOR", sdk.NewInt64Coin(x.ProviderDenom, 80_000_000))
require.Error(t, err)
// no change to free balance
assert.Equal(t, 70_000_000, providerCli.QueryVaultFreeBalance())

// Cross Stake - A user pulls out additional liens on the same collateral "cross staking" it on different chains.
err = providerCli.ExecStakeRemote(myExtValidatorAddr, sdk.NewInt64Coin(x.ProviderDenom, 80_000_000))
err = providerCli.ExecStakeRemote(sender, myExtValidatorAddr, sdk.NewInt64Coin(x.ProviderDenom, 80_000_000))
require.NoError(t, err)

require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))
Expand Down Expand Up @@ -117,7 +117,7 @@ func TestMVP(t *testing.T) {
//
// Cross Stake - A user undelegates
execMsg = fmt.Sprintf(`{"unstake":{"validator":"%s", "amount":{"denom":"%s", "amount":"30000000"}}}`, myExtValidator.String(), x.ProviderDenom)
providerCli.MustExecExtStaking(execMsg)
providerCli.MustExecExtStaking(sender, execMsg)

require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))

Expand Down Expand Up @@ -163,15 +163,15 @@ func TestMVP(t *testing.T) {
require.NoError(t, x.IbcPath.EndpointB.UpdateClient())
}

providerCli.MustExecExtStaking(`{"withdraw_unbonded":{}}`)
providerCli.MustExecExtStaking(sender, `{"withdraw_unbonded":{}}`)
assert.Equal(t, 50_000_000, providerCli.QueryVaultFreeBalance())

// provider chain
// ==============
//
// A user unstakes some free amount from the vault
balanceBefore := x.ProviderChain.Balance(x.ProviderChain.SenderAccount.GetAddress(), "stake")
providerCli.MustExecVault(fmt.Sprintf(`{"unbond":{"amount":{"denom":"%s", "amount": "30000000"}}}`, x.ProviderDenom))
providerCli.MustExecVault(sender, fmt.Sprintf(`{"unbond":{"amount":{"denom":"%s", "amount": "30000000"}}}`, x.ProviderDenom))
// then
assert.Equal(t, 20_000_000, providerCli.QueryVaultFreeBalance())
balanceAfter := x.ProviderChain.Balance(x.ProviderChain.SenderAccount.GetAddress(), x.ProviderDenom)
Expand Down Expand Up @@ -204,7 +204,7 @@ func TestMVP(t *testing.T) {
targetAddr := sdk.AccAddress(rand.Bytes(address.Len))
gotBalance := x.ConsumerChain.Balance(targetAddr, x.ConsumerDenom).Amount
require.Equal(t, math.ZeroInt(), gotBalance)
providerCli.MustExecExtStaking(fmt.Sprintf(`{"withdraw_rewards":{"validator": %q, "remote_recipient": %q}}`, myExtValidatorAddr, targetAddr.String()))
providerCli.MustExecExtStaking(sender, fmt.Sprintf(`{"withdraw_rewards":{"validator": %q, "remote_recipient": %q}}`, myExtValidatorAddr, targetAddr.String()))
require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))

// then should be on destination account
Expand Down
34 changes: 19 additions & 15 deletions tests/e2e/slashing_test.go
Original file line number Diff line number Diff line change
@@ -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) {
Expand All @@ -17,30 +18,30 @@ func TestSlashingScenario1(t *testing.T) {
// - We use millions instead of unit tokens.
x := setupExampleChains(t)
consumerCli, _, providerCli := setupMeshSecurity(t, x)

sender := x.ProviderChain.SenderAccount.GetAddress()
// Provider chain
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
execMsg := `{"bond":{}}`
providerCli.MustExecVault(execMsg, sdk.NewInt64Coin(x.ProviderDenom, 200_000_000))
providerCli.MustExecVault(sender, execMsg, sdk.NewInt64Coin(x.ProviderDenom, 200_000_000))

// Stake Locally - A user triggers a local staking action to a chosen validator.
myLocalValidatorAddr := sdk.ValAddress(x.ProviderChain.Vals.Validators[0].Address).String()
execLocalStakingMsg := fmt.Sprintf(`{"stake_local":{"amount": {"denom":%q, "amount":"%d"}, "msg":%q}}`,
x.ProviderDenom, 190_000_000,
base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"validator": "%s"}`, myLocalValidatorAddr))))
providerCli.MustExecVault(execLocalStakingMsg)
providerCli.MustExecVault(sender, execLocalStakingMsg)

assert.Equal(t, 10_000_000, providerCli.QueryVaultFreeBalance())

// Cross Stake - A user pulls out additional liens on the same collateral "cross staking" it on different chains.
myExtValidator1 := sdk.ValAddress(x.ConsumerChain.Vals.Validators[1].Address)
myExtValidator1Addr := myExtValidator1.String()
err := providerCli.ExecStakeRemote(myExtValidator1Addr, sdk.NewInt64Coin(x.ProviderDenom, 100_000_000))
err := providerCli.ExecStakeRemote(sender, myExtValidator1Addr, sdk.NewInt64Coin(x.ProviderDenom, 100_000_000))
require.NoError(t, err)
myExtValidator2 := sdk.ValAddress(x.ConsumerChain.Vals.Validators[2].Address)
myExtValidator2Addr := myExtValidator2.String()
err = providerCli.ExecStakeRemote(myExtValidator2Addr, sdk.NewInt64Coin(x.ProviderDenom, 50_000_000))
err = providerCli.ExecStakeRemote(sender, myExtValidator2Addr, sdk.NewInt64Coin(x.ProviderDenom, 50_000_000))
require.NoError(t, err)

require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))
Expand Down Expand Up @@ -91,6 +92,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

Expand All @@ -117,24 +119,24 @@ func TestSlashingScenario2(t *testing.T) {
// - We use millions instead of unit tokens.
x := setupExampleChains(t)
consumerCli, _, providerCli := setupMeshSecurity(t, x)

sender := x.ProviderChain.SenderAccount.GetAddress()
// Provider chain
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
execMsg := `{"bond":{}}`
providerCli.MustExecVault(execMsg, sdk.NewInt64Coin(x.ProviderDenom, 200_000_000))
providerCli.MustExecVault(sender, execMsg, sdk.NewInt64Coin(x.ProviderDenom, 200_000_000))

// Stake Locally - A user triggers a local staking action to a chosen validator.
myLocalValidatorAddr := sdk.ValAddress(x.ProviderChain.Vals.Validators[0].Address).String()
execLocalStakingMsg := fmt.Sprintf(`{"stake_local":{"amount": {"denom":%q, "amount":"%d"}, "msg":%q}}`,
x.ProviderDenom, 200_000_000,
base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"validator": "%s"}`, myLocalValidatorAddr))))
providerCli.MustExecVault(execLocalStakingMsg)
providerCli.MustExecVault(sender, execLocalStakingMsg)

// Cross Stake - A user pulls out additional liens on the same collateral "cross staking" it on different chains.
myExtValidator1 := sdk.ValAddress(x.ConsumerChain.Vals.Validators[1].Address)
myExtValidator1Addr := myExtValidator1.String()
err := providerCli.ExecStakeRemote(myExtValidator1Addr, sdk.NewInt64Coin(x.ProviderDenom, 200_000_000))
err := providerCli.ExecStakeRemote(sender, myExtValidator1Addr, sdk.NewInt64Coin(x.ProviderDenom, 200_000_000))
require.NoError(t, err)

require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))
Expand Down Expand Up @@ -178,6 +180,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

Expand All @@ -204,24 +207,24 @@ func TestSlashingScenario3(t *testing.T) {
// - We use millions instead of unit tokens.
x := setupExampleChains(t)
consumerCli, _, providerCli := setupMeshSecurity(t, x)

sender := x.ProviderChain.SenderAccount.GetAddress()
// Provider chain
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
execMsg := `{"bond":{}}`
providerCli.MustExecVault(execMsg, sdk.NewInt64Coin(x.ProviderDenom, 200_000_000))
providerCli.MustExecVault(sender, execMsg, sdk.NewInt64Coin(x.ProviderDenom, 200_000_000))

// Stake Locally - A user triggers a local staking action to a chosen validator.
myLocalValidatorAddr := sdk.ValAddress(x.ProviderChain.Vals.Validators[0].Address).String()
execLocalStakingMsg := fmt.Sprintf(`{"stake_local":{"amount": {"denom":%q, "amount":"%d"}, "msg":%q}}`,
x.ProviderDenom, 190_000_000,
base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf(`{"validator": "%s"}`, myLocalValidatorAddr))))
providerCli.MustExecVault(execLocalStakingMsg)
providerCli.MustExecVault(sender, execLocalStakingMsg)

// Cross Stake - A user pulls out additional liens on the same collateral "cross staking" it on different chains.
myExtValidator1 := sdk.ValAddress(x.ConsumerChain.Vals.Validators[1].Address)
myExtValidator1Addr := myExtValidator1.String()
err := providerCli.ExecStakeRemote(myExtValidator1Addr, sdk.NewInt64Coin(x.ProviderDenom, 150_000_000))
err := providerCli.ExecStakeRemote(sender, myExtValidator1Addr, sdk.NewInt64Coin(x.ProviderDenom, 150_000_000))
require.NoError(t, err)

require.NoError(t, x.Coordinator.RelayAndAckPendingPackets(x.IbcPath))
Expand Down Expand Up @@ -265,6 +268,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)

Expand Down
Loading
Loading