Skip to content

Commit

Permalink
Issue 1525: sub-section: combine superfluid query and staking query o…
Browse files Browse the repository at this point in the history
…n querying delegation by delegator (#1539)

* add normarl staking query for superfluid

* add TestGRPCQuerySuperfluidDelegationsWithNormalStaking

* add Query Delegation

* combine hieuvubk's work on Osmo equivalent. The idea belongs to hieuvubk

* change proto and cli

* minor

* change name to total-delegation-by-delegator

* another minor :v

* last minor

* Apply suggestions from code review

Co-authored-by: Matt, Park <[email protected]>

* apply changes from review

* add feature to changelog.md

* minor fix in changelog

Co-authored-by: Matt, Park <[email protected]>
  • Loading branch information
nghuyenthevinh2000 and mattverse authored Jun 30, 2022
1 parent 699b713 commit 52d46b2
Show file tree
Hide file tree
Showing 9 changed files with 919 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#1312] Stableswap: Createpool logic
* [#1230] Stableswap CFMM equations
* [#1429] solver for multi-asset CFMM
* [#1539] Superfluid: Combine superfluid and staking query on querying delegation by delegator

### Bug Fixes
* [1700](https://github.com/osmosis-labs/osmosis/pull/1700) Upgrade sdk fork with missing snapshot manager fix.
Expand Down
35 changes: 35 additions & 0 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@
- [ConnectedIntermediaryAccountResponse](#osmosis.superfluid.ConnectedIntermediaryAccountResponse)
- [EstimateSuperfluidDelegatedAmountByValidatorDenomRequest](#osmosis.superfluid.EstimateSuperfluidDelegatedAmountByValidatorDenomRequest)
- [EstimateSuperfluidDelegatedAmountByValidatorDenomResponse](#osmosis.superfluid.EstimateSuperfluidDelegatedAmountByValidatorDenomResponse)
- [QueryDelegationRequest](#osmosis.superfluid.QueryDelegationRequest)
- [QueryDelegationResponse](#osmosis.superfluid.QueryDelegationResponse)
- [QueryParamsRequest](#osmosis.superfluid.QueryParamsRequest)
- [QueryParamsResponse](#osmosis.superfluid.QueryParamsResponse)
- [SuperfluidDelegationAmountRequest](#osmosis.superfluid.SuperfluidDelegationAmountRequest)
Expand Down Expand Up @@ -3610,6 +3612,38 @@ assets



<a name="osmosis.superfluid.QueryDelegationRequest"></a>

### QueryDelegationRequest



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `delegator_address` | [string](#string) | | |






<a name="osmosis.superfluid.QueryDelegationResponse"></a>

### QueryDelegationResponse



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `superfluid_delegation_records` | [SuperfluidDelegationRecord](#osmosis.superfluid.SuperfluidDelegationRecord) | repeated | |
| `delegation_response` | [cosmos.staking.v1beta1.DelegationResponse](#cosmos.staking.v1beta1.DelegationResponse) | repeated | |
| `total_delegated_coins` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |






<a name="osmosis.superfluid.QueryParamsRequest"></a>

### QueryParamsRequest
Expand Down Expand Up @@ -3831,6 +3865,7 @@ Query defines the gRPC querier service.
| `SuperfluidUndelegationsByDelegator` | [SuperfluidUndelegationsByDelegatorRequest](#osmosis.superfluid.SuperfluidUndelegationsByDelegatorRequest) | [SuperfluidUndelegationsByDelegatorResponse](#osmosis.superfluid.SuperfluidUndelegationsByDelegatorResponse) | | GET|/osmosis/superfluid/v1beta1/superfluid_undelegations_by_delegator/{delegator_address}|
| `SuperfluidDelegationsByValidatorDenom` | [SuperfluidDelegationsByValidatorDenomRequest](#osmosis.superfluid.SuperfluidDelegationsByValidatorDenomRequest) | [SuperfluidDelegationsByValidatorDenomResponse](#osmosis.superfluid.SuperfluidDelegationsByValidatorDenomResponse) | Returns all the superfluid positions of a specific denom delegated to one validator | GET|/osmosis/superfluid/v1beta1/superfluid_delegations_by_validator_denom|
| `EstimateSuperfluidDelegatedAmountByValidatorDenom` | [EstimateSuperfluidDelegatedAmountByValidatorDenomRequest](#osmosis.superfluid.EstimateSuperfluidDelegatedAmountByValidatorDenomRequest) | [EstimateSuperfluidDelegatedAmountByValidatorDenomResponse](#osmosis.superfluid.EstimateSuperfluidDelegatedAmountByValidatorDenomResponse) | Returns the amount of a specific denom delegated to a specific validator This is labeled an estimate, because the way it calculates the amount can lead rounding errors from the true delegated amount | GET|/osmosis/superfluid/v1beta1/estimate_superfluid_delegation_amount_by_validator_denom|
| `Delegation` | [QueryDelegationRequest](#osmosis.superfluid.QueryDelegationRequest) | [QueryDelegationResponse](#osmosis.superfluid.QueryDelegationResponse) | | GET|/osmosis/superfluid/v1beta1/delegation/{delegator_address}|

<!-- end services -->

Expand Down
30 changes: 29 additions & 1 deletion proto/osmosis/superfluid/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import "osmosis/superfluid/superfluid.proto";
import "osmosis/superfluid/params.proto";
import "osmosis/lockup/lock.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "cosmos/staking/v1beta1/staking.proto";

option go_package = "github.com/osmosis-labs/osmosis/v7/x/superfluid/types";

Expand Down Expand Up @@ -112,6 +113,12 @@ service Query {
// option (google.api.http).get =
// "/osmosis/superfluid/v1beta1/superfluid_unbondings_by_validator_denom";
// }

// Returns the specified delegations for a specific delegator
rpc TotalDelegationByDelegator (QueryTotalDelegationByDelegatorRequest) returns (QueryTotalDelegationByDelegatorResponse) {
option (google.api.http).get = "/osmosis/superfluid/v1beta1/"
"total_delegation_by_delegator/{delegator_address}";
}
}

message QueryParamsRequest {}
Expand Down Expand Up @@ -256,4 +263,25 @@ message EstimateSuperfluidDelegatedAmountByValidatorDenomResponse {
// (gogoproto.nullable) = false,
// (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
// ];
// }
// }

message QueryTotalDelegationByDelegatorRequest {
string delegator_address = 1;
}

message QueryTotalDelegationByDelegatorResponse {
repeated SuperfluidDelegationRecord superfluid_delegation_records = 1
[ (gogoproto.nullable) = false ];

repeated cosmos.staking.v1beta1.DelegationResponse delegation_response = 2 [
(gogoproto.nullable) = false
];
repeated cosmos.base.v1beta1.Coin total_delegated_coins = 3 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];
cosmos.base.v1beta1.Coin total_equivalent_staked_amount = 4 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"
];
}
Empty file modified scripts/multinode-local-testnet.sh
100644 → 100755
Empty file.
30 changes: 30 additions & 0 deletions x/superfluid/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func GetQueryCmd() *cobra.Command {
GetCmdSuperfluidDelegationsByDelegator(),
GetCmdSuperfluidUndelegationsByDelegator(),
GetCmdTotalSuperfluidDelegations(),
GetCmdTotalDelegationByDelegator(),
)

return cmd
Expand Down Expand Up @@ -349,3 +350,32 @@ func GetCmdTotalSuperfluidDelegations() *cobra.Command {

return cmd
}

func GetCmdTotalDelegationByDelegator() *cobra.Command {
cmd := &cobra.Command{
Use: "total-delegation-by-delegator [delegator_address]",
Short: "Query both superfluid delegation and normal delegation",
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.TotalDelegationByDelegator(cmd.Context(), &types.QueryTotalDelegationByDelegatorRequest{
DelegatorAddress: args[0],
})

if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
88 changes: 88 additions & 0 deletions x/superfluid/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,3 +423,91 @@ func (q Querier) TotalSuperfluidDelegations(goCtx context.Context, _ *types.Tota
TotalDelegations: totalSuperfluidDelegated,
}, nil
}

func (q Querier) TotalDelegationByDelegator(goCtx context.Context, req *types.QueryTotalDelegationByDelegatorRequest) (*types.QueryTotalDelegationByDelegatorResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.DelegatorAddress) == 0 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "empty delegator address")
}

ctx := sdk.UnwrapSDKContext(goCtx)

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

res := types.QueryTotalDelegationByDelegatorResponse{
SuperfluidDelegationRecords: []types.SuperfluidDelegationRecord{},
DelegationResponse: []stakingtypes.DelegationResponse{},
TotalDelegatedCoins: sdk.NewCoins(),
TotalEquivalentStakedAmount: sdk.NewCoin(appparams.BaseCoinUnit, sdk.ZeroInt()),
}

syntheticLocks := q.Keeper.lk.GetAllSyntheticLockupsByAddr(ctx, delAddr)

for _, syntheticLock := range syntheticLocks {
// don't include unbonding delegations
if strings.Contains(syntheticLock.SynthDenom, "superunbonding") {
continue
}

periodLock, err := q.Keeper.lk.GetLockByID(ctx, syntheticLock.UnderlyingLockId)
if err != nil {
return nil, err
}

baseDenom := periodLock.Coins.GetDenomByIndex(0)
lockedCoins := sdk.NewCoin(baseDenom, periodLock.GetCoins().AmountOf(baseDenom))
valAddr, err := ValidatorAddressFromSyntheticDenom(syntheticLock.SynthDenom)

// Find how many osmo tokens this delegation is worth at superfluids current risk adjustment
// and twap of the denom.
equivalentAmount := q.Keeper.GetSuperfluidOSMOTokens(ctx, baseDenom, lockedCoins.Amount)
coin := sdk.NewCoin(appparams.BaseCoinUnit, equivalentAmount)

if err != nil {
return nil, err
}
res.SuperfluidDelegationRecords = append(res.SuperfluidDelegationRecords,
types.SuperfluidDelegationRecord{
DelegatorAddress: req.DelegatorAddress,
ValidatorAddress: valAddr,
DelegationAmount: lockedCoins,
EquivalentStakedAmount: &coin,
},
)
res.TotalDelegatedCoins = res.TotalDelegatedCoins.Add(lockedCoins)
res.TotalEquivalentStakedAmount = res.TotalEquivalentStakedAmount.Add(coin)
}

//this is for getting normal staking
q.sk.IterateDelegations(ctx, delAddr, func(_ int64, del stakingtypes.DelegationI) bool {
val, found := q.sk.GetValidator(ctx, del.GetValidatorAddr())
if !found {
return true
}

lockedCoins := sdk.NewCoin(appparams.BaseCoinUnit, val.TokensFromShares(del.GetShares()).TruncateInt())

res.DelegationResponse = append(res.DelegationResponse,
stakingtypes.DelegationResponse{
Delegation: stakingtypes.Delegation{
DelegatorAddress: del.GetDelegatorAddr().String(),
ValidatorAddress: del.GetValidatorAddr().String(),
Shares: del.GetShares(),
},
Balance: lockedCoins,
},
)

res.TotalDelegatedCoins = res.TotalDelegatedCoins.Add(lockedCoins)
res.TotalEquivalentStakedAmount = res.TotalEquivalentStakedAmount.Add(lockedCoins)

return false
})

return &res, nil
}
66 changes: 66 additions & 0 deletions x/superfluid/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package keeper_test

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

Expand Down Expand Up @@ -200,3 +202,67 @@ func (suite *KeeperTestSuite) TestGRPCQuerySuperfluidDelegationsDontIncludeUnbon
suite.Require().NoError(err)
suite.Require().Equal(totalSuperfluidDelegationsRes.TotalDelegations, sdk.NewInt(30000000))
}

func (suite *KeeperTestSuite) TestGRPCQueryTotalDelegationByDelegator() {
suite.SetupTest()

// Generate delegator addresses
delAddrs := CreateRandomAccounts(2)

// setup 2 validators
valAddrs := suite.SetupValidators([]stakingtypes.BondStatus{stakingtypes.Bonded, stakingtypes.Bonded})

denoms, _ := suite.SetupGammPoolsAndSuperfluidAssets([]sdk.Dec{sdk.NewDec(20), sdk.NewDec(20)})

// create a delegation of 1000000 for every combination of 2 delegations, 2 validators, and 2 superfluid denoms
superfluidDelegations := []superfluidDelegation{
{0, 0, 0, 1000000},
{0, 1, 1, 1000000},
{1, 0, 1, 1000000},
{1, 1, 0, 1000000},
}

// setup superfluid delegations
suite.SetupSuperfluidDelegations(delAddrs, valAddrs, superfluidDelegations, denoms)

// setup normal delegations
bond0to0 := stakingtypes.NewDelegation(delAddrs[0], valAddrs[0], sdk.NewDec(9000000))
bond0to1 := stakingtypes.NewDelegation(delAddrs[0], valAddrs[1], sdk.NewDec(9000000))
bond1to0 := stakingtypes.NewDelegation(delAddrs[1], valAddrs[0], sdk.NewDec(9000000))
bond1to1 := stakingtypes.NewDelegation(delAddrs[1], valAddrs[1], sdk.NewDec(9000000))

suite.App.StakingKeeper.SetDelegation(suite.Ctx, bond0to0)
suite.App.StakingKeeper.SetDelegation(suite.Ctx, bond0to1)
suite.App.StakingKeeper.SetDelegation(suite.Ctx, bond1to0)
suite.App.StakingKeeper.SetDelegation(suite.Ctx, bond1to1)

multiplier0 := suite.querier.Keeper.GetOsmoEquivalentMultiplier(suite.Ctx, denoms[0])
multiplier1 := suite.querier.Keeper.GetOsmoEquivalentMultiplier(suite.Ctx, denoms[1])
minRiskFactor := suite.querier.Keeper.GetParams(suite.Ctx).MinimumRiskFactor

expectAmount0 := multiplier0.Mul(sdk.NewDec(1000000)).Sub(multiplier0.Mul(sdk.NewDec(1000000)).Mul(minRiskFactor))
expectAmount1 := multiplier1.Mul(sdk.NewDec(1000000)).Sub(multiplier1.Mul(sdk.NewDec(1000000)).Mul(minRiskFactor))

// for each delegator, query all their superfluid delegations and normal delegations. Making sure they have 4 delegations
// Making sure TotalEquivalentStakedAmount is equal to converted amount + normal delegations
for _, delegator := range delAddrs {
res, err := suite.queryClient.TotalDelegationByDelegator(sdk.WrapSDKContext(suite.Ctx), &types.QueryTotalDelegationByDelegatorRequest{
DelegatorAddress: delegator.String(),
})

fmt.Printf("res = %v \n", res)

suite.Require().NoError(err)
suite.Require().Len(res.SuperfluidDelegationRecords, 2)
suite.Require().Len(res.DelegationResponse, 2)
suite.Require().True(res.TotalDelegatedCoins.IsEqual(sdk.NewCoins(
sdk.NewInt64Coin(denoms[0], 1000000),
sdk.NewInt64Coin(denoms[1], 1000000),
sdk.NewInt64Coin("uosmo", 18000000),
)))

total_osmo_equivalent := sdk.NewCoin("uosmo", expectAmount0.RoundInt().Add(expectAmount1.RoundInt()).Add(sdk.NewInt(18000000)))

suite.Require().True(res.TotalEquivalentStakedAmount.IsEqual(total_osmo_equivalent))
}
}
Loading

0 comments on commit 52d46b2

Please sign in to comment.