-
Notifications
You must be signed in to change notification settings - Fork 197
/
icacallbacks_detokenize.go
87 lines (74 loc) · 3.58 KB
/
icacallbacks_detokenize.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package keeper
import (
"fmt"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/gogoproto/proto"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
"github.com/Stride-Labs/stride/v16/utils"
icacallbackstypes "github.com/Stride-Labs/stride/v16/x/icacallbacks/types"
recordstypes "github.com/Stride-Labs/stride/v16/x/records/types"
"github.com/Stride-Labs/stride/v16/x/stakeibc/types"
)
// ICACallback after an LSM token is detokenized into native stake
//
// If successful: Remove the token deposit from the store and incremenet the validator delegation
// If failure: flag the deposit as DETOKENIZATION_FAILED
// If timeout: do nothing
// - A timeout will force the channel closed, and once the channel is restored,
// the ICA will get resubmitted
func (k Keeper) DetokenizeCallback(ctx sdk.Context, packet channeltypes.Packet, ackResponse *icacallbackstypes.AcknowledgementResponse, args []byte) error {
// Fetch callback args
detokenizeCallback := types.DetokenizeSharesCallback{}
if err := proto.Unmarshal(args, &detokenizeCallback); err != nil {
return errorsmod.Wrapf(types.ErrUnmarshalFailure, "unable to unmarshal detokenize callback: %s", err.Error())
}
chainId := detokenizeCallback.Deposit.ChainId
deposit := detokenizeCallback.Deposit
k.Logger(ctx).Info(utils.LogICACallbackWithHostZone(chainId, ICACallbackID_Detokenize, "Starting detokenize callback"))
// Regardless of failure/success/timeout, indicate that this ICA has completed
hostZone, found := k.GetHostZone(ctx, chainId)
if !found {
return errorsmod.Wrapf(types.ErrHostZoneNotFound, "Host zone not found: %s", chainId)
}
if err := k.DecrementValidatorDelegationChangesInProgress(&hostZone, deposit.ValidatorAddress); err != nil {
return err
}
k.SetHostZone(ctx, hostZone)
// No action is necessary on a timeout
if ackResponse.Status == icacallbackstypes.AckResponseStatus_TIMEOUT {
k.Logger(ctx).Error(utils.LogICACallbackStatusWithHostZone(chainId, ICACallbackID_Detokenize,
icacallbackstypes.AckResponseStatus_TIMEOUT, packet))
return nil
}
// If the ICA failed, update the deposit status
if ackResponse.Status == icacallbackstypes.AckResponseStatus_FAILURE {
k.Logger(ctx).Error(utils.LogICACallbackStatusWithHostZone(chainId, ICACallbackID_Detokenize,
icacallbackstypes.AckResponseStatus_FAILURE, packet))
k.RecordsKeeper.UpdateLSMTokenDepositStatus(ctx, *deposit, recordstypes.LSMTokenDeposit_DETOKENIZATION_FAILED)
return nil
}
k.Logger(ctx).Info(utils.LogICACallbackStatusWithHostZone(chainId, ICACallbackID_Detokenize,
icacallbackstypes.AckResponseStatus_SUCCESS, packet))
// If the ICA succeeded, remove the token deposit
k.RecordsKeeper.RemoveLSMTokenDeposit(ctx, deposit.ChainId, deposit.Denom)
// Determine the actual number of tokens that were turned to native stake
// (this can be slightly different than the amount initiated in the redeem tokens tx
// due a precision error in the SDK)
if len(ackResponse.MsgResponses) != 1 {
return fmt.Errorf("Invalid number of messages (%d) in detokenize response: %v",
len(ackResponse.MsgResponses), ackResponse.MsgResponses)
}
var detokenizeResponse types.MsgRedeemTokensForSharesResponse
if err := proto.Unmarshal(ackResponse.MsgResponses[0], &detokenizeResponse); err != nil {
return err
}
stakeAmount := detokenizeResponse.Amount.Amount
// Update delegation on the host zone and validator
err := k.AddDelegationToValidator(ctx, &hostZone, deposit.ValidatorAddress, stakeAmount, ICACallbackID_Detokenize)
if err != nil {
return err
}
k.SetHostZone(ctx, hostZone)
return nil
}