Unverified Commit cc02e031 authored by antstalepresh's avatar antstalepresh Committed by GitHub
Browse files

Superfluid basic simulation, tx/query CLI commands, resolve single node test issues (#784)


* add basic changes for simulation

* add superfluid message types

* register msg server, handler, fix build issues, configure basic actions for superfluid operations

* resolve message validatebasic, fix automatic delegation from intermediary account, increase simulation coverage

* Put superfluid unbonding duration as param, simulation test genesis manipulation

* add simulation for proposals

* add basic checker for superfluid operations

* update reward management logic

* add tx commands for superfluid delegate

* add cli commands for proposals

* single node configuration as epoch - min and relevant times

* resolve twap price issue, synthetic lockup distribution, connect epochs hook to superfluid, fix gauge creation issue

* fix simulation weights

* superfluid lockup ownership check & error handling & queries & addTokensToLock/removeTokensFromLock connection with synthetic lockup

* add more test plans

* further test steps

* Add SuperfluidDelegateMore feature, Add common codebase for GetSuperfluidOSMOTokens from twap

* simplify epoch management & resolve unit tests

* add missing queries and unit tests

* resolve accumulation store management issue for synthetic lockup

* PR cleanup

* remove reward distribution delay, fix superfluid asset removal price

* Fix gas tests

Co-authored-by: default avatarValarDragon <dojha12@gmail.com>
parent e8642532
Showing with 691 additions and 62 deletions
+691 -62
......@@ -178,6 +178,7 @@ import (
// Superfluid: Allows users to stake gamm (bonded liquidity)
superfluid "github.com/osmosis-labs/osmosis/x/superfluid"
superfluidclient "github.com/osmosis-labs/osmosis/x/superfluid/client"
superfluidkeeper "github.com/osmosis-labs/osmosis/x/superfluid/keeper"
superfluidtypes "github.com/osmosis-labs/osmosis/x/superfluid/types"
......@@ -249,7 +250,8 @@ var (
wasmclient.ProposalHandlers,
paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler,
poolincentivesclient.UpdatePoolIncentivesHandler,
ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler)...,
ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler,
superfluidclient.SetSuperfluidAssetsProposalHandler, superfluidclient.RemoveSuperfluidAssetsProposalHandler)...,
),
params.AppModuleBasic{},
crisis.AppModuleBasic{},
......@@ -484,7 +486,7 @@ func NewOsmosisApp(
lockup.NewAppModule(appCodec, *app.LockupKeeper, app.AccountKeeper, app.BankKeeper),
poolincentives.NewAppModule(appCodec, *app.PoolIncentivesKeeper),
epochs.NewAppModule(appCodec, *app.EpochsKeeper),
superfluid.NewAppModule(appCodec, app.SuperfluidKeeper, app.AccountKeeper, app.BankKeeper),
superfluid.NewAppModule(appCodec, app.SuperfluidKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.LockupKeeper, app.GAMMKeeper),
bech32ibc.NewAppModule(appCodec, *app.Bech32IBCKeeper),
)
......@@ -602,7 +604,7 @@ func NewOsmosisApp(
lockup.NewAppModule(appCodec, *app.LockupKeeper, app.AccountKeeper, app.BankKeeper),
poolincentives.NewAppModule(appCodec, *app.PoolIncentivesKeeper),
epochs.NewAppModule(appCodec, *app.EpochsKeeper),
superfluid.NewAppModule(appCodec, app.SuperfluidKeeper, app.AccountKeeper, app.BankKeeper),
superfluid.NewAppModule(appCodec, app.SuperfluidKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper, app.LockupKeeper, app.GAMMKeeper),
app.transferModule,
)
......
......@@ -61,6 +61,7 @@ import (
poolincentives "github.com/osmosis-labs/osmosis/x/pool-incentives"
poolincentiveskeeper "github.com/osmosis-labs/osmosis/x/pool-incentives/keeper"
poolincentivestypes "github.com/osmosis-labs/osmosis/x/pool-incentives/types"
superfluid "github.com/osmosis-labs/osmosis/x/superfluid"
superfluidkeeper "github.com/osmosis-labs/osmosis/x/superfluid/keeper"
superfluidtypes "github.com/osmosis-labs/osmosis/x/superfluid/types"
"github.com/osmosis-labs/osmosis/x/txfees"
......@@ -314,7 +315,8 @@ func (app *OsmosisApp) InitNormalKeepers(
AddRoute(ibchost.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)).
AddRoute(poolincentivestypes.RouterKey, poolincentives.NewPoolIncentivesProposalHandler(*app.PoolIncentivesKeeper)).
AddRoute(bech32ibctypes.RouterKey, bech32ibc.NewBech32IBCProposalHandler(*app.Bech32IBCKeeper)).
AddRoute(txfeestypes.RouterKey, txfees.NewUpdateFeeTokenProposalHandler(*app.TxFeesKeeper))
AddRoute(txfeestypes.RouterKey, txfees.NewUpdateFeeTokenProposalHandler(*app.TxFeesKeeper)).
AddRoute(superfluidtypes.RouterKey, superfluid.NewSuperfluidProposalHandler(app.SuperfluidKeeper))
// The gov proposal types can be individually enabled
if len(wasmEnabledProposals) != 0 {
......@@ -374,6 +376,7 @@ func (app *OsmosisApp) SetupHooks() {
app.EpochsKeeper.SetHooks(
epochstypes.NewMultiEpochHooks(
// insert epoch hooks receivers here
app.SuperfluidKeeper.Hooks(),
app.IncentivesKeeper.Hooks(),
app.MintKeeper.Hooks(),
),
......
......@@ -7,16 +7,6 @@ import "osmosis/superfluid/params.proto";
option go_package = "github.com/osmosis-labs/osmosis/x/superfluid/types";
message EpochOsmoEquivalentTWAP {
int64 epoch_number = 1;
string denom = 2; // superfluid asset denom, can be LP token or native token
string epoch_twap_price = 3 [
(gogoproto.moretags) = "yaml:\"epoch_twap_price\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
// GenesisState defines the module's genesis state.
message GenesisState {
Params params = 1 [ (gogoproto.nullable) = false ];
......
......@@ -2,6 +2,7 @@ syntax = "proto3";
package osmosis.superfluid;
import "gogoproto/gogo.proto";
import "google/protobuf/duration.proto";
option go_package = "github.com/osmosis-labs/osmosis/x/superfluid/types";
......@@ -16,4 +17,10 @@ message Params {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// unbonding duration of superfluid delegation
google.protobuf.Duration unbonding_duration = 3 [
(gogoproto.stdduration) = true,
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"unbonding_duration\""
];
}
......@@ -7,6 +7,7 @@ import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/duration.proto";
import "osmosis/superfluid/superfluid.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
option go_package = "github.com/osmosis-labs/osmosis/x/superfluid/types";
......@@ -16,10 +17,22 @@ service Query {
rpc AssetType(AssetTypeRequest) returns (AssetTypeResponse) {
option (google.api.http).get = "/osmosis/superfluid/v1beta1/asset_type/{denom}";
}
// Returns all superfluid assets info
// Returns all superfluid asset types
rpc AllAssets(AllAssetsRequest) returns (AllAssetsResponse) {
option (google.api.http).get = "/osmosis/superfluid/v1beta1/all_assets";
}
// Returns superfluid asset TWAP
rpc AssetTwap(AssetTwapRequest) returns (AssetTwapResponse) {
option (google.api.http).get = "/osmosis/superfluid/v1beta1/asset_twap/{denom}";
}
// Returns all superfluid intermediary account
rpc AllIntermediaryAccounts(AllIntermediaryAccountsRequest) returns (AllIntermediaryAccountsResponse) {
option (google.api.http).get = "/osmosis/superfluid/v1beta1/all_intermediary_accounts";
}
// Returns intermediary account connected to a superfluid staked lock by id
rpc ConnectedIntermediaryAccount(ConnectedIntermediaryAccountRequest) returns (ConnectedIntermediaryAccountResponse) {
option (google.api.http).get = "/osmosis/superfluid/v1beta1/connected_intermediary_account/{lock_id}";
}
}
message AssetTypeRequest {
......@@ -33,3 +46,31 @@ message AllAssetsRequest {};
message AllAssetsResponse {
repeated SuperfluidAsset assets = 1 [(gogoproto.nullable) = false];
};
message AssetTwapRequest {
string denom = 1;
};
message AssetTwapResponse {
EpochOsmoEquivalentTWAP twap = 1;
};
message SuperfluidIntermediaryAccountInfo {
string denom = 1;
string val_addr = 2;
uint64 gauge_id = 3;
string address = 4;
}
message AllIntermediaryAccountsRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
};
message AllIntermediaryAccountsResponse {
repeated SuperfluidIntermediaryAccountInfo accounts = 1 [ (gogoproto.nullable) = false ];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
};
message ConnectedIntermediaryAccountRequest {
uint64 lock_id = 1;
}
message ConnectedIntermediaryAccountResponse {
SuperfluidIntermediaryAccountInfo account = 1;
}
......@@ -29,6 +29,15 @@ message SuperfluidAsset {
message SuperfluidIntermediaryAccount {
string denom = 1;
string val_addr = 2;
// id of perpetual gauge to send rewards to for distribution
uint64 gauge_id = 3;
uint64 gauge_id = 3; // perpetual gauge for rewards distribution
}
message EpochOsmoEquivalentTWAP {
int64 epoch_number = 1;
string denom = 2; // superfluid asset denom, can be LP token or native token
string epoch_twap_price = 3 [
(gogoproto.moretags) = "yaml:\"epoch_twap_price\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
......@@ -10,7 +10,30 @@ option go_package = "github.com/osmosis-labs/osmosis/x/superfluid/types";
// Msg defines the Msg service.
service Msg {
// Execute superfluid delegation for a lockup
rpc SuperfluidDelegate(MsgSuperfluidDelegate) returns (MsgSuperfluidDelegateResponse);
// Execute superfluid undelegation for a lockup
rpc SuperfluidUndelegate(MsgSuperfluidUndelegate) returns (MsgSuperfluidUndelegateResponse);
// Execute superfluid redelegation for a lockup
rpc SuperfluidRedelegate(MsgSuperfluidRedelegate) returns (MsgSuperfluidRedelegateResponse);
}
// For now, module just supports gov messages
message MsgSuperfluidDelegate {
string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ];
uint64 lock_id = 2;
string val_addr = 3;
}
message MsgSuperfluidDelegateResponse { }
message MsgSuperfluidUndelegate {
string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ];
uint64 lock_id = 2;
}
message MsgSuperfluidUndelegateResponse { }
message MsgSuperfluidRedelegate {
string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ];
uint64 lock_id = 2;
string new_val_addr = 3;
}
message MsgSuperfluidRedelegateResponse {}
......@@ -6,10 +6,40 @@ cd $HOME
osmosisd init --chain-id=testing testing --home=$HOME/.osmosisd
osmosisd keys add validator --keyring-backend=test --home=$HOME/.osmosisd
osmosisd add-genesis-account $(osmosisd keys show validator -a --keyring-backend=test --home=$HOME/.osmosisd) 1000000000stake,1000000000valtoken --home=$HOME/.osmosisd
osmosisd add-genesis-account $(osmosisd keys show validator -a --keyring-backend=test --home=$HOME/.osmosisd) 100000000000stake,100000000000valtoken --home=$HOME/.osmosisd
osmosisd gentx validator 500000000stake --keyring-backend=test --home=$HOME/.osmosisd --chain-id=testing
osmosisd collect-gentxs --home=$HOME/.osmosisd
# update staking genesis
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["staking"]["params"]["unbonding_time"]="120s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
# update governance genesis
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["gov"]["voting_params"]["voting_period"]="10s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
# update epochs genesis
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["epochs"]["epochs"][0]["identifier"]="min"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["epochs"]["epochs"][0]["duration"]="60s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
# update poolincentives genesis
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["poolincentives"]["lockable_durations"][0]="120s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["poolincentives"]["lockable_durations"][1]="180s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["poolincentives"]["lockable_durations"][2]="240s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
# update incentives genesis
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["incentives"]["params"]["distr_epoch_identifier"]="min"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["incentives"]["lockable_durations"][0]="1s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["incentives"]["lockable_durations"][1]="120s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["incentives"]["lockable_durations"][2]="180s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["incentives"]["lockable_durations"][3]="240s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
# update mint genesis
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["mint"]["params"]["epoch_identifier"]="min"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
# update gamm genesis
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["gamm"]["params"]["pool_creation_fee"][0]["denom"]="stake"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
# update superfluid genesis
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["superfluid"]["params"]["refresh_epoch_identifier"]="min"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
cat $HOME/.osmosisd/config/genesis.json | jq '.app_state["superfluid"]["params"]["unbonding_duration"]="120s"' > $HOME/.osmosisd/config/tmp_genesis.json && mv $HOME/.osmosisd/config/tmp_genesis.json $HOME/.osmosisd/config/genesis.json
osmosisd start --home=$HOME/.osmosisd
......@@ -32,6 +32,15 @@ func RandomizedGenState(simState *module.SimulationState) {
CurrentEpochStartTime: time.Time{},
EpochCountingStarted: false,
},
{
Identifier: "second",
StartTime: time.Time{},
Duration: time.Second,
CurrentEpoch: 0,
CurrentEpochStartHeight: 0,
CurrentEpochStartTime: time.Time{},
EpochCountingStarted: false,
},
}
epochGenesis := types.NewGenesisState(epochs)
......
......@@ -20,7 +20,6 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
......@@ -31,7 +30,6 @@ var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
var _ = metadata.Join
var (
filter_Query_Pools_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
......@@ -540,14 +538,12 @@ func local_request_Query_EstimateSwapExactAmountOut_0(ctx context.Context, marsh
// RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
// UnaryRPC :call QueryServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead.
// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead.
func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error {
mux.Handle("GET", pattern_Query_Pools_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -555,7 +551,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_Pools_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -569,8 +564,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_NumPools_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -578,7 +571,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_NumPools_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -592,8 +584,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_TotalLiquidity_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -601,7 +591,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_TotalLiquidity_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -615,8 +604,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_Pool_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -624,7 +611,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_Pool_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -638,8 +624,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_PoolParams_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -647,7 +631,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_PoolParams_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -661,8 +644,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_TotalShares_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -670,7 +651,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_TotalShares_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -684,8 +664,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_PoolAssets_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -693,7 +671,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_PoolAssets_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -707,8 +684,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_SpotPrice_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -716,7 +691,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_SpotPrice_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -730,8 +704,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_EstimateSwapExactAmountIn_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -739,7 +711,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_EstimateSwapExactAmountIn_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......@@ -753,8 +724,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
mux.Handle("GET", pattern_Query_EstimateSwapExactAmountOut_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
......@@ -762,7 +731,6 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
return
}
resp, md, err := local_request_Query_EstimateSwapExactAmountOut_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
......
......@@ -221,7 +221,8 @@ func (k Keeper) doDistributionSends(ctx sdk.Context, distrs *distributionInfo) e
func (k Keeper) distributeInternal(
ctx sdk.Context, gauge types.Gauge, locks []lockuptypes.PeriodLock, distrInfo *distributionInfo) (sdk.Coins, error) {
totalDistrCoins := sdk.NewCoins()
lockSum := lockuptypes.SumLocksByDenom(locks, gauge.DistributeTo.Denom)
denom := lockuptypes.NativeDenom(gauge.DistributeTo.Denom)
lockSum := lockuptypes.SumLocksByDenom(locks, denom)
if lockSum.IsZero() {
return nil, nil
......@@ -237,7 +238,7 @@ func (k Keeper) distributeInternal(
distrCoins := sdk.Coins{}
for _, coin := range remainCoins {
// distribution amount = gauge_size * denom_lock_amount / (total_denom_lock_amount * remain_epochs)
denomLockAmt := lock.Coins.AmountOfNoDenomValidation(gauge.DistributeTo.Denom)
denomLockAmt := lock.Coins.AmountOfNoDenomValidation(denom)
amt := coin.Amount.Mul(denomLockAmt).Quo(lockSum.Mul(sdk.NewInt(int64(remainEpochs))))
if amt.IsPositive() {
newlyDistributedCoin := sdk.Coin{Denom: coin.Denom, Amount: amt}
......
......@@ -56,15 +56,15 @@ func (suite *KeeperTestSuite) TestRepeatedLockTokensGas() {
totalNumLocks := 10000
firstLockGasAmount := suite.measureLockGas(defaultAddr, defaultCoins, time.Second)
suite.Assert().Equal(86844, int(firstLockGasAmount))
suite.Assert().Equal(87871, int(firstLockGasAmount))
for i := 1; i < startAveragingAt; i++ {
suite.LockTokens(defaultAddr, defaultCoins, time.Second)
}
avgGas, maxGas := suite.measureAvgAndMaxLockGas(totalNumLocks-startAveragingAt, defaultAddr, coinsFn, durFn)
fmt.Printf("test deets: total locks created %d, begin average at %d\n", totalNumLocks, startAveragingAt)
suite.Assert().Equal(74047, int(avgGas), "average gas / lock")
suite.Assert().Equal(74137, int(maxGas), "max gas / lock")
suite.Assert().Equal(75074, int(avgGas), "average gas / lock")
suite.Assert().Equal(75164, int(maxGas), "max gas / lock")
}
func (suite *KeeperTestSuite) TestRepeatedLockTokensDistinctDurationGas() {
......@@ -76,6 +76,6 @@ func (suite *KeeperTestSuite) TestRepeatedLockTokensDistinctDurationGas() {
avgGas, maxGas := suite.measureAvgAndMaxLockGas(totalNumLocks, defaultAddr, coinsFn, durFn)
fmt.Printf("test deets: total locks created %d\n", totalNumLocks)
suite.Assert().EqualValues(124222, int(avgGas), "average gas / lock")
suite.Assert().EqualValues(253920, int(maxGas), "max gas / lock")
suite.Assert().EqualValues(125249, int(avgGas), "average gas / lock")
suite.Assert().EqualValues(254947, int(maxGas), "max gas / lock")
}
......@@ -7,6 +7,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/gogo/protobuf/proto"
"github.com/osmosis-labs/osmosis/store"
"github.com/osmosis-labs/osmosis/x/lockup/types"
......@@ -279,7 +280,7 @@ func (k Keeper) GetLockByID(ctx sdk.Context, lockID uint64) (*types.PeriodLock,
store := ctx.KVStore(k.storeKey)
lockKey := lockStoreKey(lockID)
if !store.Has(lockKey) {
return nil, fmt.Errorf("lock with ID %d does not exist", lockID)
return nil, sdkerrors.Wrap(types.ErrLockupNotFound, fmt.Sprintf("lock with ID %d does not exist", lockID))
}
bz := store.Get(lockKey)
err := proto.Unmarshal(bz, &lock)
......@@ -346,11 +347,34 @@ func (k Keeper) addTokensToLock(ctx sdk.Context, lock *types.PeriodLock, coins s
k.accumulationStore(ctx, coin.Denom).Increase(accumulationKey(lock.Duration), coin.Amount)
}
// increase synthetic lockup's accumulation store
synthLocks := k.GetAllSyntheticLockupsByLockup(ctx, lock.ID)
// when synthetic lockup exists for the lockup, disallow adding different coins
if len(synthLocks) > 0 && len(lock.Coins) > 1 {
return fmt.Errorf("multiple tokens lockup is not allowed for superfluid")
}
// Note: since synthetic lockup deletion is using native lockup's coins to reduce accumulation store
// all the synthetic lockups' accumulation should be increased
// Note: as long as token denoms does not change, synthetic lockup references are not needed to change
for _, synthLock := range synthLocks {
sCoins := syntheticCoins(coins, synthLock.Suffix)
for _, coin := range sCoins {
// Note: we use native lock's duration on accumulation store
k.accumulationStore(ctx, coin.Denom).Increase(accumulationKey(lock.Duration), coin.Amount)
}
}
return nil
}
// removeTokensFromLock is called by lockup slash function - called by superfluid module only
func (k Keeper) removeTokensFromLock(ctx sdk.Context, lock *types.PeriodLock, coins sdk.Coins) error {
// TODO: how to handle full slash for both normal lockup
// TODO: how to handle full slash for superfluid delegated lockup?
lock.Coins = lock.Coins.Sub(coins)
err := k.setLock(ctx, *lock)
......@@ -363,6 +387,19 @@ func (k Keeper) removeTokensFromLock(ctx sdk.Context, lock *types.PeriodLock, co
k.accumulationStore(ctx, coin.Denom).Decrease(accumulationKey(lock.Duration), coin.Amount)
}
// increase synthetic lockup's accumulation store
synthLocks := k.GetAllSyntheticLockupsByLockup(ctx, lock.ID)
// Note: since synthetic lockup deletion is using native lockup's coins to reduce accumulation store
// all the synthetic lockups' accumulation should be decreased
for _, synthLock := range synthLocks {
sCoins := syntheticCoins(coins, synthLock.Suffix)
for _, coin := range sCoins {
// Note: we use native lock's duration on accumulation store
k.accumulationStore(ctx, coin.Denom).Decrease(accumulationKey(lock.Duration), coin.Amount)
}
}
return nil
}
......
......@@ -11,4 +11,5 @@ var (
ErrNotLockOwner = sdkerrors.Register(ModuleName, 1, "msg sender is not the owner of specified lock")
ErrSyntheticLockupAlreadyExists = sdkerrors.Register(ModuleName, 2, "synthetic lockup already exists for same lock and suffix")
ErrSyntheticDurationLongerThanNative = sdkerrors.Register(ModuleName, 3, "synthetic lockup duration should be shorter than native lockup duration")
ErrLockupNotFound = sdkerrors.Register(ModuleName, 4, "lockup not found")
)
......@@ -2,6 +2,7 @@ package types
import (
"fmt"
"strings"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
......@@ -34,3 +35,14 @@ func SumLocksByDenom(locks []PeriodLock, denom string) sdk.Int {
}
return sum
}
// quick fix for getting native denom from synthetic denom
func NativeDenom(denom string) string {
if strings.Contains(denom, "superbonding") {
return strings.Split(denom, "superbonding")[0]
}
if strings.Contains(denom, "superunbonding") {
return strings.Split(denom, "superunbonding")[0]
}
return denom
}
package cli
// Proposal flags
const (
FlagSuperfluidAssets = "superfluid-assets"
)
......@@ -2,8 +2,12 @@ package cli
import (
"fmt"
"strconv"
"strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/version"
"github.com/osmosis-labs/osmosis/x/superfluid/types"
"github.com/spf13/cobra"
)
......@@ -19,7 +23,173 @@ func GetQueryCmd(queryRoute string) *cobra.Command {
RunE: client.ValidateCmd,
}
cmd.AddCommand()
cmd.AddCommand(
GetCmdAllSuperfluidAssets(),
GetCmdAssetTwap(),
GetCmdAllIntermediaryAccounts(),
GetCmdConnectedIntermediaryAccount(),
)
return cmd
}
// GetCmdAllSuperfluidAssets returns all superfluid enabled assets
func GetCmdAllSuperfluidAssets() *cobra.Command {
cmd := &cobra.Command{
Use: "all-superfluid-assets",
Short: "Query all superfluid assets",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all superfluid assets.
Example:
$ %s query superfluid all-superfluid-assets
`,
version.AppName,
),
),
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.AllAssets(cmd.Context(), &types.AllAssetsRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdAssetTwap returns twap of an asset by denom
func GetCmdAssetTwap() *cobra.Command {
cmd := &cobra.Command{
Use: "asset-twap [denom]",
Short: "Query asset twap by denom",
Long: strings.TrimSpace(
fmt.Sprintf(`Query asset twap by denom.
Example:
$ %s query superfluid asset-twap gamm/pool/1
`,
version.AppName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.AssetTwap(cmd.Context(), &types.AssetTwapRequest{
Denom: args[0],
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdAllIntermediaryAccounts returns all superfluid intermediary accounts
func GetCmdAllIntermediaryAccounts() *cobra.Command {
cmd := &cobra.Command{
Use: "all-intermediary-accounts",
Short: "Query all superfluid intermediary accounts",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all superfluid intermediary accounts.
Example:
$ %s query superfluid all-intermediary-accounts
`,
version.AppName,
),
),
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
res, err := queryClient.AllIntermediaryAccounts(cmd.Context(), &types.AllIntermediaryAccountsRequest{
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "superfluid")
return cmd
}
// GetCmdConnectedIntermediaryAccount returns connected intermediary account
func GetCmdConnectedIntermediaryAccount() *cobra.Command {
cmd := &cobra.Command{
Use: "connected-intermediary-account [lock_id]",
Short: "Query connected intermediary account",
Long: strings.TrimSpace(
fmt.Sprintf(`Query connected intermediary account.
Example:
$ %s query superfluid connected-intermediary-account 1
`,
version.AppName,
),
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
lockId, err := strconv.Atoi(args[0])
if err != nil {
return err
}
res, err := queryClient.ConnectedIntermediaryAccount(cmd.Context(), &types.ConnectedIntermediaryAccountRequest{
LockId: uint64(lockId),
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
......@@ -2,8 +2,15 @@ package cli
import (
"fmt"
"strconv"
"strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/osmosis-labs/osmosis/x/superfluid/types"
"github.com/spf13/cobra"
)
......@@ -18,7 +25,277 @@ func GetTxCmd() *cobra.Command {
RunE: client.ValidateCmd,
}
cmd.AddCommand()
cmd.AddCommand(
NewSuperfluidDelegateCmd(),
NewSuperfluidUndelegateCmd(),
NewSuperfluidRedelegateCmd(),
)
return cmd
}
// NewSuperfluidDelegateCmd broadcast MsgSuperfluidDelegate
func NewSuperfluidDelegateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "delegate [lock_id] [val_addr] [flags]",
Short: "superfluid delegate a lock to a validator",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)
lockId, err := strconv.Atoi(args[0])
if err != nil {
return err
}
valAddr, err := sdk.ValAddressFromBech32(args[1])
if err != nil {
return err
}
msg := types.NewMsgSuperfluidDelegate(
clientCtx.GetFromAddress(),
uint64(lockId),
valAddr,
)
return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewSuperfluidUndelegateCmd broadcast MsgSuperfluidUndelegate
func NewSuperfluidUndelegateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "undelegate [lock_id] [flags]",
Short: "superfluid undelegate a lock from a validator",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)
lockId, err := strconv.Atoi(args[0])
if err != nil {
return err
}
msg := types.NewMsgSuperfluidUndelegate(
clientCtx.GetFromAddress(),
uint64(lockId),
)
return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewSuperfluidRedelegateCmd broadcast MsgSuperfluidRedelegate
func NewSuperfluidRedelegateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "redelegate [lock_id] [val_addr] [flags]",
Short: "superfluid redelegate a lock to a new validator",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)
lockId, err := strconv.Atoi(args[0])
if err != nil {
return err
}
valAddr, err := sdk.ValAddressFromBech32(args[1])
if err != nil {
return err
}
msg := types.NewMsgSuperfluidRedelegate(
clientCtx.GetFromAddress(),
uint64(lockId),
valAddr,
)
return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewCmdSubmitSetSuperfluidAssetsProposal implements a command handler for submitting a superfluid asset set proposal transaction.
func NewCmdSubmitSetSuperfluidAssetsProposal() *cobra.Command {
cmd := &cobra.Command{
Use: "set-superfluid-assets-proposal [flags]",
Args: cobra.ExactArgs(0),
Short: "Submit a superfluid asset set proposal",
Long: "Submit a superfluid asset set proposal",
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
content, err := parseSetSuperfluidAssetsArgsToContent(cmd)
if err != nil {
return err
}
from := clientCtx.GetFromAddress()
depositStr, err := cmd.Flags().GetString(govcli.FlagDeposit)
if err != nil {
return err
}
deposit, err := sdk.ParseCoinsNormalized(depositStr)
if err != nil {
return err
}
msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from)
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().String(govcli.FlagTitle, "", "title of proposal")
cmd.Flags().String(govcli.FlagDescription, "", "description of proposal")
cmd.Flags().String(govcli.FlagDeposit, "", "deposit of proposal")
cmd.Flags().String(FlagSuperfluidAssets, "", "The superfluid asset array")
return cmd
}
// NewCmdSubmitRemoveSuperfluidAssetsProposal implements a command handler for submitting a superfluid asset remove proposal transaction.
func NewCmdSubmitRemoveSuperfluidAssetsProposal() *cobra.Command {
cmd := &cobra.Command{
Use: "remove-superfluid-assets-proposal [flags]",
Args: cobra.ExactArgs(0),
Short: "Submit a superfluid asset remove proposal",
Long: "Submit a superfluid asset remove proposal",
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
content, err := parseRemoveSuperfluidAssetsArgsToContent(cmd)
if err != nil {
return err
}
from := clientCtx.GetFromAddress()
depositStr, err := cmd.Flags().GetString(govcli.FlagDeposit)
if err != nil {
return err
}
deposit, err := sdk.ParseCoinsNormalized(depositStr)
if err != nil {
return err
}
msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from)
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().String(govcli.FlagTitle, "", "title of proposal")
cmd.Flags().String(govcli.FlagDescription, "", "description of proposal")
cmd.Flags().String(govcli.FlagDeposit, "", "deposit of proposal")
cmd.Flags().String(FlagSuperfluidAssets, "", "The superfluid asset array")
return cmd
}
func parseSetSuperfluidAssetsArgsToContent(cmd *cobra.Command) (govtypes.Content, error) {
title, err := cmd.Flags().GetString(govcli.FlagTitle)
if err != nil {
return nil, err
}
description, err := cmd.Flags().GetString(govcli.FlagDescription)
if err != nil {
return nil, err
}
assetsStr, err := cmd.Flags().GetString(FlagSuperfluidAssets)
if err != nil {
return nil, err
}
assets := strings.Split(assetsStr, ",")
superfluidAssets := []types.SuperfluidAsset{}
for _, asset := range assets {
superfluidAssets = append(superfluidAssets, types.SuperfluidAsset{
Denom: asset,
AssetType: types.SuperfluidAssetTypeLPShare,
})
}
content := &types.SetSuperfluidAssetsProposal{
Title: title,
Description: description,
Assets: superfluidAssets,
}
return content, nil
}
func parseRemoveSuperfluidAssetsArgsToContent(cmd *cobra.Command) (govtypes.Content, error) {
title, err := cmd.Flags().GetString(govcli.FlagTitle)
if err != nil {
return nil, err
}
description, err := cmd.Flags().GetString(govcli.FlagDescription)
if err != nil {
return nil, err
}
assetsStr, err := cmd.Flags().GetString(FlagSuperfluidAssets)
if err != nil {
return nil, err
}
assets := strings.Split(assetsStr, ",")
content := &types.RemoveSuperfluidAssetsProposal{
Title: title,
Description: description,
SuperfluidAssetDenoms: assets,
}
return content, nil
}
package client
import (
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
"github.com/osmosis-labs/osmosis/x/superfluid/client/cli"
"github.com/osmosis-labs/osmosis/x/superfluid/client/rest"
)
var SetSuperfluidAssetsProposalHandler = govclient.NewProposalHandler(cli.NewCmdSubmitSetSuperfluidAssetsProposal, rest.ProposalSetSuperfluidAssetsRESTHandler)
var RemoveSuperfluidAssetsProposalHandler = govclient.NewProposalHandler(cli.NewCmdSubmitRemoveSuperfluidAssetsProposal, rest.ProposalRemoveSuperfluidAssetsRESTHandler)
package rest
import (
"net/http"
"github.com/cosmos/cosmos-sdk/client"
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
)
func ProposalSetSuperfluidAssetsRESTHandler(clientCtx client.Context) govrest.ProposalRESTHandler {
return govrest.ProposalRESTHandler{
SubRoute: "set-superfluid-assets",
Handler: newSetSuperfluidAssetsHandler(clientCtx),
}
}
func newSetSuperfluidAssetsHandler(clientCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
}
}
func ProposalRemoveSuperfluidAssetsRESTHandler(clientCtx client.Context) govrest.ProposalRESTHandler {
return govrest.ProposalRESTHandler{
SubRoute: "remove-superfluid-assets",
Handler: newRemoveSuperfluidAssetsHandler(clientCtx),
}
}
func newRemoveSuperfluidAssetsHandler(clientCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment