Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stakeibc file re-org part 2 (epochly functions) #1113

Merged
merged 11 commits into from
Mar 1, 2024
192 changes: 192 additions & 0 deletions x/stakeibc/keeper/delegation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package keeper

import (
"fmt"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/gogoproto/proto"
"github.com/spf13/cast"

icatypes "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/types"

"github.com/Stride-Labs/stride/v18/utils"
recordstypes "github.com/Stride-Labs/stride/v18/x/records/types"
"github.com/Stride-Labs/stride/v18/x/stakeibc/types"
)

func (k Keeper) DelegateOnHost(ctx sdk.Context, hostZone types.HostZone, amt sdk.Coin, depositRecord recordstypes.DepositRecord) error {
// TODO: Remove this block and use connection-id from host zone
// the relevant ICA is the delegate account
owner := types.FormatHostZoneICAOwner(hostZone.ChainId, types.ICAAccountType_DELEGATION)
portID, err := icatypes.NewControllerPortID(owner)
if err != nil {
return errorsmod.Wrapf(sdkerrors.ErrInvalidAddress, "%s has no associated portId", owner)
}
connectionId, found := k.GetConnectionIdFromICAPortId(ctx, portID)
if !found {
return errorsmod.Wrapf(types.ErrICAAccountNotFound, "unable to find ICA connection Id for port %s", portID)
}

// Fetch the relevant ICA
if hostZone.DelegationIcaAddress == "" {
return errorsmod.Wrapf(types.ErrICAAccountNotFound, "no delegation account found for %s", hostZone.ChainId)
}

// Construct the transaction
targetDelegatedAmts, err := k.GetTargetValAmtsForHostZone(ctx, hostZone, amt.Amount)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Error getting target delegation amounts for host zone %s", hostZone.ChainId))
return err
}

var splitDelegations []*types.SplitDelegation
var msgs []proto.Message
for _, validator := range hostZone.Validators {
relativeAmount, ok := targetDelegatedAmts[validator.Address]
if !ok || !relativeAmount.IsPositive() {
continue
}

msgs = append(msgs, &stakingtypes.MsgDelegate{
DelegatorAddress: hostZone.DelegationIcaAddress,
ValidatorAddress: validator.Address,
Amount: sdk.NewCoin(amt.Denom, relativeAmount),
})
splitDelegations = append(splitDelegations, &types.SplitDelegation{
Validator: validator.Address,
Amount: relativeAmount,
})
}
k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "Preparing MsgDelegates from the delegation account to each validator"))

if len(msgs) == 0 {
return errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "Target delegation amount was 0 for each validator")
}

// add callback data
delegateCallback := types.DelegateCallback{
HostZoneId: hostZone.ChainId,
DepositRecordId: depositRecord.Id,
SplitDelegations: splitDelegations,
}
k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "Marshalling DelegateCallback args: %+v", delegateCallback))
marshalledCallbackArgs, err := k.MarshalDelegateCallbackArgs(ctx, delegateCallback)
if err != nil {
return err
}

// Send the transaction through SubmitTx
_, err = k.SubmitTxsStrideEpoch(ctx, connectionId, msgs, types.ICAAccountType_DELEGATION, ICACallbackID_Delegate, marshalledCallbackArgs)
if err != nil {
return errorsmod.Wrapf(err, "Failed to SubmitTxs for connectionId %s on %s. Messages: %s", connectionId, hostZone.ChainId, msgs)
}
k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "ICA MsgDelegates Successfully Sent"))

// flag the delegation change in progress on each validator
for _, splitDelegation := range splitDelegations {
if err := k.IncrementValidatorDelegationChangesInProgress(&hostZone, splitDelegation.Validator); err != nil {
return err
}
}
k.SetHostZone(ctx, hostZone)

// update the record state to DELEGATION_IN_PROGRESS
depositRecord.Status = recordstypes.DepositRecord_DELEGATION_IN_PROGRESS
k.RecordsKeeper.SetDepositRecord(ctx, depositRecord)

return nil
}

// Iterate each deposit record marked DELEGATION_QUEUE and use the delegation ICA to delegate on the host zone
func (k Keeper) StakeExistingDepositsOnHostZones(ctx sdk.Context, epochNumber uint64, depositRecords []recordstypes.DepositRecord) {
k.Logger(ctx).Info("Staking deposit records...")

stakeDepositRecords := utils.FilterDepositRecords(depositRecords, func(record recordstypes.DepositRecord) (condition bool) {
isStakeRecord := record.Status == recordstypes.DepositRecord_DELEGATION_QUEUE
isBeforeCurrentEpoch := record.DepositEpochNumber < epochNumber
return isStakeRecord && isBeforeCurrentEpoch
})

if len(stakeDepositRecords) == 0 {
k.Logger(ctx).Info("No deposit records in state DELEGATION_QUEUE")
return
}

// limit the number of staking deposits to process per epoch
maxDepositRecordsToStake := utils.Min(len(stakeDepositRecords), cast.ToInt(k.GetParam(ctx, types.KeyMaxStakeICACallsPerEpoch)))
if maxDepositRecordsToStake < len(stakeDepositRecords) {
k.Logger(ctx).Info(fmt.Sprintf(" MaxStakeICACallsPerEpoch limit reached - Only staking %d out of %d deposit records", maxDepositRecordsToStake, len(stakeDepositRecords)))
}

for _, depositRecord := range stakeDepositRecords[:maxDepositRecordsToStake] {
if depositRecord.Amount.IsZero() {
continue
}
k.Logger(ctx).Info(utils.LogWithHostZone(depositRecord.HostZoneId,
"Processing deposit record %d: %v%s", depositRecord.Id, depositRecord.Amount, depositRecord.Denom))

hostZone, hostZoneFound := k.GetHostZone(ctx, depositRecord.HostZoneId)
if !hostZoneFound {
k.Logger(ctx).Error(fmt.Sprintf("[StakeExistingDepositsOnHostZones] Host zone not found for deposit record {%d}", depositRecord.Id))
continue
}

if hostZone.Halted {
k.Logger(ctx).Error(fmt.Sprintf("[StakeExistingDepositsOnHostZones] Host zone halted for deposit record {%d}", depositRecord.Id))
continue
}

if hostZone.DelegationIcaAddress == "" {
k.Logger(ctx).Error(fmt.Sprintf("[StakeExistingDepositsOnHostZones] Zone %s is missing a delegation address!", hostZone.ChainId))
continue
}

k.Logger(ctx).Info(utils.LogWithHostZone(depositRecord.HostZoneId, "Staking %v%s", depositRecord.Amount, hostZone.HostDenom))
stakeAmount := sdk.NewCoin(hostZone.HostDenom, depositRecord.Amount)

err := k.DelegateOnHost(ctx, hostZone, stakeAmount, depositRecord)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Did not stake %s on %s | err: %s", stakeAmount.String(), hostZone.ChainId, err.Error()))
continue
}
k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "Successfully submitted stake"))

ctx.EventManager().EmitEvent(
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute("hostZone", hostZone.ChainId),
sdk.NewAttribute("newAmountStaked", depositRecord.Amount.String()),
),
)
}
}

// Delegates accrued staking rewards for reinvestment
func (k Keeper) ReinvestRewards(ctx sdk.Context) {
k.Logger(ctx).Info("Reinvesting tokens...")

for _, hostZone := range k.GetAllActiveHostZone(ctx) {
// only process host zones once withdrawal accounts are registered
if hostZone.WithdrawalIcaAddress == "" {
k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "Withdrawal account not registered for host zone"))
continue
}

// read clock time on host zone
blockTime, err := k.GetLightClientTimeSafely(ctx, hostZone.ConnectionId)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Could not find blockTime for host zone %s, err: %s", hostZone.ConnectionId, err.Error()))
continue
}
k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "BlockTime for host zone: %d", blockTime))

err = k.UpdateWithdrawalBalance(ctx, hostZone)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Error updating withdrawal balance for host zone %s: %s", hostZone.ConnectionId, err.Error()))
continue
}
}
}
154 changes: 0 additions & 154 deletions x/stakeibc/keeper/deposit_records.go

This file was deleted.

26 changes: 0 additions & 26 deletions x/stakeibc/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,32 +296,6 @@ func (k Keeper) PostRedemptionRateToOracles(ctx sdk.Context, hostDenom string, r
return nil
}

func (k Keeper) ReinvestRewards(ctx sdk.Context) {
k.Logger(ctx).Info("Reinvesting tokens...")

for _, hostZone := range k.GetAllActiveHostZone(ctx) {
// only process host zones once withdrawal accounts are registered
if hostZone.WithdrawalIcaAddress == "" {
k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "Withdrawal account not registered for host zone"))
continue
}

// read clock time on host zone
blockTime, err := k.GetLightClientTimeSafely(ctx, hostZone.ConnectionId)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Could not find blockTime for host zone %s, err: %s", hostZone.ConnectionId, err.Error()))
continue
}
k.Logger(ctx).Info(utils.LogWithHostZone(hostZone.ChainId, "BlockTime for host zone: %d", blockTime))

err = k.UpdateWithdrawalBalance(ctx, hostZone)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Error updating withdrawal balance for host zone %s: %s", hostZone.ConnectionId, err.Error()))
continue
}
}
}

// TODO [cleanup]: Remove after v17 upgrade
func (k Keeper) DisableHubTokenization(ctx sdk.Context) {
k.Logger(ctx).Info("Disabling the ability to tokenize Gaia delegations")
Expand Down
Loading
Loading