From aca8af481f8436db3d4efd484d4c4c5b19fd4cd1 Mon Sep 17 00:00:00 2001 From: aljo242 Date: Thu, 9 Mar 2023 17:16:05 -0500 Subject: [PATCH 1/8] DepositTxCallback --- x/interchainstaking/keeper/callbacks.go | 93 ++++++++++++++----------- x/interchainstaking/keeper/receipt.go | 2 +- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/x/interchainstaking/keeper/callbacks.go b/x/interchainstaking/keeper/callbacks.go index 212c1160d..a7ea91c1b 100644 --- a/x/interchainstaking/keeper/callbacks.go +++ b/x/interchainstaking/keeper/callbacks.go @@ -63,7 +63,7 @@ func (c Callbacks) RegisterCallbacks() icqtypes.QueryCallbacks { AddCallback("delegation", Callback(DelegationCallback)). AddCallback("distributerewards", Callback(DistributeRewardsFromWithdrawAccount)). AddCallback("depositinterval", Callback(DepositIntervalCallback)). - AddCallback("deposittx", Callback(DepositTx)). + AddCallback("deposittx", Callback(DepositTxCallback)). AddCallback("perfbalance", Callback(PerfBalanceCallback)). AddCallback("accountbalance", Callback(AccountBalanceCallback)). AddCallback("allbalances", Callback(AllBalancesCallback)) @@ -264,10 +264,10 @@ func checkTrustedHeader(header *tmclienttypes.Header, consState *tmclienttypes.C return nil } -// pulled directly from ibc-go tm light client -// checkValidity checks if the Tendermint header is valid. +// checkTMStateValidity checks if the Tendermint header is valid. // CONTRACT: consState.Height == header.TrustedHeight -func checkValidity( +// pulled directly from ibc-go tm light client +func checkTMStateValidity( clientState *tmclienttypes.ClientState, consState *tmclienttypes.ConsensusState, header *tmclienttypes.Header, currentTimestamp time.Time, ) error { @@ -347,44 +347,19 @@ func checkValidity( return nil } -func DepositTx(k *Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) error { - zone, found := k.GetZone(ctx, query.GetChainId()) - if !found { - return fmt.Errorf("no registered zone for chain id: %s", query.GetChainId()) - } - - if !zone.DepositsEnabled { - return fmt.Errorf("chain id %s does not current allow deposits", query.GetChainId()) - } - - k.Logger(ctx).Debug("DepositTx callback", "zone", zone.ChainId) - - res := icqtypes.GetTxWithProofResponse{} - if len(args) == 0 { - return errors.New("attempted to unmarshal zero length byte slice (6)") - } - err := k.cdc.Unmarshal(args, &res) - if err != nil { - return err - } - - _, found = k.GetReceipt(ctx, types.GetReceiptKey(zone.ChainId, res.GetTxResponse().TxHash)) - if found { - k.Logger(ctx).Debug("Found previously handled tx. Ignoring.", "txhash", res.GetTxResponse().TxHash) - return nil - } - - // validate proof +// CheckTMHeaderForZone verifies the Tendermint consensus and client states for a given zone. Returns error if unable +// to verify. +func (k *Keeper) CheckTMHeaderForZone(ctx sdk.Context, zone *types.Zone, res icqtypes.GetTxWithProofResponse) error { connection, _ := k.IBCKeeper.ConnectionKeeper.GetConnection(ctx, zone.ConnectionId) - clientState, found := k.IBCKeeper.ClientKeeper.GetClientState(ctx, connection.ClientId) if !found { return errors.New("unable to fetch client state") } - - /** we can call ClientKeeper.CheckHeaderAndUpdateState() here, but this causes state changes inside the IBCKeeper which feels bad. - so instead we copy the above two functions wholesale from ibc-go (this sucks too, but with predicatable behaviour) and validate - the inbound header manually. */ + /* + We can call ClientKeeper.CheckHeaderAndUpdateState() here, but this causes state changes inside the IBCKeeper + which feels bad. so instead we copy the above two functions wholesale from ibc-go (this sucks too, but with + predictable behaviour) and validate the inbound header manually. + */ consensusState, found := k.IBCKeeper.ClientKeeper.GetClientConsensusState(ctx, connection.ClientId, res.Header.TrustedHeight) if !found { return fmt.Errorf("unable to fetch consensus state for trusted height: %s", res.Header.TrustedHeight.String()) @@ -400,7 +375,8 @@ func DepositTx(k *Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) er return errors.New("unable to marshal consensus state") } - err = checkValidity(tmclientState, tmconsensusState, res.GetHeader(), ctx.BlockHeader().Time) + // validate tendermint statefor + err := checkTMStateValidity(tmclientState, tmconsensusState, res.GetHeader(), ctx.BlockHeader().Time) if err != nil { return fmt.Errorf("unable to validate header; %w", err) } @@ -414,7 +390,46 @@ func DepositTx(k *Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) er return fmt.Errorf("unable to validate proof: %w", err) } - return k.HandleReceiptTransaction(ctx, res.GetTxResponse(), res.GetTx(), &zone) + return nil +} + +// DepositTxCallback is a callback that verifies client chain state validity, gets Tx receipt and calls +// HandleReceiptForTransaction. +func DepositTxCallback(k *Keeper, ctx sdk.Context, args []byte, query icqtypes.Query) error { + // check validity + if len(args) == 0 { + return errors.New("attempted to unmarshal zero length byte slice (6)") + } + + zone, found := k.GetZone(ctx, query.GetChainId()) + if !found { + return fmt.Errorf("no registered zone for chain id: %s", query.GetChainId()) + } + + if !zone.DepositsEnabled { + return fmt.Errorf("chain id %s does not current allow deposits", query.GetChainId()) + } + + k.Logger(ctx).Debug("DepositTx callback", "zone", zone.ChainId) + + res := icqtypes.GetTxWithProofResponse{} + err := k.cdc.Unmarshal(args, &res) + if err != nil { + return err + } + + _, found = k.GetReceipt(ctx, types.GetReceiptKey(zone.ChainId, res.GetTxResponse().TxHash)) + if found { + k.Logger(ctx).Debug("Found previously handled tx. Ignoring.", "txhash", res.GetTxResponse().TxHash) + return nil + } + + err = k.CheckTMHeaderForZone(ctx, &zone, res) + if err != nil { + return fmt.Errorf("unable to verify proof: %w", err) + } + + return k.HandleReceiptForTransaction(ctx, res.GetTxResponse(), res.GetTx(), &zone) } // AccountBalanceCallback is a callback handler for Balance queries. diff --git a/x/interchainstaking/keeper/receipt.go b/x/interchainstaking/keeper/receipt.go index ce8ab97b7..b4ced513d 100644 --- a/x/interchainstaking/keeper/receipt.go +++ b/x/interchainstaking/keeper/receipt.go @@ -24,7 +24,7 @@ const ( ICAMsgChunkSize = 5 ) -func (k *Keeper) HandleReceiptTransaction(ctx sdk.Context, txr *sdk.TxResponse, txn *tx.Tx, zone *types.Zone) error { +func (k *Keeper) HandleReceiptForTransaction(ctx sdk.Context, txr *sdk.TxResponse, txn *tx.Tx, zone *types.Zone) error { k.Logger(ctx).Info("Deposit receipt.", "ischeck", ctx.IsCheckTx(), "isrecheck", ctx.IsReCheckTx()) hash := txr.TxHash memo := txn.Body.Memo From 9b6a6746d5075179b129db2c283ed810df46a927 Mon Sep 17 00:00:00 2001 From: aljo242 Date: Thu, 9 Mar 2023 17:20:38 -0500 Subject: [PATCH 2/8] transfer port --- x/interchainstaking/keeper/ibc_packet_handlers.go | 6 +----- x/interchainstaking/keeper/receipt.go | 4 ++-- x/interchainstaking/types/ibc_packet.go | 2 ++ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/x/interchainstaking/keeper/ibc_packet_handlers.go b/x/interchainstaking/keeper/ibc_packet_handlers.go index 964ec266e..3a1e249b6 100644 --- a/x/interchainstaking/keeper/ibc_packet_handlers.go +++ b/x/interchainstaking/keeper/ibc_packet_handlers.go @@ -29,10 +29,6 @@ import ( "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) -const ( - transferPort = "transfer" -) - type TypedMsg struct { Msg sdk.Msg Type string @@ -1044,7 +1040,7 @@ func DistributeRewardsFromWithdrawAccount(k *Keeper, ctx sdk.Context, args []byt var remotePort string var remoteChannel string k.IBCKeeper.ChannelKeeper.IterateChannels(ctx, func(channel channeltypes.IdentifiedChannel) bool { - if channel.ConnectionHops[0] == zone.ConnectionId && channel.PortId == transferPort && channel.State == channeltypes.OPEN { + if channel.ConnectionHops[0] == zone.ConnectionId && channel.PortId == types.TransferPort && channel.State == channeltypes.OPEN { remoteChannel = channel.Counterparty.ChannelId remotePort = channel.Counterparty.PortId return true diff --git a/x/interchainstaking/keeper/receipt.go b/x/interchainstaking/keeper/receipt.go index b4ced513d..b051c1901 100644 --- a/x/interchainstaking/keeper/receipt.go +++ b/x/interchainstaking/keeper/receipt.go @@ -33,7 +33,7 @@ func (k *Keeper) HandleReceiptForTransaction(ctx sdk.Context, txr *sdk.TxRespons coins := sdk.Coins{} for _, event := range txr.Events { - if event.Type == transferPort { + if event.Type == types.TransferPort { attrs := types.AttributesToMap(event.Attributes) sender := attrs["sender"] amount := attrs["amount"] @@ -124,7 +124,7 @@ func (k *Keeper) MintQAsset(ctx sdk.Context, sender sdk.AccAddress, senderAddres var srcPort string var srcChannel string k.IBCKeeper.ChannelKeeper.IterateChannels(ctx, func(channel channeltypes.IdentifiedChannel) bool { - if channel.ConnectionHops[0] == zone.ConnectionId && channel.PortId == transferPort && channel.State == channeltypes.OPEN { + if channel.ConnectionHops[0] == zone.ConnectionId && channel.PortId == types.TransferPort && channel.State == channeltypes.OPEN { srcChannel = channel.Counterparty.ChannelId srcPort = channel.Counterparty.PortId return true diff --git a/x/interchainstaking/types/ibc_packet.go b/x/interchainstaking/types/ibc_packet.go index 9bc5a5369..a0c4fd1fe 100644 --- a/x/interchainstaking/types/ibc_packet.go +++ b/x/interchainstaking/types/ibc_packet.go @@ -9,6 +9,8 @@ import ( const ( MsgTypeWithdrawal = "withdrawal" MsgTypeRebalance = "rebalance" + // TransferPort is the portID for ibc transfer module. + TransferPort = "transfer" ) func ParseMsgMemo(memo, msgType string) (epochNumber int64, err error) { From 63818172a84b5862e4907e587d3e92ab38df3567 Mon Sep 17 00:00:00 2001 From: aljo242 Date: Thu, 9 Mar 2023 17:27:23 -0500 Subject: [PATCH 3/8] HandleReceipt --- x/interchainstaking/keeper/receipt.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/x/interchainstaking/keeper/receipt.go b/x/interchainstaking/keeper/receipt.go index b051c1901..daf3154fe 100644 --- a/x/interchainstaking/keeper/receipt.go +++ b/x/interchainstaking/keeper/receipt.go @@ -68,24 +68,25 @@ func (k *Keeper) HandleReceiptForTransaction(ctx sdk.Context, txr *sdk.TxRespons k.Logger(ctx).Error("unable to decode sender address. Ignoring.", "senderAddress", senderAddress) return fmt.Errorf("unable to decode sender address. Ignoring. senderAddress=%q", senderAddress) } + var accAddress sdk.AccAddress = addressBytes if err := zone.ValidateCoinsForZone(ctx, coins); err != nil { - // we expect this to trigger if the validatorset has changed recently (i.e. we haven't seen the validator before. That is okay, we'll catch it next round!) + // we expect this to trigger if the valset has changed recently (i.e. we haven't seen the validator before. + // That is okay, we'll catch it next round!) k.Logger(ctx).Error("unable to validate coins. Ignoring.", "senderAddress", senderAddress) return fmt.Errorf("unable to validate coins. Ignoring. senderAddress=%q", senderAddress) } - var accAddress sdk.AccAddress = addressBytes - - k.Logger(ctx).Info("Found new deposit tx", "deposit_address", zone.DepositAddress.GetAddress(), "sender", senderAddress, "local", accAddress.String(), "chain id", zone.ChainId, "amount", coins, "hash", hash) + k.Logger(ctx).Info("Found new deposit tx", "deposit_address", zone.DepositAddress.GetAddress(), "senderAddress", senderAddress, "local", accAddress.String(), "chain id", zone.ChainId, "amount", coins, "hash", hash) // create receipt if err := k.UpdateIntent(ctx, accAddress, zone, coins, memo); err != nil { - k.Logger(ctx).Error("unable to update intent. Ignoring.", "senderAddress", senderAddress, "zone", zone.ChainId, "err", err) + k.Logger(ctx).Error("unable to update intent. Ignoring.", "senderAddress", senderAddress, "zone", zone.ChainId, "err", err.Error()) return fmt.Errorf("unable to update intent. Ignoring. senderAddress=%q zone=%q err: %w", senderAddress, zone.ChainId, err) } + if err := k.MintQAsset(ctx, accAddress, senderAddress, zone, coins, false); err != nil { - k.Logger(ctx).Error("unable to mint QAsset. Ignoring.", "senderAddress", senderAddress, "zone", zone.ChainId, "err", err) + k.Logger(ctx).Error("unable to mint QAsset. Ignoring.", "senderAddress", senderAddress, "zone", zone.ChainId, "err", err.Error()) return fmt.Errorf("unable to mint QAsset. Ignoring. senderAddress=%q zone=%q err: %w", senderAddress, zone.ChainId, err) } @@ -95,7 +96,6 @@ func (k *Keeper) HandleReceiptForTransaction(ctx sdk.Context, txr *sdk.TxRespons } receipt := k.NewReceipt(ctx, zone, senderAddress, hash, coins) - k.SetReceipt(ctx, *receipt) return nil From adc69c8e8344ab65ed396738bf6c2dafd00ceb5e Mon Sep 17 00:00:00 2001 From: aljo242 Date: Thu, 9 Mar 2023 18:12:51 -0500 Subject: [PATCH 4/8] request redemption --- x/interchainstaking/keeper/intent.go | 51 ++++++------- x/interchainstaking/keeper/msg_server.go | 20 ++---- x/interchainstaking/keeper/receipt.go | 91 +++++++++++++++--------- 3 files changed, 91 insertions(+), 71 deletions(-) diff --git a/x/interchainstaking/keeper/intent.go b/x/interchainstaking/keeper/intent.go index e6afff172..500e5684e 100644 --- a/x/interchainstaking/keeper/intent.go +++ b/x/interchainstaking/keeper/intent.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - "cosmossdk.io/math" + sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -70,7 +70,7 @@ func (k *Keeper) IterateIntents(ctx sdk.Context, zone *types.Zone, snapshot bool // AllIntents returns every intent in the store for the specified zone func (k *Keeper) AllIntents(ctx sdk.Context, zone *types.Zone, snapshot bool) []types.DelegatorIntent { - intents := []types.DelegatorIntent{} + var intents []types.DelegatorIntent k.IterateIntents(ctx, zone, snapshot, func(_ int64, intent types.DelegatorIntent) (stop bool) { intents = append(intents, intent) return false @@ -80,7 +80,7 @@ func (k *Keeper) AllIntents(ctx sdk.Context, zone *types.Zone, snapshot bool) [] // AllIntentsAsPointer returns every intent in the store for the specified zone func (k *Keeper) AllIntentsAsPointer(ctx sdk.Context, zone *types.Zone, snapshot bool) []*types.DelegatorIntent { - intents := []*types.DelegatorIntent{} + var intents []*types.DelegatorIntent k.IterateIntents(ctx, zone, snapshot, func(_ int64, intent types.DelegatorIntent) (stop bool) { intents = append(intents, &intent) return false @@ -102,12 +102,12 @@ func (k *Keeper) AggregateIntents(ctx sdk.Context, zone *types.Zone) error { // return true // } // balance := k.BankKeeper.GetBalance(ctx, addr, zone.LocalDenom) - balance := sdk.NewCoin(zone.LocalDenom, math.ZeroInt()) + balance := sdk.NewCoin(zone.LocalDenom, sdkmath.ZeroInt()) // grab offchain asset value, and raise the users' base value by this amount. // currently ignoring base value (locally held assets) k.ClaimsManagerKeeper.IterateLastEpochUserClaims(ctx, zone.ChainId, intent.Delegator, func(index int64, data prtypes.Claim) (stop bool) { - balance.Amount = balance.Amount.Add(math.NewIntFromUint64(data.Amount)) + balance.Amount = balance.Amount.Add(sdkmath.NewIntFromUint64(data.Amount)) // claim amounts are in zone.baseDenom - but given weights are all relative to one another this okay. k.Logger(ctx).Error("Intents - found claim for user", "user", intent.Delegator, "claim amount", data.Amount, "new balance", balance.Amount) return false @@ -153,10 +153,14 @@ func (k *Keeper) AggregateIntents(ctx sdk.Context, zone *types.Zone) error { return nil } -func (k *Keeper) UpdateIntent(ctx sdk.Context, sender sdk.AccAddress, zone *types.Zone, inAmount sdk.Coins, memo string) error { +// UpdateIntent updates +func (k *Keeper) UpdateIntent(ctx sdk.Context, delegator sdk.AccAddress, zone *types.Zone, inAmount sdk.Coins, memo string) error { snapshot := false + updateWithCoin := inAmount.IsValid() + updateWithMemo := len(memo) > 0 + // this is here because we need access to the bankKeeper to ordinalize intent - intent, _ := k.GetIntent(ctx, zone, sender.String(), snapshot) + delIntent, _ := k.GetIntent(ctx, zone, delegator.String(), snapshot) // ordinalize // this is the currently held amount @@ -165,54 +169,53 @@ func (k *Keeper) UpdateIntent(ctx sdk.Context, sender sdk.AccAddress, zone *type // if balance.Amount.IsNil() { // balance.Amount = math.ZeroInt() // } - balance := sdk.NewCoin(zone.BaseDenom, math.ZeroInt()) + claimAmt := sdkmath.ZeroInt() // grab offchain asset value, and raise the users' base value by this amount. - k.ClaimsManagerKeeper.IterateLastEpochUserClaims(ctx, zone.ChainId, sender.String(), func(index int64, data prtypes.Claim) (stop bool) { - k.Logger(ctx).Error("Update intents - found claim for user", "user", intent.Delegator, "claim amount", data.Amount, "new balance", balance.Amount) - - balance.Amount = balance.Amount.Add(math.NewIntFromUint64(data.Amount)) + k.ClaimsManagerKeeper.IterateLastEpochUserClaims(ctx, zone.ChainId, delegator.String(), func(index int64, claim prtypes.Claim) (stop bool) { + claimAmt = claimAmt.Add(sdkmath.NewIntFromUint64(claim.Amount)) + k.Logger(ctx).Error("Update intents - found claim for user", "user", delIntent.Delegator, "claim amount", claim.Amount, "new balance", claimAmt) return false }) // inAmount is ordinal with respect to the redemption rate, so we must scale - baseBalance := zone.RedemptionRate.Mul(sdk.NewDecFromInt(balance.Amount)) + baseBalance := zone.RedemptionRate.Mul(sdk.NewDecFromInt(claimAmt)) if baseBalance.IsZero() { return nil } - if inAmount.IsValid() { - intent = zone.UpdateIntentWithCoins(intent, baseBalance, inAmount) + if updateWithCoin { + delIntent = zone.UpdateIntentWithCoins(delIntent, baseBalance, inAmount) } - if len(memo) > 0 { + if updateWithMemo { var err error - intent, err = zone.UpdateIntentWithMemo(intent, memo, baseBalance, inAmount) + delIntent, err = zone.UpdateIntentWithMemo(delIntent, memo, baseBalance, inAmount) if err != nil { return err } } - if len(intent.Intents) == 0 { + if len(delIntent.Intents) == 0 { return nil } - k.SetIntent(ctx, zone, intent, snapshot) + k.SetIntent(ctx, zone, delIntent, snapshot) return nil } -func (k msgServer) validateIntents(zone types.Zone, intents []*types.ValidatorIntent) error { - errors := make(map[string]error) +func (k msgServer) validateValidatorIntents(zone types.Zone, intents []*types.ValidatorIntent) error { + errMap := make(map[string]error) for i, intent := range intents { _, found := zone.GetValidatorByValoper(intent.ValoperAddress) if !found { - errors[fmt.Sprintf("intent[%v]", i)] = fmt.Errorf("unable to find valoper %s", intent.ValoperAddress) + errMap[fmt.Sprintf("intent[%v]", i)] = fmt.Errorf("unable to find valoper %s", intent.ValoperAddress) } } - if len(errors) > 0 { - return multierror.New(errors) + if len(errMap) > 0 { + return multierror.New(errMap) } return nil diff --git a/x/interchainstaking/keeper/msg_server.go b/x/interchainstaking/keeper/msg_server.go index 256a7abcf..ab83a26bd 100644 --- a/x/interchainstaking/keeper/msg_server.go +++ b/x/interchainstaking/keeper/msg_server.go @@ -28,6 +28,7 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer { var _ types.MsgServer = msgServer{} +// RequestRedemption handles MsgRequestRedemption by creating a corresponding withdrawal record queued for unbonding. func (k msgServer) RequestRedemption(goCtx context.Context, msg *types.MsgRequestRedemption) (*types.MsgRequestRedemptionResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -55,7 +56,6 @@ func (k msgServer) RequestRedemption(goCtx context.Context, msg *types.MsgReques } var zone *types.Zone - k.IterateZones(ctx, func(_ int64, thisZone *types.Zone) bool { if thisZone.LocalDenom == msg.Value.GetDenom() { zone = thisZone @@ -65,7 +65,7 @@ func (k msgServer) RequestRedemption(goCtx context.Context, msg *types.MsgReques }) // does zone exist? - if nil == zone { + if zone == nil { return nil, fmt.Errorf("unable to find matching zone for denom %s", msg.Value.GetDenom()) } @@ -89,14 +89,8 @@ func (k msgServer) RequestRedemption(goCtx context.Context, msg *types.MsgReques } // get min of LastRedemptionRate (N-1) and RedemptionRate (N) - var rate sdk.Dec - rate = zone.LastRedemptionRate - if zone.RedemptionRate.LT(rate) { - rate = zone.RedemptionRate - } - + rate := sdk.MinDec(zone.LastRedemptionRate, zone.RedemptionRate) nativeTokens := sdk.NewDecFromInt(msg.Value.Amount).Mul(rate).TruncateInt() - outTokens := sdk.NewCoin(zone.BaseDenom, nativeTokens) k.Logger(ctx).Info("tokens to distribute", "amount", outTokens) @@ -106,16 +100,16 @@ func (k msgServer) RequestRedemption(goCtx context.Context, msg *types.MsgReques hashString := hex.EncodeToString(hash[:]) if err := k.BankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.EscrowModuleAccount, sdk.NewCoins(msg.Value)); err != nil { - return nil, err + return nil, fmt.Errorf("unable to send coins to escrow account: %w", err) } if zone.LiquidityModule { if err = k.processRedemptionForLsm(ctx, zone, sender, msg.DestinationAddress, nativeTokens, msg.Value, hashString); err != nil { - return nil, err + return nil, fmt.Errorf("unable to process redemption for LSM: %w", err) } } else { if err = k.queueRedemption(ctx, zone, sender, msg.DestinationAddress, nativeTokens, msg.Value, hashString); err != nil { - return nil, err + return nil, fmt.Errorf("unable to queue redemption: %w", err) } } @@ -152,7 +146,7 @@ func (k msgServer) SignalIntent(goCtx context.Context, msg *types.MsgSignalInten return nil, err } - if err := k.validateIntents(zone, intents); err != nil { + if err := k.validateValidatorIntents(zone, intents); err != nil { return nil, err } diff --git a/x/interchainstaking/keeper/receipt.go b/x/interchainstaking/keeper/receipt.go index daf3154fe..215621d90 100644 --- a/x/interchainstaking/keeper/receipt.go +++ b/x/interchainstaking/keeper/receipt.go @@ -25,12 +25,12 @@ const ( ) func (k *Keeper) HandleReceiptForTransaction(ctx sdk.Context, txr *sdk.TxResponse, txn *tx.Tx, zone *types.Zone) error { - k.Logger(ctx).Info("Deposit receipt.", "ischeck", ctx.IsCheckTx(), "isrecheck", ctx.IsReCheckTx()) + k.Logger(ctx).Info("deposit receipt.", "ischeck", ctx.IsCheckTx(), "isrecheck", ctx.IsReCheckTx()) hash := txr.TxHash memo := txn.Body.Memo senderAddress := Unset - coins := sdk.Coins{} + assets := sdk.Coins{} for _, event := range txr.Events { if event.Type == types.TransferPort { @@ -47,12 +47,12 @@ func (k *Keeper) HandleReceiptForTransaction(ctx sdk.Context, txr *sdk.TxRespons return fmt.Errorf("sender mismatch: expected %q, got %q", senderAddress, sender) } - k.Logger(ctx).Info("Deposit receipt", "deposit_address", zone.DepositAddress.GetAddress(), "sender", sender, "amount", amount) + k.Logger(ctx).Info("deposit receipt", "deposit_address", zone.DepositAddress.GetAddress(), "sender", sender, "amount", amount) thisCoins, err := sdk.ParseCoinsNormalized(amount) if err != nil { k.Logger(ctx).Error("unable to parse coin", "string", amount) } - coins = coins.Add(thisCoins...) + assets = assets.Add(thisCoins...) } } } @@ -68,54 +68,54 @@ func (k *Keeper) HandleReceiptForTransaction(ctx sdk.Context, txr *sdk.TxRespons k.Logger(ctx).Error("unable to decode sender address. Ignoring.", "senderAddress", senderAddress) return fmt.Errorf("unable to decode sender address. Ignoring. senderAddress=%q", senderAddress) } - var accAddress sdk.AccAddress = addressBytes + var senderAccAddress sdk.AccAddress = addressBytes - if err := zone.ValidateCoinsForZone(ctx, coins); err != nil { + if err := zone.ValidateCoinsForZone(ctx, assets); err != nil { // we expect this to trigger if the valset has changed recently (i.e. we haven't seen the validator before. // That is okay, we'll catch it next round!) k.Logger(ctx).Error("unable to validate coins. Ignoring.", "senderAddress", senderAddress) return fmt.Errorf("unable to validate coins. Ignoring. senderAddress=%q", senderAddress) } - k.Logger(ctx).Info("Found new deposit tx", "deposit_address", zone.DepositAddress.GetAddress(), "senderAddress", senderAddress, "local", accAddress.String(), "chain id", zone.ChainId, "amount", coins, "hash", hash) - // create receipt + k.Logger(ctx).Info("found new deposit tx", "deposit_address", zone.DepositAddress.GetAddress(), "senderAddress", senderAddress, "local", senderAccAddress.String(), "chain id", zone.ChainId, "assets", assets, "hash", hash) - if err := k.UpdateIntent(ctx, accAddress, zone, coins, memo); err != nil { + // update state + if err := k.UpdateIntent(ctx, senderAccAddress, zone, assets, memo); err != nil { k.Logger(ctx).Error("unable to update intent. Ignoring.", "senderAddress", senderAddress, "zone", zone.ChainId, "err", err.Error()) return fmt.Errorf("unable to update intent. Ignoring. senderAddress=%q zone=%q err: %w", senderAddress, zone.ChainId, err) } - if err := k.MintQAsset(ctx, accAddress, senderAddress, zone, coins, false); err != nil { + if err := k.MintQAsset(ctx, senderAccAddress, senderAddress, zone, assets); err != nil { k.Logger(ctx).Error("unable to mint QAsset. Ignoring.", "senderAddress", senderAddress, "zone", zone.ChainId, "err", err.Error()) return fmt.Errorf("unable to mint QAsset. Ignoring. senderAddress=%q zone=%q err: %w", senderAddress, zone.ChainId, err) } - if err := k.TransferToDelegate(ctx, zone, coins, hash); err != nil { + if err := k.TransferToDelegate(ctx, zone, assets, hash); err != nil { k.Logger(ctx).Error("unable to transfer to delegate. Ignoring.", "senderAddress", senderAddress, "zone", zone.ChainId, "err", err) return fmt.Errorf("unable to transfer to delegate. Ignoring. senderAddress=%q zone=%q err: %w", senderAddress, zone.ChainId, err) } - receipt := k.NewReceipt(ctx, zone, senderAddress, hash, coins) + // create receipt + receipt := k.NewReceipt(ctx, zone, senderAddress, hash, assets) k.SetReceipt(ctx, *receipt) return nil } -func (k *Keeper) MintQAsset(ctx sdk.Context, sender sdk.AccAddress, senderAddress string, zone *types.Zone, inCoins sdk.Coins, returnToSender bool) error { +// MintQAsset mints qAssets based on the native asset redemption rate. Tokens are then transferred to the given user. +func (k *Keeper) MintQAsset(ctx sdk.Context, sender sdk.AccAddress, senderAddress string, zone *types.Zone, assets sdk.Coins) error { if zone.RedemptionRate.IsZero() { return errors.New("zero redemption rate") } - var err error - - outCoins := sdk.Coins{} - for _, inCoin := range inCoins.Sort() { - outAmount := sdk.NewDecFromInt(inCoin.Amount).Quo(zone.RedemptionRate).TruncateInt() - outCoin := sdk.NewCoin(zone.LocalDenom, outAmount) - outCoins = outCoins.Add(outCoin) + qAssets := sdk.Coins{} + for _, asset := range assets.Sort() { + amount := sdk.NewDecFromInt(asset.Amount).Quo(zone.RedemptionRate).TruncateInt() + qAssets = qAssets.Add(sdk.NewCoin(zone.LocalDenom, amount)) } - k.Logger(ctx).Info("Minting qAssets for receipt", "assets", outCoins) - err = k.BankKeeper.MintCoins(ctx, types.ModuleName, outCoins) + + k.Logger(ctx).Info("Minting qAssets for receipt", "assets", qAssets) + err := k.BankKeeper.MintCoins(ctx, types.ModuleName, qAssets) if err != nil { return err } @@ -123,6 +123,7 @@ func (k *Keeper) MintQAsset(ctx sdk.Context, sender sdk.AccAddress, senderAddres if zone.ReturnToSender { var srcPort string var srcChannel string + k.IBCKeeper.ChannelKeeper.IterateChannels(ctx, func(channel channeltypes.IdentifiedChannel) bool { if channel.ConnectionHops[0] == zone.ConnectionId && channel.PortId == types.TransferPort && channel.State == channeltypes.OPEN { srcChannel = channel.Counterparty.ChannelId @@ -135,22 +136,44 @@ func (k *Keeper) MintQAsset(ctx sdk.Context, sender sdk.AccAddress, senderAddres return errors.New("unable to find remote transfer connection") } - err = k.TransferKeeper.SendTransfer(ctx, srcPort, srcChannel, outCoins[0], k.AccountKeeper.GetModuleAddress(types.ModuleName), senderAddress, clienttypes.Height{RevisionNumber: 0, RevisionHeight: 0}, uint64(ctx.BlockTime().UnixNano()+5*time.Minute.Nanoseconds())) + err = k.TransferKeeper.SendTransfer( + ctx, + srcPort, + srcChannel, + qAssets[0], + k.AccountKeeper.GetModuleAddress(types.ModuleName), + senderAddress, + clienttypes.Height{ + RevisionNumber: 0, + RevisionHeight: 0, + }, + uint64(ctx.BlockTime().UnixNano()+5*time.Minute.Nanoseconds()), + ) } else { + err = k.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, qAssets) + } - err = k.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, sender, outCoins) - k.Logger(ctx).Info("Transferred qAssets to sender", "assets", outCoins, "sender", sender) - + if err != nil { + return fmt.Errorf("unable to transfer coins: %w", err) } - return err + + k.Logger(ctx).Info("Transferred qAssets to sender", "assets", qAssets, "sender", sender) + return nil } +// TransferToDelegate transfers tokens from the zone deposit account address to the zone delegate account address. func (k *Keeper) TransferToDelegate(ctx sdk.Context, zone *types.Zone, coins sdk.Coins, memo string) error { msg := &bankTypes.MsgSend{FromAddress: zone.DepositAddress.GetAddress(), ToAddress: zone.DelegationAddress.GetAddress(), Amount: coins} return k.SubmitTx(ctx, []sdk.Msg{msg}, zone.DepositAddress, memo) } +// SubmitTx submits a Tx on behalf of an ICAAccount to a remote chain. func (k *Keeper) SubmitTx(ctx sdk.Context, msgs []sdk.Msg, account *types.ICAAccount, memo string) error { + // if no messages, do nothing + if len(msgs) == 0 { + return nil + } + portID := account.GetPortName() connectionID, err := k.GetConnectionForPort(ctx, portID) if err != nil { @@ -179,10 +202,7 @@ func (k *Keeper) SubmitTx(ctx sdk.Context, msgs []sdk.Msg, account *types.ICAAcc if len(msgs) < chunkSize { chunkSize = len(msgs) } - - // remove chunk from original msg slice msgsChunk := msgs[0:chunkSize] - msgs = msgs[chunkSize:] // build and submit message for this chunk data, err := icatypes.SerializeCosmosTx(k.cdc, msgsChunk) @@ -201,6 +221,9 @@ func (k *Keeper) SubmitTx(ctx sdk.Context, msgs []sdk.Msg, account *types.ICAAcc if err != nil { return err } + + // remove chunk from original msg slice + msgs = msgs[chunkSize:] } return nil @@ -213,7 +236,7 @@ func (k *Keeper) NewReceipt(ctx sdk.Context, zone *types.Zone, sender string, tx return &types.Receipt{ChainId: zone.ChainId, Sender: sender, Txhash: txhash, Amount: amount, FirstSeen: &t} } -// GetReceipt returns receipt +// GetReceipt returns receipt for the given key. func (k *Keeper) GetReceipt(ctx sdk.Context, key string) (types.Receipt, bool) { receipt := types.Receipt{} store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixReceipt) @@ -226,7 +249,7 @@ func (k *Keeper) GetReceipt(ctx sdk.Context, key string) (types.Receipt, bool) { return receipt, true } -// SetReceipt set receipt info +// SetReceipt sets receipt info. func (k *Keeper) SetReceipt(ctx sdk.Context, receipt types.Receipt) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixReceipt) bz := k.cdc.MustMarshal(&receipt) @@ -266,7 +289,7 @@ func (k *Keeper) AllReceipts(ctx sdk.Context) []types.Receipt { return receipts } -// IterateZoneReceipts iterates through receipts of the given zone +// IterateZoneReceipts iterates through receipts of the given zone. func (k *Keeper) IterateZoneReceipts(ctx sdk.Context, zone *types.Zone, fn func(index int64, receiptInfo types.Receipt) (stop bool)) { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixReceipt) iterator := sdk.KVStorePrefixIterator(store, []byte(zone.ChainId)) @@ -284,7 +307,7 @@ func (k *Keeper) IterateZoneReceipts(ctx sdk.Context, zone *types.Zone, fn func( } } -// UserZoneReceipts returns all receipts of the given user for the given zone +// UserZoneReceipts returns all receipts of the given user for the given zone. func (k *Keeper) UserZoneReceipts(ctx sdk.Context, zone *types.Zone, addr sdk.AccAddress) ([]types.Receipt, error) { receipts := make([]types.Receipt, 0) From dbafc55e7e36754cab9b946ff54bd483168385a9 Mon Sep 17 00:00:00 2001 From: aljo242 Date: Thu, 9 Mar 2023 18:23:55 -0500 Subject: [PATCH 5/8] after epoch end --- x/interchainstaking/keeper/abci.go | 10 +-- x/interchainstaking/keeper/hooks.go | 86 +++++++++++++++++------ x/interchainstaking/keeper/redemptions.go | 2 +- 3 files changed, 70 insertions(+), 28 deletions(-) diff --git a/x/interchainstaking/keeper/abci.go b/x/interchainstaking/keeper/abci.go index 6955986a1..7e906ae88 100644 --- a/x/interchainstaking/keeper/abci.go +++ b/x/interchainstaking/keeper/abci.go @@ -15,7 +15,7 @@ import ( const blockInterval = 30 -type zoneItrFn func(index int64, zoneInfo *types.Zone) (stop bool) +type zoneItrFn func(index int64, zone *types.Zone) (stop bool) // BeginBlocker of interchainstaking module func (k *Keeper) BeginBlocker(ctx sdk.Context) { @@ -35,13 +35,13 @@ func (k *Keeper) BeginBlocker(ctx sdk.Context) { // commenting this out until we can revisit. in its current state it causes more issues than it fixes. if err := k.EnsureWithdrawalAddresses(ctx, zone); err != nil { - k.Logger(ctx).Error("error in EnsureWithdrawalAddresses", "error", err) + k.Logger(ctx).Error("error in EnsureWithdrawalAddresses", "error", err.Error()) } if err := k.HandleMaturedUnbondings(ctx, zone); err != nil { - k.Logger(ctx).Error("error in HandleMaturedUnbondings", "error", err) + k.Logger(ctx).Error("error in HandleMaturedUnbondings", "error", err.Error()) } if err := k.GCCompletedUnbondings(ctx, zone); err != nil { - k.Logger(ctx).Error("error in GCCompletedUnbondings", "error", err) + k.Logger(ctx).Error("error in GCCompletedUnbondings", "error", err.Error()) } } @@ -58,7 +58,7 @@ func (k *Keeper) BeginBlocker(ctx sdk.Context) { query := stakingTypes.QueryValidatorsRequest{} err := k.EmitValSetQuery(ctx, zone, query, sdkmath.NewInt(period)) if err != nil { - k.Logger(ctx).Error("unable to trigger valset update query", "error", err) + k.Logger(ctx).Error("unable to trigger valset update query", "error", err.Error()) // failing to emit the valset update is not terminal but constitutes // an error, as if this starts happening frequent it is something // we should investigate. diff --git a/x/interchainstaking/keeper/hooks.go b/x/interchainstaking/keeper/hooks.go index 5f93b921a..a65fb9816 100644 --- a/x/interchainstaking/keeper/hooks.go +++ b/x/interchainstaking/keeper/hooks.go @@ -14,60 +14,96 @@ func (k *Keeper) BeforeEpochStart(_ sdk.Context, _ string, _ int64) error { return nil } +// AfterEpochEnd is called after any registered epoch ends. +// calls: +// +// k.AggregateIntents +// k.HandleQueuedUnbondings +// k.Rebalance +// +// and re-queries icq for new zone info. func (k *Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { // every epoch if epochIdentifier == "epoch" { - k.Logger(ctx).Info("handling epoch end") + k.Logger(ctx).Info("handling epoch end", "epoch_identifier", epochIdentifier, "epoch_number", epochNumber) - k.IterateZones(ctx, func(index int64, zoneInfo *types.Zone) (stop bool) { + k.IterateZones(ctx, func(index int64, zone *types.Zone) (stop bool) { k.Logger(ctx).Info("taking a snapshot of intents") - err := k.AggregateIntents(ctx, zoneInfo) + err := k.AggregateIntents(ctx, zone) if err != nil { // we can and need not panic here; logging the error is sufficient. // an error here is not expected, but also not terminal. // we don't return on failure here as we still want to attempt // the unrelated tasks below. - k.Logger(ctx).Error("encountered a problem aggregating intents; leaving aggregated intents unchanged since last epoch", "error", err) + k.Logger(ctx).Error( + "encountered a problem aggregating intents; leaving aggregated intents unchanged since last epoch", + "error", err.Error(), + "chain_id", zone.ChainId, + "epoch_identifier", epochIdentifier, + "epoch_number", epochNumber, + ) } - if zoneInfo.DelegationAddress == nil { + if zone.DelegationAddress == nil { // we have reached the end of the epoch and the delegation address is nil. // This shouldn't happen in normal operation, but can if the zone was registered right on the epoch boundary. return false } - if err := k.HandleQueuedUnbondings(ctx, zoneInfo, epochNumber); err != nil { - k.Logger(ctx).Error(err.Error()) + if err := k.HandleQueuedUnbondings(ctx, zone, epochNumber); err != nil { // we can and need not panic here; logging the error is sufficient. // an error here is not expected, but also not terminal. // we don't return on failure here as we still want to attempt // the unrelated tasks below. + k.Logger(ctx).Error( + "encountered a problem handling queued unbondings", + "error", err.Error(), + "chain_id", zone.ChainId, + "epoch_identifier", epochIdentifier, + "epoch_number", epochNumber, + ) } - err = k.Rebalance(ctx, zoneInfo, epochNumber) + err = k.Rebalance(ctx, zone, epochNumber) if err != nil { // we can and need not panic here; logging the error is sufficient. // an error here is not expected, but also not terminal. // we don't return on failure here as we still want to attempt // the unrelated tasks below. - k.Logger(ctx).Error("encountered a problem rebalancing", "error", err.Error()) + k.Logger(ctx).Error( + "encountered a problem rebalancing", + "error", err.Error(), + "chain_id", zone.ChainId, + "epoch_identifier", epochIdentifier, + "epoch_number", epochNumber, + ) } - if zoneInfo.WithdrawalWaitgroup > 0 { - k.Logger(ctx).Error("epoch waitgroup was unexpected > 0; this means we did not process the previous epoch!") - zoneInfo.WithdrawalWaitgroup = 0 + if zone.WithdrawalWaitgroup > 0 { + k.Logger(ctx).Error( + "epoch waitgroup was unexpected > 0; this means we did not process the previous epoch!", + "chain_id", zone.ChainId, + "epoch_identifier", epochIdentifier, + "epoch_number", epochNumber, + ) + zone.WithdrawalWaitgroup = 0 } // OnChanOpenAck calls SetWithdrawalAddress (see ibc_module.go) - k.Logger(ctx).Info("Withdrawing rewards") + k.Logger(ctx).Info( + "withdrawing rewards", + "chain_id", zone.ChainId, + "epoch_identifier", epochIdentifier, + "epoch_number", epochNumber, + ) - delegationQuery := stakingtypes.QueryDelegatorDelegationsRequest{DelegatorAddr: zoneInfo.DelegationAddress.Address, Pagination: &query.PageRequest{Limit: uint64(len(zoneInfo.Validators))}} + delegationQuery := stakingtypes.QueryDelegatorDelegationsRequest{DelegatorAddr: zone.DelegationAddress.Address, Pagination: &query.PageRequest{Limit: uint64(len(zoneInfo.Validators))}} bz := k.cdc.MustMarshal(&delegationQuery) k.ICQKeeper.MakeRequest( ctx, - zoneInfo.ConnectionId, - zoneInfo.ChainId, + zone.ConnectionId, + zone.ChainId, "cosmos.staking.v1beta1.Query/DelegatorDelegations", bz, sdk.NewInt(-1), @@ -76,13 +112,13 @@ func (k *Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNum 0, ) - rewardsQuery := distrtypes.QueryDelegationTotalRewardsRequest{DelegatorAddress: zoneInfo.DelegationAddress.Address} + rewardsQuery := distrtypes.QueryDelegationTotalRewardsRequest{DelegatorAddress: zone.DelegationAddress.Address} bz = k.cdc.MustMarshal(&rewardsQuery) k.ICQKeeper.MakeRequest( ctx, - zoneInfo.ConnectionId, - zoneInfo.ChainId, + zone.ConnectionId, + zone.ChainId, "cosmos.distribution.v1beta1.Query/DelegationTotalRewards", bz, sdk.NewInt(-1), @@ -94,9 +130,14 @@ func (k *Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNum // increment the WithdrawalWaitgroup // this allows us to track the response for every protocol delegator // WithdrawalWaitgroup is decremented in RewardsCallback - zoneInfo.WithdrawalWaitgroup++ - k.Logger(ctx).Info("Incrementing waitgroup for delegation", "value", zoneInfo.WithdrawalWaitgroup) - k.SetZone(ctx, zoneInfo) + zone.WithdrawalWaitgroup++ + k.Logger(ctx).Info("Incrementing waitgroup for delegation", + "value", zone.WithdrawalWaitgroup, + "chain_id", zone.ChainId, + "epoch_identifier", epochIdentifier, + "epoch_number", epochNumber, + ) + k.SetZone(ctx, zone) return false }) @@ -118,6 +159,7 @@ func (k *Keeper) Hooks() Hooks { } // epochs hooks + func (h Hooks) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { return h.k.BeforeEpochStart(ctx, epochIdentifier, epochNumber) } diff --git a/x/interchainstaking/keeper/redemptions.go b/x/interchainstaking/keeper/redemptions.go index f135b7364..bf87fefc4 100644 --- a/x/interchainstaking/keeper/redemptions.go +++ b/x/interchainstaking/keeper/redemptions.go @@ -72,8 +72,8 @@ func (k *Keeper) queueRedemption( hash string, ) error { //nolint:unparam // we know that the error is always nil distribution := make([]*types.Distribution, 0) - amount := sdk.NewCoins(sdk.NewCoin(zone.BaseDenom, nativeTokens)) + k.AddWithdrawalRecord( ctx, zone.ChainId, From 806c7c6e4fc6e10ac49b14d9d59c373ed9c9ebc3 Mon Sep 17 00:00:00 2001 From: aljo242 Date: Thu, 9 Mar 2023 18:27:44 -0500 Subject: [PATCH 6/8] epoch --- x/interchainstaking/keeper/hooks.go | 9 +++++++-- x/interchainstaking/keeper/ibc_packet_handlers.go | 6 +++--- x/interchainstaking/types/interchainstaking.go | 5 +++++ 3 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 x/interchainstaking/types/interchainstaking.go diff --git a/x/interchainstaking/keeper/hooks.go b/x/interchainstaking/keeper/hooks.go index a65fb9816..73f6fc28a 100644 --- a/x/interchainstaking/keeper/hooks.go +++ b/x/interchainstaking/keeper/hooks.go @@ -24,7 +24,7 @@ func (k *Keeper) BeforeEpochStart(_ sdk.Context, _ string, _ int64) error { // and re-queries icq for new zone info. func (k *Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber int64) error { // every epoch - if epochIdentifier == "epoch" { + if epochIdentifier == types.EpochIdentifier { k.Logger(ctx).Info("handling epoch end", "epoch_identifier", epochIdentifier, "epoch_number", epochNumber) k.IterateZones(ctx, func(index int64, zone *types.Zone) (stop bool) { @@ -97,7 +97,12 @@ func (k *Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNum "epoch_number", epochNumber, ) - delegationQuery := stakingtypes.QueryDelegatorDelegationsRequest{DelegatorAddr: zone.DelegationAddress.Address, Pagination: &query.PageRequest{Limit: uint64(len(zoneInfo.Validators))}} + delegationQuery := stakingtypes.QueryDelegatorDelegationsRequest{ + DelegatorAddr: zone.DelegationAddress.Address, + Pagination: &query.PageRequest{ + Limit: uint64(len(zone.Validators)), + }, + } bz := k.cdc.MustMarshal(&delegationQuery) k.ICQKeeper.MakeRequest( diff --git a/x/interchainstaking/keeper/ibc_packet_handlers.go b/x/interchainstaking/keeper/ibc_packet_handlers.go index 3a1e249b6..ae287ba5b 100644 --- a/x/interchainstaking/keeper/ibc_packet_handlers.go +++ b/x/interchainstaking/keeper/ibc_packet_handlers.go @@ -587,7 +587,7 @@ func (k *Keeper) HandleBeginRedelegate(ctx sdk.Context, msg sdk.Msg, completion zone := k.GetZoneForDelegateAccount(ctx, redelegateMsg.DelegatorAddress) record, found := k.GetRedelegationRecord(ctx, zone.ChainId, redelegateMsg.ValidatorSrcAddress, redelegateMsg.ValidatorDstAddress, epochNumber) if !found { - k.Logger(ctx).Error("unable to find redelegation record", "chain", zone.ChainId, "source", redelegateMsg.ValidatorSrcAddress, "dst", redelegateMsg.ValidatorDstAddress, "epoch", epochNumber) + k.Logger(ctx).Error("unable to find redelegation record", "chain", zone.ChainId, "source", redelegateMsg.ValidatorSrcAddress, "dst", redelegateMsg.ValidatorDstAddress, "epoch_number", epochNumber) return fmt.Errorf("unable to find redelegation record for chain %s, src: %s, dst: %s, at epoch %d", zone.ChainId, redelegateMsg.ValidatorSrcAddress, redelegateMsg.ValidatorDstAddress, epochNumber) } k.Logger(ctx).Info("updating redelegation record with completion time", "completion", completion) @@ -596,10 +596,10 @@ func (k *Keeper) HandleBeginRedelegate(ctx sdk.Context, msg sdk.Msg, completion delegation, found := k.GetDelegation(ctx, zone, redelegateMsg.DelegatorAddress, redelegateMsg.ValidatorDstAddress) if !found { - k.Logger(ctx).Error("unable to find delegation record", "chain", zone.ChainId, "source", redelegateMsg.ValidatorSrcAddress, "dst", redelegateMsg.ValidatorDstAddress, "epoch", epochNumber) + k.Logger(ctx).Error("unable to find delegation record", "chain", zone.ChainId, "source", redelegateMsg.ValidatorSrcAddress, "dst", redelegateMsg.ValidatorDstAddress, "epoch_number", epochNumber) return fmt.Errorf("unable to find delegation record for chain %s, src: %s, dst: %s, at epoch %d", zone.ChainId, redelegateMsg.ValidatorSrcAddress, redelegateMsg.ValidatorDstAddress, epochNumber) } - delegation.RedelegationEnd = completion.Unix() // this field should be a timestamp, but lets avoid unnecessary state changes. + delegation.RedelegationEnd = completion.Unix() // this field should be a timestamp, but let's avoid unnecessary state changes. k.SetDelegation(ctx, zone, delegation) return nil } diff --git a/x/interchainstaking/types/interchainstaking.go b/x/interchainstaking/types/interchainstaking.go new file mode 100644 index 000000000..1beb0e5c2 --- /dev/null +++ b/x/interchainstaking/types/interchainstaking.go @@ -0,0 +1,5 @@ +package types + +const ( + EpochIdentifier = "epoch" +) From 9f9ed1b15fc1c21b46d5bfd0c7a894c389ead416 Mon Sep 17 00:00:00 2001 From: aljo242 Date: Thu, 9 Mar 2023 19:32:11 -0500 Subject: [PATCH 7/8] update signatures --- x/airdrop/keeper/claim_handler.go | 2 +- x/airdrop/keeper/msg_server_test.go | 2 +- x/interchainstaking/genesis.go | 6 +- x/interchainstaking/keeper/grpc_query.go | 4 +- x/interchainstaking/keeper/grpc_query_test.go | 2 +- x/interchainstaking/keeper/hooks.go | 10 +- x/interchainstaking/keeper/intent.go | 94 +++++++++++-------- x/interchainstaking/keeper/intent_test.go | 26 ++--- x/interchainstaking/keeper/msg_server.go | 2 +- x/interchainstaking/keeper/msg_server_test.go | 2 +- x/interchainstaking/keeper/receipt.go | 2 +- x/interchainstaking/keeper/redemptions.go | 79 ++++++++-------- x/interchainstaking/types/delegation_test.go | 1 - .../types/interchainstaking.go | 1 + x/interchainstaking/types/proposals_test.go | 3 +- x/interchainstaking/types/validator_test.go | 3 +- x/interchainstaking/types/zones_test.go | 1 - x/participationrewards/keeper/callbacks.go | 4 +- x/participationrewards/keeper/hooks.go | 4 +- x/participationrewards/keeper/keeper_test.go | 2 +- .../keeper/rewards_validatorSelection.go | 2 +- 21 files changed, 133 insertions(+), 119 deletions(-) diff --git a/x/airdrop/keeper/claim_handler.go b/x/airdrop/keeper/claim_handler.go index d85dbfb29..3fb9a9fba 100644 --- a/x/airdrop/keeper/claim_handler.go +++ b/x/airdrop/keeper/claim_handler.go @@ -183,7 +183,7 @@ func (k Keeper) verifyZoneIntent(ctx sdk.Context, chainID string, address string return fmt.Errorf("zone %s not found", chainID) } - intent, ok := k.icsKeeper.GetIntent(ctx, &zone, addr.String(), false) + intent, ok := k.icsKeeper.GetDelegatorIntent(ctx, &zone, addr.String(), false) if !ok || len(intent.Intents) == 0 { return fmt.Errorf("intent not found or no intents set for %s", addr) } diff --git a/x/airdrop/keeper/msg_server_test.go b/x/airdrop/keeper/msg_server_test.go index b95911a90..5a1bebed5 100644 --- a/x/airdrop/keeper/msg_server_test.go +++ b/x/airdrop/keeper/msg_server_test.go @@ -313,7 +313,7 @@ func (suite *KeeperTestSuite) Test_msgServer_Claim() { }, }, } - appA.InterchainstakingKeeper.SetIntent( + appA.InterchainstakingKeeper.SetDelegatorIntent( suite.chainA.GetContext(), &zone, intent, diff --git a/x/interchainstaking/genesis.go b/x/interchainstaking/genesis.go index 69752fc20..0ce1c56d7 100644 --- a/x/interchainstaking/genesis.go +++ b/x/interchainstaking/genesis.go @@ -49,7 +49,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) panic("unable to find zone for delegation") } for _, delegatorIntent := range delegatorIntentsForZone.DelegationIntent { - k.SetIntent(ctx, &zone, *delegatorIntent, false) + k.SetDelegatorIntent(ctx, &zone, *delegatorIntent, false) } } @@ -98,9 +98,9 @@ func ExportDelegatorIntentsPerZone(ctx sdk.Context, k keeper.Keeper) []types.Del delegatorIntentsForZones := make([]types.DelegatorIntentsForZone, 0) k.IterateZones(ctx, func(_ int64, zoneInfo *types.Zone) (stop bool) { // export current epoch intents - delegatorIntentsForZones = append(delegatorIntentsForZones, types.DelegatorIntentsForZone{ChainId: zoneInfo.ChainId, DelegationIntent: k.AllIntentsAsPointer(ctx, zoneInfo, false), Snapshot: false}) + delegatorIntentsForZones = append(delegatorIntentsForZones, types.DelegatorIntentsForZone{ChainId: zoneInfo.ChainId, DelegationIntent: k.AllDelegatorIntentsAsPointer(ctx, zoneInfo, false), Snapshot: false}) // export last epoch intents - delegatorIntentsForZones = append(delegatorIntentsForZones, types.DelegatorIntentsForZone{ChainId: zoneInfo.ChainId, DelegationIntent: k.AllIntentsAsPointer(ctx, zoneInfo, true), Snapshot: true}) + delegatorIntentsForZones = append(delegatorIntentsForZones, types.DelegatorIntentsForZone{ChainId: zoneInfo.ChainId, DelegationIntent: k.AllDelegatorIntentsAsPointer(ctx, zoneInfo, true), Snapshot: true}) return false }) return delegatorIntentsForZones diff --git a/x/interchainstaking/keeper/grpc_query.go b/x/interchainstaking/keeper/grpc_query.go index 19e6dd1c4..b9623502d 100644 --- a/x/interchainstaking/keeper/grpc_query.go +++ b/x/interchainstaking/keeper/grpc_query.go @@ -102,8 +102,8 @@ func (k *Keeper) DelegatorIntent(c context.Context, req *types.QueryDelegatorInt } // we can ignore bool (found) as it always returns true - // - see comment in GetIntent - intent, _ := k.GetIntent(ctx, &zone, req.DelegatorAddress, false) + // - see comment in GetDelegatorIntent + intent, _ := k.GetDelegatorIntent(ctx, &zone, req.DelegatorAddress, false) return &types.QueryDelegatorIntentResponse{Intent: &intent}, nil } diff --git a/x/interchainstaking/keeper/grpc_query_test.go b/x/interchainstaking/keeper/grpc_query_test.go index 3408f78fa..e44bd631b 100644 --- a/x/interchainstaking/keeper/grpc_query_test.go +++ b/x/interchainstaking/keeper/grpc_query_test.go @@ -212,7 +212,7 @@ func (suite *KeeperTestSuite) TestKeeper_DelegatorIntent() { }, } for _, intent := range intents { - icsKeeper.SetIntent(ctx, &zone, intent, false) + icsKeeper.SetDelegatorIntent(ctx, &zone, intent, false) } }, &types.QueryDelegatorIntentRequest{ diff --git a/x/interchainstaking/keeper/hooks.go b/x/interchainstaking/keeper/hooks.go index 73f6fc28a..c8618acac 100644 --- a/x/interchainstaking/keeper/hooks.go +++ b/x/interchainstaking/keeper/hooks.go @@ -17,7 +17,7 @@ func (k *Keeper) BeforeEpochStart(_ sdk.Context, _ string, _ int64) error { // AfterEpochEnd is called after any registered epoch ends. // calls: // -// k.AggregateIntents +// k.AggregateDelegatorIntents // k.HandleQueuedUnbondings // k.Rebalance // @@ -28,8 +28,12 @@ func (k *Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNum k.Logger(ctx).Info("handling epoch end", "epoch_identifier", epochIdentifier, "epoch_number", epochNumber) k.IterateZones(ctx, func(index int64, zone *types.Zone) (stop bool) { - k.Logger(ctx).Info("taking a snapshot of intents") - err := k.AggregateIntents(ctx, zone) + k.Logger(ctx).Info( + "taking a snapshot of delegator intents", + "epoch_identifier", epochIdentifier, + "epoch_number", epochNumber, + ) + err := k.AggregateDelegatorIntents(ctx, zone) if err != nil { // we can and need not panic here; logging the error is sufficient. // an error here is not expected, but also not terminal. diff --git a/x/interchainstaking/keeper/intent.go b/x/interchainstaking/keeper/intent.go index 500e5684e..431eb5e1c 100644 --- a/x/interchainstaking/keeper/intent.go +++ b/x/interchainstaking/keeper/intent.go @@ -20,8 +20,8 @@ func (k *Keeper) getStoreKey(zone *types.Zone, snapshot bool) []byte { return append(types.KeyPrefixIntent, []byte(zone.ChainId)...) } -// GetIntent returns intent info by zone and delegator -func (k *Keeper) GetIntent(ctx sdk.Context, zone *types.Zone, delegator string, snapshot bool) (types.DelegatorIntent, bool) { +// GetDelegatorIntent returns intent info by zone and delegator +func (k *Keeper) GetDelegatorIntent(ctx sdk.Context, zone *types.Zone, delegator string, snapshot bool) (types.DelegatorIntent, bool) { intent := types.DelegatorIntent{} store := prefix.NewStore(ctx.KVStore(k.storeKey), k.getStoreKey(zone, snapshot)) bz := store.Get([]byte(delegator)) @@ -33,21 +33,21 @@ func (k *Keeper) GetIntent(ctx sdk.Context, zone *types.Zone, delegator string, return intent, true } -// SetIntent store the delegator intent -func (k *Keeper) SetIntent(ctx sdk.Context, zone *types.Zone, intent types.DelegatorIntent, snapshot bool) { +// SetDelegatorIntent store the delegator intent +func (k *Keeper) SetDelegatorIntent(ctx sdk.Context, zone *types.Zone, intent types.DelegatorIntent, snapshot bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.getStoreKey(zone, snapshot)) bz := k.cdc.MustMarshal(&intent) store.Set([]byte(intent.Delegator), bz) } -// DeleteIntent deletes delegator intent -func (k *Keeper) DeleteIntent(ctx sdk.Context, zone *types.Zone, delegator string, snapshot bool) { +// DeleteDelegatorIntent deletes delegator intent +func (k *Keeper) DeleteDelegatorIntent(ctx sdk.Context, zone *types.Zone, delegator string, snapshot bool) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.getStoreKey(zone, snapshot)) store.Delete([]byte(delegator)) } -// IterateIntents iterate through intents for a given zone -func (k *Keeper) IterateIntents(ctx sdk.Context, zone *types.Zone, snapshot bool, fn func(index int64, intent types.DelegatorIntent) (stop bool)) { +// IterateDelegatorIntents iterate through delegator intents for a given zone +func (k *Keeper) IterateDelegatorIntents(ctx sdk.Context, zone *types.Zone, snapshot bool, fn func(index int64, intent types.DelegatorIntent) (stop bool)) { store := prefix.NewStore(ctx.KVStore(k.storeKey), k.getStoreKey(zone, snapshot)) iterator := sdk.KVStorePrefixIterator(store, nil) @@ -68,34 +68,34 @@ func (k *Keeper) IterateIntents(ctx sdk.Context, zone *types.Zone, snapshot bool } } -// AllIntents returns every intent in the store for the specified zone -func (k *Keeper) AllIntents(ctx sdk.Context, zone *types.Zone, snapshot bool) []types.DelegatorIntent { +// AllDelegatorIntents returns every intent in the store for the specified zone +func (k *Keeper) AllDelegatorIntents(ctx sdk.Context, zone *types.Zone, snapshot bool) []types.DelegatorIntent { var intents []types.DelegatorIntent - k.IterateIntents(ctx, zone, snapshot, func(_ int64, intent types.DelegatorIntent) (stop bool) { + k.IterateDelegatorIntents(ctx, zone, snapshot, func(_ int64, intent types.DelegatorIntent) (stop bool) { intents = append(intents, intent) return false }) return intents } -// AllIntentsAsPointer returns every intent in the store for the specified zone -func (k *Keeper) AllIntentsAsPointer(ctx sdk.Context, zone *types.Zone, snapshot bool) []*types.DelegatorIntent { +// AllDelegatorIntentsAsPointer returns every intent in the store for the specified zone +func (k *Keeper) AllDelegatorIntentsAsPointer(ctx sdk.Context, zone *types.Zone, snapshot bool) []*types.DelegatorIntent { var intents []*types.DelegatorIntent - k.IterateIntents(ctx, zone, snapshot, func(_ int64, intent types.DelegatorIntent) (stop bool) { + k.IterateDelegatorIntents(ctx, zone, snapshot, func(_ int64, intent types.DelegatorIntent) (stop bool) { intents = append(intents, &intent) return false }) return intents } -func (k *Keeper) AggregateIntents(ctx sdk.Context, zone *types.Zone) error { - var err error +// AggregateDelegatorIntents takes a snapshot of delegator intents for a given zone. +func (k *Keeper) AggregateDelegatorIntents(ctx sdk.Context, zone *types.Zone) error { snapshot := false aggregate := make(types.ValidatorIntents, 0) ordinalizedIntentSum := sdk.ZeroDec() // reduce intents - k.IterateIntents(ctx, zone, snapshot, func(_ int64, intent types.DelegatorIntent) (stop bool) { + k.IterateDelegatorIntents(ctx, zone, snapshot, func(_ int64, delIntent types.DelegatorIntent) (stop bool) { // addr, localErr := sdk.AccAddressFromBech32(intent.Delegator) // if localErr != nil { // err = localErr @@ -106,32 +106,40 @@ func (k *Keeper) AggregateIntents(ctx sdk.Context, zone *types.Zone) error { // grab offchain asset value, and raise the users' base value by this amount. // currently ignoring base value (locally held assets) - k.ClaimsManagerKeeper.IterateLastEpochUserClaims(ctx, zone.ChainId, intent.Delegator, func(index int64, data prtypes.Claim) (stop bool) { + k.ClaimsManagerKeeper.IterateLastEpochUserClaims(ctx, zone.ChainId, delIntent.Delegator, func(index int64, data prtypes.Claim) (stop bool) { balance.Amount = balance.Amount.Add(sdkmath.NewIntFromUint64(data.Amount)) // claim amounts are in zone.baseDenom - but given weights are all relative to one another this okay. - k.Logger(ctx).Error("Intents - found claim for user", "user", intent.Delegator, "claim amount", data.Amount, "new balance", balance.Amount) + k.Logger(ctx).Error( + "intents - found claim for user", + "user", delIntent.Delegator, + "claim amount", data.Amount, + "new balance", balance.Amount, + ) return false }) - intents := intent.Ordinalize(sdk.NewDecFromInt(balance.Amount)).Intents - k.Logger(ctx).Error("Intents - ordinalized", "user", intent.Delegator, "new balance", balance.Amount, "normal intents", intent.Intents, "intents", intents) - - for vIntent := range intents.Sort() { - thisIntent, ok := aggregate.GetForValoper(intents[vIntent].ValoperAddress) - ordinalizedIntentSum = ordinalizedIntentSum.Add(intents[vIntent].Weight) - if !ok { - aggregate = append(aggregate, intents[vIntent]) + valIntents := delIntent.Ordinalize(sdk.NewDecFromInt(balance.Amount)).Intents + k.Logger(ctx).Error( + "intents - ordinalized", + "user", delIntent.Delegator, + "new balance", balance.Amount, + "normal intents", delIntent.Intents, + "intents", valIntents, + ) + + for idx := range valIntents.Sort() { + valIntent, found := aggregate.GetForValoper(valIntents[idx].ValoperAddress) + ordinalizedIntentSum = ordinalizedIntentSum.Add(valIntents[idx].Weight) + if !found { + aggregate = append(aggregate, valIntents[idx]) } else { - thisIntent.Weight = thisIntent.Weight.Add(intents[vIntent].Weight) - aggregate = aggregate.SetForValoper(intents[vIntent].ValoperAddress, thisIntent) + valIntent.Weight = valIntent.Weight.Add(valIntents[idx].Weight) + aggregate = aggregate.SetForValoper(valIntents[idx].ValoperAddress, valIntent) } } return false }) - if err != nil { - return err - } if len(aggregate) > 0 && ordinalizedIntentSum.IsZero() { return errors.New("ordinalized intent sum is zero, this may happen if no claims are recorded") @@ -139,28 +147,32 @@ func (k *Keeper) AggregateIntents(ctx sdk.Context, zone *types.Zone) error { // normalise aggregated intents again. newAggregate := make(types.ValidatorIntents, 0) - for _, intent := range aggregate.Sort() { - if !intent.Weight.IsZero() && intent.Weight.IsPositive() { - intent.Weight = intent.Weight.Quo(ordinalizedIntentSum) - newAggregate = append(newAggregate, intent) + for _, valIntent := range aggregate.Sort() { + if !valIntent.Weight.IsZero() && valIntent.Weight.IsPositive() { + valIntent.Weight = valIntent.Weight.Quo(ordinalizedIntentSum) + newAggregate = append(newAggregate, valIntent) } } - k.Logger(ctx).Info("aggregates", "agg", newAggregate, "chain", zone.ChainId) + k.Logger(ctx).Info( + "aggregates", + "agg", newAggregate, + "chain", zone.ChainId, + ) zone.AggregateIntent = newAggregate k.SetZone(ctx, zone) return nil } -// UpdateIntent updates -func (k *Keeper) UpdateIntent(ctx sdk.Context, delegator sdk.AccAddress, zone *types.Zone, inAmount sdk.Coins, memo string) error { +// UpdateDelegatorIntent updates +func (k *Keeper) UpdateDelegatorIntent(ctx sdk.Context, delegator sdk.AccAddress, zone *types.Zone, inAmount sdk.Coins, memo string) error { snapshot := false updateWithCoin := inAmount.IsValid() updateWithMemo := len(memo) > 0 // this is here because we need access to the bankKeeper to ordinalize intent - delIntent, _ := k.GetIntent(ctx, zone, delegator.String(), snapshot) + delIntent, _ := k.GetDelegatorIntent(ctx, zone, delegator.String(), snapshot) // ordinalize // this is the currently held amount @@ -200,7 +212,7 @@ func (k *Keeper) UpdateIntent(ctx sdk.Context, delegator sdk.AccAddress, zone *t return nil } - k.SetIntent(ctx, zone, delIntent, snapshot) + k.SetDelegatorIntent(ctx, zone, delIntent, snapshot) return nil } diff --git a/x/interchainstaking/keeper/intent_test.go b/x/interchainstaking/keeper/intent_test.go index 7d077045f..3a76cb2e0 100644 --- a/x/interchainstaking/keeper/intent_test.go +++ b/x/interchainstaking/keeper/intent_test.go @@ -26,11 +26,11 @@ func (suite *KeeperTestSuite) TestKeeper_IntentStore() { zoneValidatorAddresses := zone.GetValidatorsAddressesAsSlice() // check that there are no intents - intents := icsKeeper.AllIntents(ctx, &zone, false) + intents := icsKeeper.AllDelegatorIntents(ctx, &zone, false) suite.Require().Len(intents, 0) // set intents for testAddress - icsKeeper.SetIntent( + icsKeeper.SetDelegatorIntent( ctx, &zone, icstypes.DelegatorIntent{ @@ -57,7 +57,7 @@ func (suite *KeeperTestSuite) TestKeeper_IntentStore() { false, ) // set intents for user1 - icsKeeper.SetIntent( + icsKeeper.SetDelegatorIntent( ctx, &zone, icstypes.DelegatorIntent{ @@ -84,7 +84,7 @@ func (suite *KeeperTestSuite) TestKeeper_IntentStore() { false, ) // set intents for user2 - icsKeeper.SetIntent( + icsKeeper.SetDelegatorIntent( ctx, &zone, icstypes.DelegatorIntent{ @@ -108,20 +108,20 @@ func (suite *KeeperTestSuite) TestKeeper_IntentStore() { ) // check for intents set above - intents = icsKeeper.AllIntents(ctx, &zone, false) + intents = icsKeeper.AllDelegatorIntents(ctx, &zone, false) suite.Require().Len(intents, 3) // delete intent for testAddress - icsKeeper.DeleteIntent(ctx, &zone, testAddress, false) + icsKeeper.DeleteDelegatorIntent(ctx, &zone, testAddress, false) // check intents - intents = icsKeeper.AllIntents(ctx, &zone, false) + intents = icsKeeper.AllDelegatorIntents(ctx, &zone, false) suite.Require().Len(intents, 2) suite.T().Logf("intents:\n%+v\n", intents) // update intent for user1 - err := icsKeeper.UpdateIntent( + err := icsKeeper.UpdateDelegatorIntent( ctx, user2, &zone, @@ -136,7 +136,7 @@ func (suite *KeeperTestSuite) TestKeeper_IntentStore() { suite.Require().NoError(err) // load and match pointers - intentsPointers := icsKeeper.AllIntentsAsPointer(ctx, &zone, false) + intentsPointers := icsKeeper.AllDelegatorIntentsAsPointer(ctx, &zone, false) for i, ip := range intentsPointers { suite.Require().Equal(intents[i], *ip) } @@ -322,10 +322,10 @@ func (suite *KeeperTestSuite) TestAggregateIntent() { } for _, intent := range tt.intents(zone) { - icsKeeper.SetIntent(ctx, &zone, intent, false) + icsKeeper.SetDelegatorIntent(ctx, &zone, intent, false) } - icsKeeper.AggregateIntents(ctx, &zone) + icsKeeper.AggregateDelegatorIntents(ctx, &zone) // refresh zone to pull new aggregate zone, found = icsKeeper.GetZone(ctx, suite.chainB.ChainID) @@ -433,14 +433,14 @@ func (suite *KeeperTestSuite) TestAggregateIntent() { // } // for _, intent := range tt.intents(zone) { -// icsKeeper.SetIntent(ctx, zone, intent, false) +// icsKeeper.SetDelegatorIntent(ctx, zone, intent, false) // } // for _, claim := range tt.claims(zone) { // qapp.ClaimsManagerKeeper.SetLastEpochClaim(ctx, &claim) // } -// icsKeeper.AggregateIntents(ctx, zone) +// icsKeeper.AggregateDelegatorIntents(ctx, zone) // // refresh zone to pull new aggregate // zone, found = icsKeeper.GetZone(ctx, s.chainB.ChainID) diff --git a/x/interchainstaking/keeper/msg_server.go b/x/interchainstaking/keeper/msg_server.go index ab83a26bd..4fca31e39 100644 --- a/x/interchainstaking/keeper/msg_server.go +++ b/x/interchainstaking/keeper/msg_server.go @@ -155,7 +155,7 @@ func (k msgServer) SignalIntent(goCtx context.Context, msg *types.MsgSignalInten Intents: intents, } - k.SetIntent(ctx, &zone, intent, false) + k.SetDelegatorIntent(ctx, &zone, intent, false) ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( diff --git a/x/interchainstaking/keeper/msg_server_test.go b/x/interchainstaking/keeper/msg_server_test.go index 0e2c7395a..f8cd817e9 100644 --- a/x/interchainstaking/keeper/msg_server_test.go +++ b/x/interchainstaking/keeper/msg_server_test.go @@ -527,7 +527,7 @@ func (s *KeeperTestSuite) TestSignalIntent() { zone, found := icsKeeper.GetZone(s.chainA.GetContext(), s.chainB.ChainID) s.Require().True(found) - intent, found := icsKeeper.GetIntent(s.chainA.GetContext(), &zone, testAddress, false) + intent, found := icsKeeper.GetDelegatorIntent(s.chainA.GetContext(), &zone, testAddress, false) s.Require().True(found) intents := intent.GetIntents() diff --git a/x/interchainstaking/keeper/receipt.go b/x/interchainstaking/keeper/receipt.go index 215621d90..10432c232 100644 --- a/x/interchainstaking/keeper/receipt.go +++ b/x/interchainstaking/keeper/receipt.go @@ -80,7 +80,7 @@ func (k *Keeper) HandleReceiptForTransaction(ctx sdk.Context, txr *sdk.TxRespons k.Logger(ctx).Info("found new deposit tx", "deposit_address", zone.DepositAddress.GetAddress(), "senderAddress", senderAddress, "local", senderAccAddress.String(), "chain id", zone.ChainId, "assets", assets, "hash", hash) // update state - if err := k.UpdateIntent(ctx, senderAccAddress, zone, assets, memo); err != nil { + if err := k.UpdateDelegatorIntent(ctx, senderAccAddress, zone, assets, memo); err != nil { k.Logger(ctx).Error("unable to update intent. Ignoring.", "senderAddress", senderAddress, "zone", zone.ChainId, "err", err.Error()) return fmt.Errorf("unable to update intent. Ignoring. senderAddress=%q zone=%q err: %w", senderAddress, zone.ChainId, err) } diff --git a/x/interchainstaking/keeper/redemptions.go b/x/interchainstaking/keeper/redemptions.go index bf87fefc4..5af5b07d6 100644 --- a/x/interchainstaking/keeper/redemptions.go +++ b/x/interchainstaking/keeper/redemptions.go @@ -17,7 +17,7 @@ import ( // processRedemptionForLsm will determine based on user intent, the tokens to return to the user, generate Redeem message and send them. func (k *Keeper) processRedemptionForLsm(ctx sdk.Context, zone *types.Zone, sender sdk.AccAddress, destination string, nativeTokens math.Int, burnAmount sdk.Coin, hash string) error { - intent, found := k.GetIntent(ctx, zone, sender.String(), false) + intent, found := k.GetDelegatorIntent(ctx, zone, sender.String(), false) // msgs is slice of MsgTokenizeShares, so we can handle dust allocation later. msgs := make([]*lsmstakingtypes.MsgTokenizeShares, 0) intents := intent.Intents @@ -122,12 +122,12 @@ func (k *Keeper) GetUnlockedTokensForZone(ctx sdk.Context, zone *types.Zone) (ma // a single unbond transaction per delegation. func (k *Keeper) HandleQueuedUnbondings(ctx sdk.Context, zone *types.Zone, epoch int64) error { // out here will only ever be in native bond denom - out := make(map[string]sdk.Coin, 0) - txhashes := make(map[string][]string, 0) + valOutCoinsMap := make(map[string]sdk.Coin, 0) + txHashes := make(map[string][]string, 0) totalToWithdraw := sdk.NewCoin(zone.BaseDenom, sdk.ZeroInt()) - distributions := make(map[string][]*types.Distribution, 0) - amounts := make(map[string]sdk.Coin, 0) + txDistrsMap := make(map[string][]*types.Distribution, 0) + txCoinMap := make(map[string]sdk.Coin, 0) _, totalAvailable := k.GetUnlockedTokensForZone(ctx, zone) k.IterateZoneStatusWithdrawalRecords(ctx, zone.ChainId, WithdrawStatusQueued, func(idx int64, withdrawal types.WithdrawalRecord) bool { @@ -143,8 +143,8 @@ func (k *Keeper) HandleQueuedUnbondings(ctx sdk.Context, zone *types.Zone, epoch } totalToWithdraw = totalToWithdraw.Add(withdrawal.Amount[0]) - amounts[withdrawal.Txhash] = withdrawal.Amount[0] - distributions[withdrawal.Txhash] = make([]*types.Distribution, 0) + txCoinMap[withdrawal.Txhash] = withdrawal.Amount[0] + txDistrsMap[withdrawal.Txhash] = make([]*types.Distribution, 0) return false }) @@ -153,53 +153,50 @@ func (k *Keeper) HandleQueuedUnbondings(ctx sdk.Context, zone *types.Zone, epoch return nil } - allocations := k.DeterminePlanForUndelegation(ctx, zone, sdk.NewCoins(totalToWithdraw)) - valopers := utils.Keys(allocations) + allocationsMap := k.DeterminePlanForUndelegation(ctx, zone, sdk.NewCoins(totalToWithdraw)) + valopers := utils.Keys(allocationsMap) vidx := 0 v := valopers[vidx] WITHDRAWAL: - for _, hash := range utils.Keys(amounts) { + for _, hash := range utils.Keys(txCoinMap) { for { - fmt.Println(amounts[hash].Amount) - if amounts[hash].Amount.IsZero() { + if txCoinMap[hash].Amount.IsZero() { continue WITHDRAWAL } - if allocations[v].GT(amounts[hash].Amount) { - allocations[v] = allocations[v].Sub(amounts[hash].Amount) - distributions[hash] = append(distributions[hash], &types.Distribution{Valoper: v, Amount: amounts[hash].Amount.Uint64()}) - existing, found := out[v] + if allocationsMap[v].GT(txCoinMap[hash].Amount) { + allocationsMap[v] = allocationsMap[v].Sub(txCoinMap[hash].Amount) + txDistrsMap[hash] = append(txDistrsMap[hash], &types.Distribution{Valoper: v, Amount: txCoinMap[hash].Amount.Uint64()}) + existing, found := valOutCoinsMap[v] if !found { - out[v] = amounts[hash] - txhashes[v] = []string{hash} + valOutCoinsMap[v] = txCoinMap[hash] + txHashes[v] = []string{hash} } else { - out[v] = existing.Add(amounts[hash]) - txhashes[v] = append(txhashes[v], hash) + valOutCoinsMap[v] = existing.Add(txCoinMap[hash]) + txHashes[v] = append(txHashes[v], hash) } - amounts[hash] = sdk.NewCoin(amounts[hash].Denom, sdk.ZeroInt()) + txCoinMap[hash] = sdk.NewCoin(txCoinMap[hash].Denom, sdk.ZeroInt()) continue WITHDRAWAL } else { - distributions[hash] = append(distributions[hash], &types.Distribution{Valoper: v, Amount: allocations[v].Uint64()}) - amounts[hash] = sdk.NewCoin(amounts[hash].Denom, amounts[hash].Amount.Sub(allocations[v])) - existing, found := out[v] + txDistrsMap[hash] = append(txDistrsMap[hash], &types.Distribution{Valoper: v, Amount: allocationsMap[v].Uint64()}) + txCoinMap[hash] = sdk.NewCoin(txCoinMap[hash].Denom, txCoinMap[hash].Amount.Sub(allocationsMap[v])) + existing, found := valOutCoinsMap[v] if !found { - out[v] = sdk.NewCoin(zone.BaseDenom, allocations[v]) - txhashes[v] = []string{hash} + valOutCoinsMap[v] = sdk.NewCoin(zone.BaseDenom, allocationsMap[v]) + txHashes[v] = []string{hash} } else { - out[v] = existing.Add(sdk.NewCoin(zone.BaseDenom, allocations[v])) - txhashes[v] = append(txhashes[v], hash) + valOutCoinsMap[v] = existing.Add(sdk.NewCoin(zone.BaseDenom, allocationsMap[v])) + txHashes[v] = append(txHashes[v], hash) } - allocations[v] = sdk.ZeroInt() + allocationsMap[v] = sdk.ZeroInt() } - if allocations[v].IsZero() { - fmt.Println("valopers len", len(valopers)) - fmt.Println("vidx+1", vidx+1) + if allocationsMap[v].IsZero() { if len(valopers) > vidx+1 { vidx++ v = valopers[vidx] } else { - if !amounts[hash].Amount.IsZero() { + if !txCoinMap[hash].Amount.IsZero() { return fmt.Errorf("unable to satisfy unbonding") } continue WITHDRAWAL @@ -208,26 +205,26 @@ WITHDRAWAL: } } - for _, hash := range utils.Keys(distributions) { + for _, hash := range utils.Keys(txDistrsMap) { record, found := k.GetWithdrawalRecord(ctx, zone.ChainId, hash, WithdrawStatusQueued) if !found { return errors.New("unable to find withdrawal record") } - record.Distribution = distributions[hash] + record.Distribution = txDistrsMap[hash] k.UpdateWithdrawalRecordStatus(ctx, &record, WithdrawStatusUnbond) } - if len(txhashes) == 0 { + if len(txHashes) == 0 { // no records to handle. return nil } var msgs []sdk.Msg - for _, valoper := range utils.Keys(out) { - if !out[valoper].Amount.IsZero() { - sort.Strings(txhashes[valoper]) - k.SetUnbondingRecord(ctx, types.UnbondingRecord{ChainId: zone.ChainId, EpochNumber: epoch, Validator: valoper, RelatedTxhash: txhashes[valoper]}) - msgs = append(msgs, &stakingtypes.MsgUndelegate{DelegatorAddress: zone.DelegationAddress.Address, ValidatorAddress: valoper, Amount: out[valoper]}) + for _, valoper := range utils.Keys(valOutCoinsMap) { + if !valOutCoinsMap[valoper].Amount.IsZero() { + sort.Strings(txHashes[valoper]) + k.SetUnbondingRecord(ctx, types.UnbondingRecord{ChainId: zone.ChainId, EpochNumber: epoch, Validator: valoper, RelatedTxhash: txHashes[valoper]}) + msgs = append(msgs, &stakingtypes.MsgUndelegate{DelegatorAddress: zone.DelegationAddress.Address, ValidatorAddress: valoper, Amount: valOutCoinsMap[valoper]}) } } diff --git a/x/interchainstaking/types/delegation_test.go b/x/interchainstaking/types/delegation_test.go index 10021643f..0e340f0bf 100644 --- a/x/interchainstaking/types/delegation_test.go +++ b/x/interchainstaking/types/delegation_test.go @@ -103,7 +103,6 @@ func TestNormalizeValidatorIntentsDeterminism(t *testing.T) { } }) } - } func TestDetermineAllocationsForDelegation(t *testing.T) { diff --git a/x/interchainstaking/types/interchainstaking.go b/x/interchainstaking/types/interchainstaking.go index 1beb0e5c2..ead9ff85a 100644 --- a/x/interchainstaking/types/interchainstaking.go +++ b/x/interchainstaking/types/interchainstaking.go @@ -1,5 +1,6 @@ package types const ( + // EpochIdentifier is the identifier that is checked against when running epoch hooks. EpochIdentifier = "epoch" ) diff --git a/x/interchainstaking/types/proposals_test.go b/x/interchainstaking/types/proposals_test.go index 0b6eca921..59d8eecc2 100644 --- a/x/interchainstaking/types/proposals_test.go +++ b/x/interchainstaking/types/proposals_test.go @@ -1,10 +1,11 @@ package types_test import ( - "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" "strings" "testing" + "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" + "github.com/stretchr/testify/require" ) diff --git a/x/interchainstaking/types/validator_test.go b/x/interchainstaking/types/validator_test.go index e3c9e4faf..e00e03a20 100644 --- a/x/interchainstaking/types/validator_test.go +++ b/x/interchainstaking/types/validator_test.go @@ -1,10 +1,11 @@ package types_test import ( + "testing" + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" - "testing" "github.com/ingenuity-build/quicksilver/utils" "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" diff --git a/x/interchainstaking/types/zones_test.go b/x/interchainstaking/types/zones_test.go index 818c4d2d4..ad7151be6 100644 --- a/x/interchainstaking/types/zones_test.go +++ b/x/interchainstaking/types/zones_test.go @@ -497,7 +497,6 @@ func TestUpdateIntentWithCoins(t *testing.T) { } } } - } func TestZone_GetBondedValidatorAddressesAsSlice(t *testing.T) { diff --git a/x/participationrewards/keeper/callbacks.go b/x/participationrewards/keeper/callbacks.go index 6fde9d003..1e968ff2f 100644 --- a/x/participationrewards/keeper/callbacks.go +++ b/x/participationrewards/keeper/callbacks.go @@ -86,8 +86,8 @@ func ValidatorSelectionRewardsCallback(k Keeper, ctx sdk.Context, response []byt } // create snapshot of current intents for next epoch boundary - for _, di := range k.icsKeeper.AllIntents(ctx, &zone, false) { - k.icsKeeper.SetIntent(ctx, &zone, di, true) + for _, di := range k.icsKeeper.AllDelegatorIntents(ctx, &zone, false) { + k.icsKeeper.SetDelegatorIntent(ctx, &zone, di, true) } // set zone ValidatorSelectionAllocation to zero diff --git a/x/participationrewards/keeper/hooks.go b/x/participationrewards/keeper/hooks.go index 909f609cb..37717190d 100644 --- a/x/participationrewards/keeper/hooks.go +++ b/x/participationrewards/keeper/hooks.go @@ -77,8 +77,8 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumb // ValidatorSelectionRewardsCallback; for _, zone := range k.icsKeeper.AllZones(ctx) { zone := zone - for _, di := range k.icsKeeper.AllIntents(ctx, &zone, false) { - k.icsKeeper.SetIntent(ctx, &zone, di, true) + for _, di := range k.icsKeeper.AllDelegatorIntents(ctx, &zone, false) { + k.icsKeeper.SetDelegatorIntent(ctx, &zone, di, true) } } diff --git a/x/participationrewards/keeper/keeper_test.go b/x/participationrewards/keeper/keeper_test.go index 24bd69ac0..292f41fce 100644 --- a/x/participationrewards/keeper/keeper_test.go +++ b/x/participationrewards/keeper/keeper_test.go @@ -503,7 +503,7 @@ func (suite *KeeperTestSuite) addIntent(address string, zone icstypes.Zone, inte Delegator: address, Intents: intents, } - suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetIntent(suite.chainA.GetContext(), &zone, intent, false) + suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper.SetDelegatorIntent(suite.chainA.GetContext(), &zone, intent, false) } func (suite *KeeperTestSuite) setupTestClaims() { diff --git a/x/participationrewards/keeper/rewards_validatorSelection.go b/x/participationrewards/keeper/rewards_validatorSelection.go index 34f3073a4..df1b969b2 100644 --- a/x/participationrewards/keeper/rewards_validatorSelection.go +++ b/x/participationrewards/keeper/rewards_validatorSelection.go @@ -270,7 +270,7 @@ func (k Keeper) calcUserValidatorSelectionAllocations( sum := sdk.NewDec(0) userScores := make([]userScore, 0) // obtain snapshotted intents of last epoch boundary - for _, di := range k.icsKeeper.AllIntents(ctx, zone, true) { + for _, di := range k.icsKeeper.AllDelegatorIntents(ctx, zone, true) { uSum := sdk.NewDec(0) for _, intent := range di.GetIntents() { // calc overall user score From d3031a70dc94800bfb9b86c9cc6f8b01a6d2ec00 Mon Sep 17 00:00:00 2001 From: aljo242 Date: Thu, 9 Mar 2023 19:37:01 -0500 Subject: [PATCH 8/8] format --- x/interchainstaking/types/proposals_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/interchainstaking/types/proposals_test.go b/x/interchainstaking/types/proposals_test.go index 59d8eecc2..c9ab9ba3a 100644 --- a/x/interchainstaking/types/proposals_test.go +++ b/x/interchainstaking/types/proposals_test.go @@ -4,9 +4,9 @@ import ( "strings" "testing" - "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" - "github.com/stretchr/testify/require" + + "github.com/ingenuity-build/quicksilver/x/interchainstaking/types" ) func TestRegisterZoneProposal_ValidateBasic(t *testing.T) {