Skip to content

Commit

Permalink
Merge pull request #190 from crescent-network/feat/position-assets
Browse files Browse the repository at this point in the history
feat: add PositionAssets query
  • Loading branch information
kingcre committed Aug 30, 2023
2 parents 3c45650 + cbd8e05 commit 868f1c1
Show file tree
Hide file tree
Showing 13 changed files with 876 additions and 147 deletions.
1 change: 0 additions & 1 deletion app/params/weights.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ const (
DefaultWeightMsgMMOrder int = 0
DefaultWeightMsgCancelOrder int = 0
DefaultWeightMsgCancelAllOrders int = 0
DefaultWeightMsgCancelMMOrder int = 0

// Deprecated claim module
DefaultWeightMsgClaim int = 0
Expand Down
4 changes: 2 additions & 2 deletions app/testutil/liquidamm.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ func (s *TestSuite) BurnShare(senderAddr sdk.AccAddress, publicPositionId uint64
return
}

func (s *TestSuite) PlaceBid(bidderAddr sdk.AccAddress, positionId, auctionId uint64, share sdk.Coin) (bid liquidammtypes.Bid) {
func (s *TestSuite) PlaceBid(bidderAddr sdk.AccAddress, publicPositionId, auctionId uint64, share sdk.Coin) (bid liquidammtypes.Bid) {
s.T().Helper()
var err error
bid, err = s.App.LiquidAMMKeeper.PlaceBid(s.Ctx, bidderAddr, positionId, auctionId, share)
bid, err = s.App.LiquidAMMKeeper.PlaceBid(s.Ctx, bidderAddr, publicPositionId, auctionId, share)
s.Require().NoError(err)
return
}
Expand Down
2 changes: 1 addition & 1 deletion client/docs/statik/statik.go

Large diffs are not rendered by default.

96 changes: 96 additions & 0 deletions client/docs/swagger-ui/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13558,6 +13558,75 @@ paths:
format: uint64
tags:
- Query
'/crescent/amm/v1beta1/positions/{position_id}/assets':
get:
operationId: PositionAssets
responses:
'200':
description: A successful response.
schema:
type: object
properties:
coin0:
type: object
properties:
denom:
type: string
amount:
type: string
description: >-
Coin defines a token with a denomination and an amount.


NOTE: The amount field is an Int which implements the custom
method

signatures required by gogoproto.
coin1:
type: object
properties:
denom:
type: string
amount:
type: string
description: >-
Coin defines a token with a denomination and an amount.


NOTE: The amount field is an Int which implements the custom
method

signatures required by gogoproto.
default:
description: An unexpected error response
schema:
type: object
properties:
error:
type: string
code:
type: integer
format: int32
message:
type: string
details:
type: array
items:
type: object
properties:
type_url:
type: string
value:
type: string
format: byte
parameters:
- name: position_id
in: path
required: true
type: string
format: uint64
tags:
- Query
/crescent/amm/v1beta1/simulation/add_liquidity:
get:
operationId: AddLiquiditySimulation
Expand Down Expand Up @@ -21507,6 +21576,33 @@ definitions:
method

signatures required by gogoproto.
crescent.amm.v1beta1.QueryPositionAssetsResponse:
type: object
properties:
coin0:
type: object
properties:
denom:
type: string
amount:
type: string
description: |-
Coin defines a token with a denomination and an amount.

NOTE: The amount field is an Int which implements the custom method
signatures required by gogoproto.
coin1:
type: object
properties:
denom:
type: string
amount:
type: string
description: |-
Coin defines a token with a denomination and an amount.

NOTE: The amount field is an Int which implements the custom method
signatures required by gogoproto.
crescent.amm.v1beta1.QueryPositionResponse:
type: object
properties:
Expand Down
12 changes: 12 additions & 0 deletions proto/crescent/amm/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ service Query {
rpc Position(QueryPositionRequest) returns (QueryPositionResponse) {
option (google.api.http).get = "/crescent/amm/v1beta1/positions/{position_id}";
}
rpc PositionAssets(QueryPositionAssetsRequest) returns (QueryPositionAssetsResponse) {
option (google.api.http).get = "/crescent/amm/v1beta1/positions/{position_id}/assets";
}
rpc AddLiquiditySimulation(QueryAddLiquiditySimulationRequest) returns (QueryAddLiquiditySimulationResponse) {
option (google.api.http).get = "/crescent/amm/v1beta1/simulation/add_liquidity";
}
Expand Down Expand Up @@ -96,6 +99,15 @@ message QueryPositionResponse {
PositionResponse position = 1 [(gogoproto.nullable) = false];
}

message QueryPositionAssetsRequest {
uint64 position_id = 1;
}

message QueryPositionAssetsResponse {
cosmos.base.v1beta1.Coin coin0 = 1 [(gogoproto.nullable) = false];
cosmos.base.v1beta1.Coin coin1 = 2 [(gogoproto.nullable) = false];
}

message QueryAddLiquiditySimulationRequest {
uint64 pool_id = 1;
string lower_price = 2;
Expand Down
37 changes: 37 additions & 0 deletions x/amm/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func GetQueryCmd() *cobra.Command {
NewQueryPoolCmd(),
NewQueryAllPositionsCmd(),
NewQueryPositionCmd(),
NewQueryPositionAssetsCmd(),
NewQueryAddLiquiditySimulationCmd(),
NewQueryRemoveLiquiditySimulationCmd(),
NewQueryCollectibleCoinsCmd(),
Expand Down Expand Up @@ -250,6 +251,42 @@ $ %s query %s position 1
return cmd
}

func NewQueryPositionAssetsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "position-assets [position-id]",
Args: cobra.ExactArgs(1),
Short: "Query a position's underlying assets",
Long: strings.TrimSpace(
fmt.Sprintf(`Query a position's underlying assets.
Example:
$ %s query %s position-assets 1
`,
version.AppName, types.ModuleName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
positionId, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("invalid position id: %w", err)
}
queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.PositionAssets(cmd.Context(), &types.QueryPositionAssetsRequest{
PositionId: positionId,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

func NewQueryAddLiquiditySimulationCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "add-liquidity-simulation [pool-id] [lower-price] [upper-price] [desired-amount]",
Expand Down
16 changes: 16 additions & 0 deletions x/amm/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,22 @@ func (k Querier) Position(c context.Context, req *types.QueryPositionRequest) (*
return &types.QueryPositionResponse{Position: types.NewPositionResponse(position)}, nil
}

func (k Querier) PositionAssets(c context.Context, req *types.QueryPositionAssetsRequest) (*types.QueryPositionAssetsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)
position, found := k.GetPosition(ctx, req.PositionId)
if !found {
return nil, status.Error(codes.NotFound, "position not found")
}
coin0, coin1, err := k.Keeper.PositionAssets(ctx, position.Id)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
return &types.QueryPositionAssetsResponse{Coin0: coin0, Coin1: coin1}, nil
}

func (k Querier) AddLiquiditySimulation(c context.Context, req *types.QueryAddLiquiditySimulationRequest) (*types.QueryAddLiquiditySimulationResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
Expand Down
50 changes: 50 additions & 0 deletions x/amm/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,56 @@ func (s *KeeperTestSuite) TestQueryPosition() {
}
}

func (s *KeeperTestSuite) TestQueryPositionAssets() {
s.SetupSampleScenario()

for _, tc := range []struct {
name string
req *types.QueryPositionAssetsRequest
expectedErr string
postRun func(resp *types.QueryPositionAssetsResponse)
}{
{
"happy case",
&types.QueryPositionAssetsRequest{
PositionId: 1,
},
"",
func(resp *types.QueryPositionAssetsResponse) {
s.AssertEqual(utils.ParseCoin("133675209ucre"), resp.Coin0)
s.AssertEqual(utils.ParseCoin("257373895uusd"), resp.Coin1)
},
},
{
"position not found",
&types.QueryPositionAssetsRequest{
PositionId: 0,
},
"rpc error: code = NotFound desc = position not found",
nil,
},
{
"position not found 2",
&types.QueryPositionAssetsRequest{
PositionId: 5,
},
"rpc error: code = NotFound desc = position not found",
nil,
},
} {
s.Run(tc.name, func() {
ctx, _ := s.Ctx.CacheContext()
resp, err := s.querier.PositionAssets(sdk.WrapSDKContext(ctx), tc.req)
if tc.expectedErr == "" {
s.Require().NoError(err)
tc.postRun(resp)
} else {
s.Require().EqualError(err, tc.expectedErr)
}
})
}
}

func (s *KeeperTestSuite) TestQueryAddLiquiditySimulation() {
s.SetupSampleScenario()

Expand Down
15 changes: 15 additions & 0 deletions x/amm/keeper/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,21 @@ func (k Keeper) Collect(
return nil
}

func (k Keeper) PositionAssets(ctx sdk.Context, positionId uint64) (coin0, coin1 sdk.Coin, err error) {
position, found := k.GetPosition(ctx, positionId)
if !found {
return coin0, coin1, sdkerrors.Wrap(sdkerrors.ErrNotFound, "position not found")
}
pool := k.MustGetPool(ctx, position.PoolId)
ctx, _ = ctx.CacheContext()
_, amt0, amt1 := k.modifyPosition(
ctx, pool, position.MustGetOwnerAddress(), position.LowerTick, position.UpperTick, position.Liquidity.Neg())
amt0, amt1 = amt0.Neg(), amt1.Neg()
coin0 = sdk.NewCoin(pool.Denom0, amt0)
coin1 = sdk.NewCoin(pool.Denom1, amt1)
return
}

func (k Keeper) CollectibleCoins(ctx sdk.Context, positionId uint64) (fee, farmingRewards sdk.Coins, err error) {
position, found := k.GetPosition(ctx, positionId)
if !found {
Expand Down
12 changes: 8 additions & 4 deletions x/amm/simulation/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func SimulateMsgCreatePool(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
simAccount, msg, found := findMsgCreatePoolParams(r, accs, ek, k, ctx)
simAccount, msg, found := findMsgCreatePoolParams(r, accs, bk, ek, k, ctx)
if !found {
return simtypes.NoOpMsg(
types.ModuleName, types.TypeMsgCreatePool, "unable to create pool"), nil, nil
Expand Down Expand Up @@ -144,7 +144,7 @@ func SimulateMsgRemoveLiquidity(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
simAccount, msg, found := findMsgPlaceRemoveLiquidityParams(r, accs, k, ctx)
simAccount, msg, found := findMsgRemoveLiquidityParams(r, accs, k, ctx)
if !found {
return simtypes.NoOpMsg(
types.ModuleName, types.TypeMsgRemoveLiquidity, "unable to remove liquidity"), nil, nil
Expand Down Expand Up @@ -196,7 +196,7 @@ func SimulateMsgCollect(
}

func findMsgCreatePoolParams(r *rand.Rand, accs []simtypes.Account,
ek types.ExchangeKeeper, k keeper.Keeper, ctx sdk.Context) (acc simtypes.Account, msg *types.MsgCreatePool, found bool) {
bk types.BankKeeper, ek types.ExchangeKeeper, k keeper.Keeper, ctx sdk.Context) (acc simtypes.Account, msg *types.MsgCreatePool, found bool) {
var markets []exchangetypes.Market
ek.IterateAllMarkets(ctx, func(market exchangetypes.Market) (stop bool) {
markets = append(markets, market)
Expand All @@ -206,6 +206,10 @@ func findMsgCreatePoolParams(r *rand.Rand, accs []simtypes.Account,
for _, market := range markets {
if found := k.LookupPoolByMarket(ctx, market.Id); !found {
acc, _ = simtypes.RandomAcc(r, accs)
spendable := bk.SpendableCoins(ctx, acc.Address)
if !spendable.IsAllGTE(k.GetPoolCreationFee(ctx)) {
continue
}
marketState := ek.MustGetMarketState(ctx, market.Id)
var price sdk.Dec
if marketState.LastPrice != nil {
Expand Down Expand Up @@ -286,7 +290,7 @@ func findMsgAddLiquidityParams(
return acc, msg, false
}

func findMsgPlaceRemoveLiquidityParams(
func findMsgRemoveLiquidityParams(
r *rand.Rand, accs []simtypes.Account,
k keeper.Keeper, ctx sdk.Context) (acc simtypes.Account, msg *types.MsgRemoveLiquidity, found bool) {
accs = utils.ShuffleSimAccounts(r, accs)
Expand Down
Loading

0 comments on commit 868f1c1

Please sign in to comment.