Skip to content

Commit

Permalink
Define new method to handle zero max cap
Browse files Browse the repository at this point in the history
  • Loading branch information
trinitys7 committed Jun 24, 2024
1 parent 3cdce6e commit bfe1849
Show file tree
Hide file tree
Showing 18 changed files with 745 additions and 228 deletions.
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) | | |






<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
2 changes: 2 additions & 0 deletions x/meshsecurity/contract/in_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ type (
}
BondMsg struct {
Amount wasmvmtypes.Coin `json:"amount"`
Delegator string `json:"delegator"`
Validator string `json:"validator"`
}
UnbondMsg struct {
Amount wasmvmtypes.Coin `json:"amount"`
Delegator string `json:"delegator"`
Validator string `json:"validator"`
}
)
34 changes: 31 additions & 3 deletions x/meshsecurity/contract/query.go
Original file line number Diff line number Diff line change
@@ -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"`
Expand All @@ -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
}
16 changes: 12 additions & 4 deletions x/meshsecurity/keeper/handler_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ 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, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error)
Undelegate(ctx sdk.Context, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) error
}

type CustomMsgHandler struct {
Expand Down Expand Up @@ -88,7 +88,11 @@ func (h CustomMsgHandler) handleBondMsg(ctx sdk.Context, actor sdk.AccAddress, b
if err != nil {
return nil, nil, err
}
_, err = h.k.Delegate(ctx, actor, valAddr, coin)
delAddr, err := sdk.AccAddressFromBech32(bondMsg.Delegator)
if err != nil {
return nil, nil, err
}
_, err = h.k.Delegate(ctx, actor, delAddr, valAddr, coin)
if err != nil {
return nil, nil, err
}
Expand All @@ -111,7 +115,11 @@ func (h CustomMsgHandler) handleUnbondMsg(ctx sdk.Context, actor sdk.AccAddress,
if err != nil {
return nil, nil, err
}
err = h.k.Undelegate(ctx, actor, valAddr, coin)
delAddr, err := sdk.AccAddressFromBech32(bondMsg.Delegator)
if err != nil {
return nil, nil, err
}
err = h.k.Undelegate(ctx, actor, delAddr, valAddr, coin)
if err != nil {
return nil, nil, err
}
Expand Down
41 changes: 21 additions & 20 deletions x/meshsecurity/keeper/handler_plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@ 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()))

specs := map[string]struct {
src wasmvmtypes.CosmosMsg
Expand All @@ -48,7 +49,7 @@ func TestCustomMeshSecDispatchMsg(t *testing.T) {
src: wasmvmtypes.CosmosMsg{Custom: validBondMsg},
auth: allAuthZ,
setup: func(t *testing.T) (msKeeper, func()) {
fn, asserts := captureDelegateCall(t, myContractAddr, myValidatorAddr, myAmount, sdk.OneDec())
fn, asserts := captureDelegateCall(t, myContractAddr, myDelegatorAddr, myValidatorAddr, myAmount, sdk.OneDec())
return &msKeeperMock{DelegateFn: fn}, asserts
},
expEvents: []sdk.Event{sdk.NewEvent("instant_delegate",
Expand All @@ -62,7 +63,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, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error) {
return sdk.ZeroDec(), myErr
}}
return &m, t.FailNow
Expand All @@ -73,7 +74,7 @@ func TestCustomMeshSecDispatchMsg(t *testing.T) {
src: wasmvmtypes.CosmosMsg{Custom: validUnbondMsg},
auth: allAuthZ,
setup: func(t *testing.T) (msKeeper, func()) {
fn, asserts := captureCall(t, myContractAddr, myValidatorAddr, myAmount)
fn, asserts := captureCall(t, myContractAddr, myDelegatorAddr, myValidatorAddr, myAmount)
return &msKeeperMock{UndelegateFn: fn}, asserts
},
expEvents: []sdk.Event{sdk.NewEvent("instant_unbond",
Expand All @@ -87,7 +88,7 @@ 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, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) error {
return myErr
}}
return &m, t.FailNow
Expand Down Expand Up @@ -153,19 +154,19 @@ func TestCustomMeshSecDispatchMsg(t *testing.T) {
}
}

func captureDelegateCall(t *testing.T, myContractAddr sdk.AccAddress, myValidatorAddr sdk.ValAddress, expCoin sdk.Coin, retShare sdk.Dec) (func(_ sdk.Context, actor sdk.AccAddress, val sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error), func()) {
fn, asserts := captureCall(t, myContractAddr, myValidatorAddr, expCoin)
return func(ctx sdk.Context, actor sdk.AccAddress, val sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error) {
return retShare, fn(ctx, actor, val, coin)
func captureDelegateCall(t *testing.T, myContractAddr, myDelegatorAddr sdk.AccAddress, myValidatorAddr sdk.ValAddress, expCoin sdk.Coin, retShare sdk.Dec) (func(_ sdk.Context, actor, del sdk.AccAddress, val sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error), func()) {
fn, asserts := captureCall(t, myContractAddr, myDelegatorAddr, myValidatorAddr, expCoin)
return func(ctx sdk.Context, actor, del sdk.AccAddress, val sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error) {
return retShare, fn(ctx, actor, del, val, coin)
}, asserts
}

func captureCall(t *testing.T, myContractAddr sdk.AccAddress, myValidatorAddr sdk.ValAddress, expCoin sdk.Coin) (func(_ sdk.Context, actor sdk.AccAddress, val sdk.ValAddress, coin sdk.Coin) error, func()) {
func captureCall(t *testing.T, myContractAddr, myDelegatorAddr sdk.AccAddress, myValidatorAddr sdk.ValAddress, expCoin sdk.Coin) (func(_ sdk.Context, actor, del sdk.AccAddress, val sdk.ValAddress, coin sdk.Coin) error, func()) {
var (
captureVal sdk.ValAddress
capturedAmount sdk.Coin
)
fn := func(_ sdk.Context, actor sdk.AccAddress, val sdk.ValAddress, coin sdk.Coin) error {
fn := func(_ sdk.Context, actor, del sdk.AccAddress, val sdk.ValAddress, coin sdk.Coin) error {
require.Equal(t, myContractAddr, actor)
captureVal = val
capturedAmount = coin
Expand All @@ -181,22 +182,22 @@ 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, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) (sdk.Dec, error)
UndelegateFn func(ctx sdk.Context, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress, coin sdk.Coin) 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, delAddr 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, delAddr, 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, delAddr 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, delAddr, valAddr, coin)
}

func TestIntegrityHandler(t *testing.T) {
Expand Down
60 changes: 60 additions & 0 deletions x/meshsecurity/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, storeKey storetypes.StoreKey, actor, delAddr sdk.AccAddress, valAddr sdk.ValAddress) types.Delegation {
store := ctx.KVStore(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, k.storeKey, actor, delAddr, valAddr)
newDelegation.Amount = newDelegation.Amount.Add(changeAmount)
if !newDelegation.Amount.IsPositive() {
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 {
Expand Down
Loading

0 comments on commit bfe1849

Please sign in to comment.