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: allow depositing vesting tokens in the vault #182

Merged
merged 4 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions demo/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ import (
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity"
meshseckeeper "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/keeper"
meshsectypes "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurity/types"
meshsecprov "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurityprovider"
meshsecprovkeeper "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurityprovider/keeper"
meshsecprovtypes "github.com/osmosis-labs/mesh-security-sdk/x/meshsecurityprovider/types"
)

const appName = "MeshApp"
Expand Down Expand Up @@ -200,6 +203,7 @@ var (
ica.AppModuleBasic{},
ibcfee.AppModuleBasic{},
meshsecurity.AppModuleBasic{},
meshsecprov.AppModuleBasic{},
)

// module account permissions
Expand Down Expand Up @@ -263,6 +267,7 @@ type MeshApp struct {
TransferKeeper ibctransferkeeper.Keeper
WasmKeeper wasmkeeper.Keeper
MeshSecKeeper *meshseckeeper.Keeper
MeshSecProvKeeper *meshsecprovkeeper.Keeper

ScopedIBCKeeper capabilitykeeper.ScopedKeeper
ScopedICAHostKeeper capabilitykeeper.ScopedKeeper
Expand Down Expand Up @@ -314,6 +319,7 @@ func NewMeshApp(
wasmtypes.StoreKey, icahosttypes.StoreKey,
icacontrollertypes.StoreKey,
meshsectypes.StoreKey,
meshsecprovtypes.StoreKey,
)

tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey)
Expand Down Expand Up @@ -417,6 +423,15 @@ func NewMeshApp(
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

app.MeshSecProvKeeper = meshsecprovkeeper.NewKeeper(
appCodec,
keys[meshsecprovtypes.StoreKey],
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
app.BankKeeper,
app.WasmKeeper,
app.StakingKeeper,
)

app.SlashingKeeper = slashingkeeper.NewKeeper(
appCodec,
legacyAmino,
Expand Down Expand Up @@ -589,6 +604,7 @@ func NewMeshApp(
nested,
// append our custom message handler for mesh-security
meshseckeeper.NewDefaultCustomMsgHandler(app.MeshSecKeeper),
meshsecprovkeeper.CustomMessageDecorator(app.MeshSecProvKeeper),
)
})
wasmOpts = append(wasmOpts, meshMessageHandler,
Expand Down Expand Up @@ -694,6 +710,7 @@ func NewMeshApp(
ibcfee.NewAppModule(app.IBCFeeKeeper),
ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper),
meshsecurity.NewAppModule(appCodec, app.MeshSecKeeper),
meshsecprov.NewAppModule(app.MeshSecProvKeeper),
crisis.NewAppModule(app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), // always be last to make sure that it checks for all invariants and not only part of them
)

Expand All @@ -715,6 +732,7 @@ func NewMeshApp(
ibcfeetypes.ModuleName,
wasmtypes.ModuleName,
meshsectypes.ModuleName,
meshsecprovtypes.ModuleName,
)

app.ModuleManager.SetOrderEndBlockers(
Expand All @@ -731,6 +749,7 @@ func NewMeshApp(
ibcfeetypes.ModuleName,
wasmtypes.ModuleName,
meshsectypes.ModuleName, // last to capture all chain events
meshsecprovtypes.ModuleName,
)

// NOTE: The genutils module must occur after staking so that pools are
Expand All @@ -755,6 +774,7 @@ func NewMeshApp(
// wasm after ibc transfer
wasmtypes.ModuleName,
meshsectypes.ModuleName,
meshsecprovtypes.ModuleName,
}
app.ModuleManager.SetOrderInitGenesis(genesisModuleOrder...)
app.ModuleManager.SetOrderExportGenesis(genesisModuleOrder...)
Expand Down
Binary file added demo/build/meshd
Binary file not shown.
4 changes: 3 additions & 1 deletion tests/e2e/e2e.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ type example struct {
ConsumerChain *ibctesting.TestChain
ProviderChain *ibctesting.TestChain
ConsumerApp *app.MeshApp
ProviderApp *app.MeshApp
IbcPath *ibctesting.Path
ProviderDenom string
ConsumerDenom string
Expand All @@ -114,6 +115,7 @@ func setupExampleChains(t *testing.T) example {
ConsumerChain: consChain,
ProviderChain: provChain,
ConsumerApp: consChain.App.(*app.MeshApp),
ProviderApp: provChain.App.(*app.MeshApp),
IbcPath: ibctesting.NewPath(consChain, provChain),
ProviderDenom: sdk.DefaultBondDenom,
ConsumerDenom: sdk.DefaultBondDenom,
Expand All @@ -132,7 +134,7 @@ func setupMeshSecurity(t *testing.T, x example) (*TestConsumerClient, ConsumerCo
x.ConsumerChain.DefaultMsgFees = sdk.NewCoins(sdk.NewCoin(x.ConsumerDenom, math.NewInt(1_000_000)))

providerCli := NewProviderClient(t, x.ProviderChain)
providerContracts := providerCli.BootstrapContracts(x.IbcPath.EndpointA.ConnectionID, converterPortID)
providerContracts := providerCli.BootstrapContracts(x.ProviderApp, x.IbcPath.EndpointA.ConnectionID, converterPortID)

// setup ibc control path: consumer -> provider (direction matters)
x.IbcPath.EndpointB.ChannelConfig = &ibctesting2.ChannelConfig{
Expand Down
4 changes: 2 additions & 2 deletions tests/e2e/mvp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ func TestMVP(t *testing.T) {
// 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, 100_000_000))
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())
Expand Down
12 changes: 6 additions & 6 deletions tests/e2e/slashing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ func TestSlashingScenario1(t *testing.T) {
// 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))
execMsg := fmt.Sprintf(`{"bond":{"amount":{"denom":"%s", "amount":"200000000"}}}`, x.ProviderDenom)
providerCli.MustExecVault(execMsg)

// Stake Locally - A user triggers a local staking action to a chosen validator.
myLocalValidatorAddr := sdk.ValAddress(x.ProviderChain.Vals.Validators[0].Address).String()
Expand Down Expand Up @@ -121,8 +121,8 @@ func TestSlashingScenario2(t *testing.T) {
// 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))
execMsg := fmt.Sprintf(`{"bond":{"amount":{"denom":"%s", "amount":"200000000"}}}`, x.ProviderDenom)
providerCli.MustExecVault(execMsg)

// Stake Locally - A user triggers a local staking action to a chosen validator.
myLocalValidatorAddr := sdk.ValAddress(x.ProviderChain.Vals.Validators[0].Address).String()
Expand Down Expand Up @@ -208,8 +208,8 @@ func TestSlashingScenario3(t *testing.T) {
// 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))
execMsg := fmt.Sprintf(`{"bond":{"amount":{"denom":"%s", "amount":"200000000"}}}`, x.ProviderDenom)
providerCli.MustExecVault(execMsg)

// Stake Locally - A user triggers a local staking action to a chosen validator.
myLocalValidatorAddr := sdk.ValAddress(x.ProviderChain.Vals.Validators[0].Address).String()
Expand Down
8 changes: 5 additions & 3 deletions tests/e2e/test_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ type ProviderContracts struct {
externalStaking sdk.AccAddress
}

func (p *TestProviderClient) BootstrapContracts(connId, portID string) ProviderContracts {
var (
func (p *TestProviderClient) BootstrapContracts(provApp *app.MeshApp, connId, portID string) ProviderContracts { var (
unbondingPeriod = 21 * 24 * 60 * 60 // 21 days - make configurable?
localSlashRatioDoubleSign = "0.20"
localSlashRatioOffline = "0.10"
Expand All @@ -95,7 +94,10 @@ func (p *TestProviderClient) BootstrapContracts(connId, portID string) ProviderC
nativeInitMsg := []byte(fmt.Sprintf(`{"denom": %q, "proxy_code_id": %d, "slash_ratio_dsign": %q, "slash_ratio_offline": %q }`, localTokenDenom, proxyCodeID, localSlashRatioDoubleSign, localSlashRatioOffline))
initMsg := []byte(fmt.Sprintf(`{"denom": %q, "local_staking": {"code_id": %d, "msg": %q}}`, localTokenDenom, nativeStakingCodeID, base64.StdEncoding.EncodeToString(nativeInitMsg)))
vaultContract := InstantiateContract(p.t, p.chain, vaultCodeID, initMsg)

ctx := p.chain.GetContext()
params := provApp.MeshSecProvKeeper.GetParams(ctx)
params.VaultAddress = vaultContract.String()
provApp.MeshSecProvKeeper.SetParams(ctx, params)
// external staking
extStakingCodeID := p.chain.StoreCodeFile(buildPathToWasm("mesh_external_staking.wasm")).CodeID
initMsg = []byte(fmt.Sprintf(
Expand Down
8 changes: 4 additions & 4 deletions tests/starship/mvp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ func Test2WayContract(t *testing.T) {
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
fmt.Println("provider chain: deposit vault denom to provide some collateral to account")
execMsg := `{"bond":{}}`
vault, err := providerClient1.MustExecVault(execMsg, sdk.NewInt64Coin(providerClient1.Chain.Denom, 100_000_000))
execMsg := fmt.Sprintf(`{"bond":{"amount":{"denom":"%s", "amount":"100000000"}}}`, providerClient1.Chain.Denom)
vault, err := providerClient1.MustExecVault(execMsg)
require.NoError(t, err)
require.NotEmpty(t, vault)

Expand Down Expand Up @@ -130,8 +130,8 @@ func Test2WayContract(t *testing.T) {
// ==============
// Deposit - A user deposits the vault denom to provide some collateral to their account
fmt.Println("provider chain: deposit vault denom to provide some collateral to account")
execMsg = `{"bond":{}}`
vault, err = providerClient2.MustExecVault(execMsg, sdk.NewInt64Coin(providerClient2.Chain.Denom, 100_000_000))
execMsg = fmt.Sprintf(`{"bond":{"amount":{"denom":"%s", "amount":"100000000"}}}`, providerClient2.Chain.Denom)
vault, err = providerClient2.MustExecVault(execMsg)
require.NoError(t, err)
require.NotEmpty(t, vault)

Expand Down
6 changes: 3 additions & 3 deletions tests/testdata/copy_local_wasm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ command -v shellcheck > /dev/null && shellcheck "$0"

echo "DEV-only: copy from local built instead of downloading"

for contract in 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_simple_price_feed \
mesh_vault mesh_virtual_staking ; do
cp -f ../../../../mesh-security/artifacts/${contract}.wasm .
cp -f ../../../mesh-security/artifacts/${contract}.wasm .
gzip -fk ${contract}.wasm
rm -f ${contract}.wasm
done

cd ../../../../mesh-security
cd ../../../mesh-security
tag=$(git rev-parse HEAD)
cd -
rm -f version.txt
Expand Down
Binary file modified tests/testdata/mesh_converter.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_external_staking.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_native_staking.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_native_staking_proxy.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_simple_price_feed.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_vault.wasm.gz
Binary file not shown.
Binary file modified tests/testdata/mesh_virtual_staking.wasm.gz
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/testdata/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.10.0-alpha.1
34284a38601ff132e8d7b5594a87794faa71bbed
2 changes: 1 addition & 1 deletion x/meshsecurity/abci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func TestEndBlocker(t *testing.T) {
assert: func(t *testing.T, ctx sdk.Context) {
require.Len(t, capturedCalls, 2)
assert.Equal(t, myContractAddr, capturedCalls[0].contractAddress)
exp := fmt.Sprintf(`{"valset_update":{"additions":[{"address":"%s","commission":"0.000000000000000000","max_commission":"0.000000000000000000","max_change_rate":"0.000000000000000000"}],"removals":[],"updated":[],"jailed":[],"unjailed":[],"slashed":[],"tombstoned":[]}}`, val1.GetOperator())
exp := fmt.Sprintf(`{"handle_valset_update":{"additions":[{"address":"%s","commission":"0.000000000000000000","max_commission":"0.000000000000000000","max_change_rate":"0.000000000000000000"}],"removals":[],"updated":[],"jailed":[],"unjailed":[],"slashed":[],"tombstoned":[]}}`, val1.GetOperator())
assert.JSONEq(t, exp, string(capturedCalls[0].msg))

assert.Equal(t, myOtherContractAddr, capturedCalls[1].contractAddress)
Expand Down
2 changes: 1 addition & 1 deletion x/meshsecurity/contract/out_message.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
type (
SudoMsg struct {
HandleEpoch *struct{} `json:"handle_epoch,omitempty"`
ValsetUpdate *ValsetUpdate `json:"valset_update,omitempty"`
ValsetUpdate *ValsetUpdate `json:"handle_valset_update,omitempty"`
}

// Validator alias to wasmVM type
Expand Down
21 changes: 21 additions & 0 deletions x/meshsecurityprovider/contract/in_message.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package contract

import wasmvmtypes "github.com/CosmWasm/wasmvm/types"

type (
CustomMsg struct {
Provider *ProviderMsg `json:"provider,omitempty"`
}
ProviderMsg struct {
Bond *BondMsg `json:"bond,omitempty"`
Unbond *UnbondMsg `json:"unbond,omitempty"`
}
BondMsg struct {
Amount wasmvmtypes.Coin `json:"amount"`
Delegator string `json:"delegator"`
}
UnbondMsg struct {
Amount wasmvmtypes.Coin `json:"amount"`
Delegator string `json:"delegator"`
}
)
51 changes: 51 additions & 0 deletions x/meshsecurityprovider/keeper/handle_plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package keeper

import (
"encoding/json"

wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurityprovider/contract"
)

type CustomMessenger struct {
k *Keeper
}


// CustomMessageDecorator returns decorator for custom CosmWasm bindings messages
func CustomMessageDecorator(provKeeper *Keeper) *CustomMessenger {
return &CustomMessenger{
k: provKeeper,
}
}

var _ wasmkeeper.Messenger = (*CustomMessenger)(nil)

// DispatchMsg executes on the contractMsg.
func (h CustomMessenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, _ string, msg wasmvmtypes.CosmosMsg) ([]sdk.Event, [][]byte, error) {
if msg.Custom == nil {
return nil, nil, wasmtypes.ErrUnknownMsg
}
var customMsg contract.CustomMsg
if err := json.Unmarshal(msg.Custom, &customMsg); err != nil {
return nil, nil, sdkerrors.ErrJSONUnmarshal.Wrap("custom message")
}
if customMsg.Provider == nil {
// not our message type
return nil, nil, wasmtypes.ErrUnknownMsg
}
switch {
case customMsg.Provider.Bond != nil:
return h.k.HandleBondMsg(ctx, contractAddr, customMsg.Provider.Bond)
case customMsg.Provider.Unbond != nil:
return h.k.HandleUnbondMsg(ctx, contractAddr, customMsg.Provider.Unbond)
}
return nil, nil, wasmtypes.ErrUnknownMsg
}

59 changes: 59 additions & 0 deletions x/meshsecurityprovider/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ package keeper
import (
"github.com/cometbft/cometbft/libs/log"

wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurityprovider/contract"
"github.com/osmosis-labs/mesh-security-sdk/x/meshsecurityprovider/types"
)

Expand Down Expand Up @@ -88,3 +91,59 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
Params: k.GetParams(ctx),
}
}

func (k Keeper) HandleBondMsg(ctx sdk.Context, actor sdk.AccAddress, bondMsg *contract.BondMsg) ([]sdk.Event, [][]byte, error) {
if actor.String() != k.VaultAddress(ctx) {
return nil, nil, sdkerrors.ErrUnauthorized.Wrapf("contract has no permission for mesh security operations")
}

coin, err := wasmkeeper.ConvertWasmCoinToSdkCoin(bondMsg.Amount)
if err != nil {
return nil, nil, err
}

delAddr, err := sdk.AccAddressFromBech32(bondMsg.Delegator)
if err != nil {
return nil, nil, err
}

err = k.bankKeeper.DelegateCoins(ctx, delAddr, actor, sdk.NewCoins(coin))
if err != nil {
return nil, nil, err
}

return []sdk.Event{sdk.NewEvent(
types.EventTypeBond,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(sdk.AttributeKeyAmount, coin.String()),
sdk.NewAttribute(types.AttributeKeyDelegator, delAddr.String()),
)}, nil, nil
}

func (k Keeper) HandleUnbondMsg(ctx sdk.Context, actor sdk.AccAddress, unbondMsg *contract.UnbondMsg) ([]sdk.Event, [][]byte, error) {
if actor.String() != k.VaultAddress(ctx) {
return nil, nil, sdkerrors.ErrUnauthorized.Wrapf("contract has no permission for mesh security operations")
}

coin, err := wasmkeeper.ConvertWasmCoinToSdkCoin(unbondMsg.Amount)
if err != nil {
return nil, nil, err
}

delAddr, err := sdk.AccAddressFromBech32(unbondMsg.Delegator)
if err != nil {
return nil, nil, err
}

err = k.bankKeeper.UndelegateCoins(ctx, actor, delAddr, sdk.NewCoins(coin))
if err != nil {
return nil, nil, err
}

return []sdk.Event{sdk.NewEvent(
types.EventTypeUnbond,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(sdk.AttributeKeyAmount, coin.String()),
sdk.NewAttribute(types.AttributeKeyDelegator, delAddr.String()),
)}, nil, nil
}
Loading