Skip to content

Commit

Permalink
Add boilerplate for stableswap (#1214)
Browse files Browse the repository at this point in the history
* Add boilerplate for stableswap

* Update proto/osmosis/gamm/pool-models/stableswap/tx.proto

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update proto/osmosis/gamm/pool-models/stableswap/tx.proto

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* rename file

* make proto-all

* Delete old pb.go file

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
  • Loading branch information
ValarDragon and alexanderbez authored Apr 8, 2022
1 parent db353ce commit 3c582ef
Show file tree
Hide file tree
Showing 13 changed files with 1,887 additions and 48 deletions.
66 changes: 66 additions & 0 deletions proto/osmosis/gamm/pool-models/stableswap/stableswap_pool.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
syntax = "proto3";
package osmosis.gamm.stableswap.v1beta1;

import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";

import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";

import "cosmos/auth/v1beta1/auth.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/osmosis-labs/osmosis/v7/x/gamm/pool-models/stableswap";

// PoolParams defined the parameters that will be managed by the pool
// governance in the future. This params are not managed by the chain
// governance. Instead they will be managed by the token holders of the pool.
// The pool's token holders are specified in future_pool_governor.
message PoolParams {
string swapFee = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.moretags) = "yaml:\"swap_fee\"",
(gogoproto.nullable) = false
];
string exitFee = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.moretags) = "yaml:\"exit_fee\"",
(gogoproto.nullable) = false
];
}

// Pool is the stableswap Pool struct
message Pool {
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;
option (cosmos_proto.implements_interface) = "PoolI";

string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ];
uint64 id = 2;

PoolParams poolParams = 3 [
(gogoproto.moretags) = "yaml:\"stableswap_pool_params\"",
(gogoproto.nullable) = false
];

// This string specifies who will govern the pool in the future.
// Valid forms of this are:
// {token name},{duration}
// {duration}
// where {token name} if specified is the token which determines the
// governor, and if not specified is the LP token for this pool.duration is
// a time specified as 0w,1w,2w, etc. which specifies how long the token
// would need to be locked up to count in governance. 0w means no lockup.
string future_pool_governor = 4
[ (gogoproto.moretags) = "yaml:\"future_pool_governor\"" ];
// sum of all LP shares
cosmos.base.v1beta1.Coin totalShares = 5 [
(gogoproto.moretags) = "yaml:\"total_shares\"",
(gogoproto.nullable) = false
];
// assets in the pool
repeated cosmos.base.v1beta1.Coin poolLiquidity = 6 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
}
31 changes: 31 additions & 0 deletions proto/osmosis/gamm/pool-models/stableswap/tx.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
syntax = "proto3";
package osmosis.gamm.stableswap.v1beta1;

import "cosmos/base/v1beta1/coin.proto";
import "gogoproto/gogo.proto";
import "osmosis/gamm/pool-models/stableswap/stableswap_pool.proto";

option go_package = "github.com/osmosis-labs/osmosis/v7/x/gamm/pool-models/stableswap";

service Msg {
rpc CreateStableswapPool(MsgCreateStableswapPool)
returns (MsgCreateStableswapPoolResponse);
}

message MsgCreateStableswapPool {
string sender = 1 [ (gogoproto.moretags) = "yaml:\"sender\"" ];

PoolParams poolParams = 2 [ (gogoproto.moretags) = "yaml:\"pool_params\"" ];

repeated cosmos.base.v1beta1.Coin initial_pool_liquidity = 3 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];

string future_pool_governor = 4
[ (gogoproto.moretags) = "yaml:\"future_pool_governor\"" ];
}

message MsgCreateStableswapPoolResponse {
uint64 pool_id = 1 [ (gogoproto.customname) = "PoolID" ];
}
3 changes: 2 additions & 1 deletion proto/osmosis/txfees/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ service Query {

rpc DenomSpotPrice(QueryDenomSpotPriceRequest)
returns (QueryDenomSpotPriceResponse) {
option (google.api.http).get = "/osmosis/txfees/v1beta1/spot_price_by_denom";
option (google.api.http).get =
"/osmosis/txfees/v1beta1/spot_price_by_denom";
}

rpc DenomPoolId(QueryDenomPoolIdRequest) returns (QueryDenomPoolIdResponse) {
Expand Down
41 changes: 0 additions & 41 deletions x/gamm/pool-models/balancer/balancer_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,47 +517,6 @@ func (params PoolParams) GetPoolExitFee() sdk.Dec {
return params.ExitFee
}

func ValidateFutureGovernor(governor string) error {
// allow empty governor
if governor == "" {
return nil
}

// validation for future owner
// "osmo1fqlr98d45v5ysqgp6h56kpujcj4cvsjnjq9nck"
_, err := sdk.AccAddressFromBech32(governor)
if err == nil {
return nil
}

lockTimeStr := ""
splits := strings.Split(governor, ",")
if len(splits) > 2 {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, fmt.Sprintf("invalid future governor: %s", governor))
}

// token,100h
if len(splits) == 2 {
lpTokenStr := splits[0]
if sdk.ValidateDenom(lpTokenStr) != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, fmt.Sprintf("invalid future governor: %s", governor))
}
lockTimeStr = splits[1]
}

// 100h
if len(splits) == 1 {
lockTimeStr = splits[0]
}

// Note that a duration of 0 is allowed
_, err = time.ParseDuration(lockTimeStr)
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, fmt.Sprintf("invalid future governor: %s", governor))
}
return nil
}

// subPoolAssetWeights subtracts the weights of two different pool asset slices.
// It assumes that both pool assets have the same token denominations,
// with the denominations in the same order.
Expand Down
2 changes: 1 addition & 1 deletion x/gamm/pool-models/balancer/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (msg MsgCreateBalancerPool) ValidateBasic() error {
}

// validation for future owner
if err = ValidateFutureGovernor(msg.FuturePoolGovernor); err != nil {
if err = types.ValidateFutureGovernor(msg.FuturePoolGovernor); err != nil {
return err
}

Expand Down
48 changes: 48 additions & 0 deletions x/gamm/pool-models/stableswap/codec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package stableswap

import (
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"

types "github.com/osmosis-labs/osmosis/v7/x/gamm/types"
)

// RegisterLegacyAminoCodec registers the necessary x/gamm interfaces and concrete types
// on the provided LegacyAmino codec. These types are used for Amino JSON serialization.
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
cdc.RegisterConcrete(&Pool{}, "osmosis/gamm/StableswapPool", nil)
cdc.RegisterConcrete(&MsgCreateStableswapPool{}, "osmosis/gamm/create-stableswap-pool", nil)
cdc.RegisterConcrete(&PoolParams{}, "osmosis/gamm/StableswapPoolParams", nil)
}

func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterInterface(
"osmosis.gamm.v1beta1.PoolI",
(*types.PoolI)(nil),
&Pool{},
)
registry.RegisterImplementations(
(*sdk.Msg)(nil),
&MsgCreateStableswapPool{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}

var (
amino = codec.NewLegacyAmino()

// ModuleCdc references the global x/bank module codec. Note, the codec should
// ONLY be used in certain instances of tests and for JSON encoding as Amino is
// still used for that purpose.
//
// The actual codec used for serialization should be provided to x/staking and
// defined at the application level.
ModuleCdc = codec.NewAminoCodec(amino)
)

func init() {
RegisterLegacyAminoCodec(amino)
amino.Seal()
}
84 changes: 84 additions & 0 deletions x/gamm/pool-models/stableswap/msgs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package stableswap

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

"github.com/osmosis-labs/osmosis/v7/x/gamm/types"
)

const (
TypeMsgCreateStableswapPool = "create_stableswap_pool"
)

var _ sdk.Msg = &MsgCreateStableswapPool{}
var _ types.CreatePoolMsg = &MsgCreateStableswapPool{}

func NewMsgCreateStableswapPool(
sender sdk.AccAddress,
poolParams PoolParams,
initialLiquidity sdk.Coins,
futurePoolGovernor string) MsgCreateStableswapPool {
return MsgCreateStableswapPool{
Sender: sender.String(),
PoolParams: &poolParams,
InitialPoolLiquidity: initialLiquidity,
FuturePoolGovernor: futurePoolGovernor,
}
}

func (msg MsgCreateStableswapPool) Route() string { return types.RouterKey }
func (msg MsgCreateStableswapPool) Type() string { return TypeMsgCreateStableswapPool }
func (msg MsgCreateStableswapPool) ValidateBasic() error {
_, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "Invalid sender address (%s)", err)
}

err = msg.PoolParams.Validate()
if err != nil {
return err
}

// TODO: Add validation for pool initial liquidity

// validation for future owner
if err = types.ValidateFutureGovernor(msg.FuturePoolGovernor); err != nil {
return err
}

return nil
}

func (msg MsgCreateStableswapPool) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(&msg))
}

func (msg MsgCreateStableswapPool) GetSigners() []sdk.AccAddress {
sender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
panic(err)
}
return []sdk.AccAddress{sender}
}

/// Implement the CreatePoolMsg interface

func (msg MsgCreateStableswapPool) PoolCreator() sdk.AccAddress {
sender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
panic(err)
}
return sender
}
func (msg MsgCreateStableswapPool) Validate(ctx sdk.Context) error {
return msg.ValidateBasic()
}

func (msg MsgCreateStableswapPool) InitialLiquidity() sdk.Coins {
return msg.InitialPoolLiquidity
}

func (msg MsgCreateStableswapPool) CreatePool(ctx sdk.Context, poolID uint64) (types.PoolI, error) {
return &Pool{}, types.ErrNotImplemented
}
26 changes: 26 additions & 0 deletions x/gamm/pool-models/stableswap/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package stableswap

import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/osmosis-labs/osmosis/v7/x/gamm/types"
)

func (params PoolParams) Validate() error {
if params.ExitFee.IsNegative() {
return types.ErrNegativeExitFee
}

if params.ExitFee.GTE(sdk.OneDec()) {
return types.ErrTooMuchExitFee
}

if params.SwapFee.IsNegative() {
return types.ErrNegativeSwapFee
}

if params.SwapFee.GTE(sdk.OneDec()) {
return types.ErrTooMuchSwapFee
}
return nil
}
Loading

0 comments on commit 3c582ef

Please sign in to comment.