-
Notifications
You must be signed in to change notification settings - Fork 197
/
deposit_records.go
137 lines (116 loc) · 6.52 KB
/
deposit_records.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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package keeper
import (
"fmt"
"strconv"
ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"
sdk "github.com/cosmos/cosmos-sdk/types"
ibctypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types"
"github.com/spf13/cast"
"github.com/Stride-Labs/stride/utils"
recordstypes "github.com/Stride-Labs/stride/x/records/types"
"github.com/Stride-Labs/stride/x/stakeibc/types"
)
func (k Keeper) CreateDepositRecordsForEpoch(ctx sdk.Context, epochNumber uint64) {
// Create one new deposit record / host zone for the next epoch
createDepositRecords := func(ctx sdk.Context, index int64, zoneInfo types.HostZone) error {
k.Logger(ctx).Info(fmt.Sprintf("createDepositRecords, index: %d, zoneInfo: %s", index, zoneInfo.ConnectionId))
depositRecord := recordstypes.DepositRecord{
Id: 0,
Amount: 0,
Denom: zoneInfo.HostDenom,
HostZoneId: zoneInfo.ChainId,
Status: recordstypes.DepositRecord_TRANSFER,
DepositEpochNumber: epochNumber,
}
k.RecordsKeeper.AppendDepositRecord(ctx, depositRecord)
return nil
}
k.IterateHostZones(ctx, createDepositRecords)
}
func (k Keeper) TransferExistingDepositsToHostZones(ctx sdk.Context, epochNumber uint64, depositRecords []recordstypes.DepositRecord) {
transferDepositRecords := utils.FilterDepositRecords(depositRecords, func(record recordstypes.DepositRecord) (condition bool) {
isTransferRecord := record.Status == recordstypes.DepositRecord_TRANSFER
isBeforeCurrentEpoch := record.DepositEpochNumber < epochNumber
return isTransferRecord && isBeforeCurrentEpoch
})
ibcTransferTimeoutNanos := k.GetParam(ctx, types.KeyIBCTransferTimeoutNanos)
for _, depositRecord := range transferDepositRecords {
pstr := fmt.Sprintf("\t[TransferExistingDepositsToHostZones] Processing deposits {%d} {%s} {%d}", depositRecord.Id, depositRecord.Denom, depositRecord.Amount)
k.Logger(ctx).Info(pstr)
// if a TRANSFER record has 0 balance and was created in the previous epoch, it's safe to remove since it will never be updated or used"
if depositRecord.Amount <= 0 {
k.Logger(ctx).Info("[TransferExistingDepositsToHostZones] Empty deposit record (ID: %s)! Removing.", depositRecord.Id)
k.RecordsKeeper.RemoveDepositRecord(ctx, depositRecord.Id)
continue
}
hostZone, hostZoneFound := k.GetHostZone(ctx, depositRecord.HostZoneId)
if !hostZoneFound {
k.Logger(ctx).Error(fmt.Sprintf("[TransferExistingDepositsToHostZones] Host zone not found for deposit record id %d", depositRecord.Id))
continue
}
hostZoneModuleAddress := hostZone.GetAddress()
delegateAccount := hostZone.GetDelegationAccount()
if delegateAccount == nil || delegateAccount.GetAddress() == "" {
k.Logger(ctx).Error(fmt.Sprintf("[TransferExistingDepositsToHostZones] Zone %s is missing a delegation address!", hostZone.ChainId))
continue
}
delegateAddress := delegateAccount.GetAddress()
transferCoin := sdk.NewCoin(hostZone.GetIBCDenom(), sdk.NewInt(depositRecord.Amount))
// timeout 30 min in the future
// NOTE: this assumes no clock drift between chains, which tendermint guarantees
// if we onboard non-tendermint chains, we need to use the time on the host chain to
// calculate the timeout
// https://github.com/tendermint/tendermint/blob/v0.34.x/spec/consensus/bft-time.md
timeoutTimestamp := uint64(ctx.BlockTime().UnixNano()) + ibcTransferTimeoutNanos
msg := ibctypes.NewMsgTransfer(ibctransfertypes.PortID, hostZone.TransferChannelId, transferCoin, hostZoneModuleAddress, delegateAddress, clienttypes.Height{}, timeoutTimestamp)
k.Logger(ctx).Info(fmt.Sprintf("TransferExistingDepositsToHostZones msg %v", msg))
err := k.RecordsKeeper.Transfer(ctx, msg, depositRecord.Id)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("\t[TransferExistingDepositsToHostZones] Failed to initiate IBC transfer to host zone, HostZone: %v, Channel: %v, Amount: %v, ModuleAddress: %v, DelegateAddress: %v, Timeout: %v",
hostZone.ChainId, hostZone.TransferChannelId, transferCoin, hostZoneModuleAddress, delegateAddress, timeoutTimestamp))
k.Logger(ctx).Error(fmt.Sprintf("\t[TransferExistingDepositsToHostZones] err {%s}", err.Error()))
continue
}
}
}
func (k Keeper) StakeExistingDepositsOnHostZones(ctx sdk.Context, epochNumber uint64, depositRecords []recordstypes.DepositRecord) {
stakeDepositRecords := utils.FilterDepositRecords(depositRecords, func(record recordstypes.DepositRecord) (condition bool) {
isStakeRecord := record.Status == recordstypes.DepositRecord_STAKE
isBeforeCurrentEpoch := record.DepositEpochNumber < epochNumber
return isStakeRecord && isBeforeCurrentEpoch
})
// limit the number of staking deposits to process per epoch
maxDepositRecordsToStake := utils.Min(len(stakeDepositRecords), cast.ToInt(k.GetParam(ctx, types.KeyMaxStakeICACallsPerEpoch)))
k.Logger(ctx).Info(fmt.Sprintf("Staking %d out of %d deposit records", maxDepositRecordsToStake, len(stakeDepositRecords)))
for _, depositRecord := range stakeDepositRecords[:maxDepositRecordsToStake] {
k.Logger(ctx).Info(fmt.Sprintf("\t[StakeExistingDepositsOnHostZones] Processing deposit ID:{%d} DENOM:{%s} AMT:{%d}",
depositRecord.Id, depositRecord.Denom, depositRecord.Amount))
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
}
delegateAccount := hostZone.GetDelegationAccount()
if delegateAccount == nil || delegateAccount.GetAddress() == "" {
k.Logger(ctx).Error(fmt.Sprintf("[StakeExistingDepositsOnHostZones] Zone %s is missing a delegation address!", hostZone.ChainId))
continue
}
k.Logger(ctx).Info(fmt.Sprintf("\t[StakeExistingDepositsOnHostZones] Staking %d on %s", depositRecord.Amount, hostZone.HostDenom))
stakeAmount := sdk.NewCoin(hostZone.HostDenom, sdk.NewInt(depositRecord.Amount))
err := k.DelegateOnHost(ctx, hostZone, stakeAmount, depositRecord.Id)
if err != nil {
k.Logger(ctx).Error(fmt.Sprintf("Did not stake %s on %s | err: %s", stakeAmount.String(), hostZone.ChainId, err.Error()))
continue
} else {
k.Logger(ctx).Info(fmt.Sprintf("Successfully submitted stake for %s on %s", stakeAmount.String(), hostZone.ChainId))
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute("hostZone", hostZone.ChainId),
sdk.NewAttribute("newAmountStaked", strconv.FormatInt(depositRecord.Amount, 10)),
),
)
}
}