Skip to content

Commit

Permalink
Add Unbonding Query (#647)
Browse files Browse the repository at this point in the history
  • Loading branch information
shellvish authored Mar 10, 2023
1 parent b3196d2 commit f07ff73
Show file tree
Hide file tree
Showing 7 changed files with 1,254 additions and 69 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ build:
go build -mod=readonly -ldflags '$(ldflags)' -trimpath -o $(BUILDDIR) ./...;

install: go.sum
go install $(BUILD_FLAGS) ./cmd/strided
go install $(BUILD_FLAGS) ./cmd/strided

clean:
rm -rf $(BUILDDIR)/*
Expand Down
18 changes: 18 additions & 0 deletions proto/stride/stakeibc/address_unbonding.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
syntax = "proto3";
package stride.stakeibc;

import "gogoproto/gogo.proto";

option go_package = "github.com/Stride-Labs/stride/v6/x/stakeibc/types";

message AddressUnbonding {
string address = 1;
string receiver = 2;
string unbonding_estimated_time = 3;
string amount = 4 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string denom = 5;
bool claim_is_pending = 8;
}
15 changes: 15 additions & 0 deletions proto/stride/stakeibc/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "stride/stakeibc/params.proto";
import "stride/stakeibc/validator.proto";
import "stride/stakeibc/host_zone.proto";
import "stride/stakeibc/epoch_tracker.proto";
import "stride/stakeibc/address_unbonding.proto";
// this line is used by starport scaffolding # 1

option go_package = "github.com/Stride-Labs/stride/v6/x/stakeibc/types";
Expand Down Expand Up @@ -66,6 +67,13 @@ service Query {
"/Stride-Labs/stride/stakeibc/next_packet_sequence/{channel_id}/"
"{port_id}";
}

// Queries an address's unbondings
rpc AddressUnbondings(QueryAddressUnbondings)
returns (QueryAddressUnbondingsResponse) {
option (google.api.http).get =
"/Stride-Labs/stride/stakeibc/unbondings/{address}";
}
}

// QueryInterchainAccountFromAddressRequest is the request type for the
Expand Down Expand Up @@ -132,3 +140,10 @@ message QueryGetNextPacketSequenceRequest {
}

message QueryGetNextPacketSequenceResponse { uint64 sequence = 1; }

message QueryAddressUnbondings { string address = 1; }

message QueryAddressUnbondingsResponse {
repeated AddressUnbonding address_unbondings = 1
[ (gogoproto.nullable) = false ];
}
86 changes: 86 additions & 0 deletions x/stakeibc/keeper/grpc_query_address_unbondings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package keeper

import (
"context"
"fmt"
"strings"
"time"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

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

epochtypes "github.com/Stride-Labs/stride/v6/x/epochs/types"
"github.com/Stride-Labs/stride/v6/x/stakeibc/types"
)

const nanosecondsInDay = 86400000000000

func (k Keeper) AddressUnbondings(c context.Context, req *types.QueryAddressUnbondings) (*types.QueryAddressUnbondingsResponse, error) {
// The function queries all the unbondings associated with a Stride address.
// This should provide more visiblity into the unbonding process for a user.

if req == nil || req.Address == "" {
return nil, status.Error(codes.InvalidArgument, "invalid request")
}
ctx := sdk.UnwrapSDKContext(c)

var addressUnbondings []types.AddressUnbonding

// get the relevant day
dayEpochTracker, found := k.GetEpochTracker(ctx, epochtypes.DAY_EPOCH)
if !found {
return nil, sdkerrors.ErrKeyNotFound
}
currentDay := dayEpochTracker.EpochNumber

epochUnbondingRecords := k.RecordsKeeper.GetAllEpochUnbondingRecord(ctx)

for _, epochUnbondingRecord := range epochUnbondingRecords {
for _, hostZoneUnbonding := range epochUnbondingRecord.GetHostZoneUnbondings() {
for _, userRedemptionRecordId := range hostZoneUnbonding.GetUserRedemptionRecords() {
userRedemptionRecordComponents := strings.Split(userRedemptionRecordId, ".")
if len(userRedemptionRecordComponents) != 3 {
k.Logger(ctx).Error(fmt.Sprintf("invalid user redemption record id %s", userRedemptionRecordId))
continue
}
userRedemptionRecordAddress := userRedemptionRecordComponents[2]
if userRedemptionRecordAddress == req.Address {
userRedemptionRecord, found := k.RecordsKeeper.GetUserRedemptionRecord(ctx, userRedemptionRecordId)
if !found {
continue // the record has already been claimed
}

// get the anticipated unbonding time
unbondingTime := hostZoneUnbonding.UnbondingTime
if unbondingTime == 0 {
hostZone, found := k.GetHostZone(ctx, hostZoneUnbonding.HostZoneId)
if !found {
return nil, sdkerrors.ErrKeyNotFound
}
daysUntilUnbonding := hostZone.UnbondingFrequency - (currentDay % hostZone.UnbondingFrequency)
unbondingStartTime := dayEpochTracker.NextEpochStartTime + ((daysUntilUnbonding - 1) * nanosecondsInDay)
unbondingDurationEstimate := (hostZone.UnbondingFrequency - 1) * 7
unbondingTime = unbondingStartTime + (unbondingDurationEstimate * nanosecondsInDay)
}
unbondingTime = unbondingTime + nanosecondsInDay
unbondingTimeStr := time.Unix(0, int64(unbondingTime)).UTC().String()

addressUnbonding := types.AddressUnbonding{
Address: req.Address,
Receiver: userRedemptionRecord.Receiver,
UnbondingEstimatedTime: unbondingTimeStr,
Amount: userRedemptionRecord.Amount,
Denom: userRedemptionRecord.Denom,
ClaimIsPending: userRedemptionRecord.ClaimIsPending,
}
addressUnbondings = append(addressUnbondings, addressUnbonding)
}
}
}
}

return &types.QueryAddressUnbondingsResponse{AddressUnbondings: addressUnbondings}, nil
}
Loading

0 comments on commit f07ff73

Please sign in to comment.