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

[LSM] Scaffolding #706

Merged
merged 13 commits into from
Apr 6, 2023
11 changes: 7 additions & 4 deletions app/upgrades/v5/upgrades_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
recordtypes "github.com/Stride-Labs/stride/v8/x/records/types"
stakeibckeeper "github.com/Stride-Labs/stride/v8/x/stakeibc/keeper"
oldstakeibctypes "github.com/Stride-Labs/stride/v8/x/stakeibc/migrations/v2/types"
newstakeibctypes "github.com/Stride-Labs/stride/v8/x/stakeibc/migrations/v3/types"
stakeibctypes "github.com/Stride-Labs/stride/v8/x/stakeibc/types"
)

Expand Down Expand Up @@ -371,15 +372,17 @@ func (s *UpgradeTestSuite) SetupOldStakeibcStore(codec codec.Codec) func() {

// Callback to check stakeibc store after migration
return func() {
hostZone, found := s.App.StakeibcKeeper.GetHostZone(s.Ctx, hostZoneId)
s.Require().True(found, "host zone found")
hostZoneBz := hostzoneStore.Get([]byte(hostZone.ChainId))
var hostZone newstakeibctypes.HostZone
codec.MustUnmarshal(hostZoneBz, &hostZone)

s.Require().Equal(hostZone.ChainId, hostZoneId, "host zone chain id")

s.Require().Equal(hostZone.DelegationAccount.Address, delegationAddress, "delegation address")
s.Require().Equal(hostZone.RedemptionAccount.Address, redemptionAddress, "redemption address")

s.Require().Equal(hostZone.DelegationAccount.Target, stakeibctypes.ICAAccountType_DELEGATION, "delegation target")
s.Require().Equal(hostZone.RedemptionAccount.Target, stakeibctypes.ICAAccountType_REDEMPTION, "redemption target")
s.Require().Equal(hostZone.DelegationAccount.Target, newstakeibctypes.ICAAccountType_DELEGATION, "delegation target")
s.Require().Equal(hostZone.RedemptionAccount.Target, newstakeibctypes.ICAAccountType_REDEMPTION, "redemption target")

s.Require().Nil(hostZone.FeeAccount, "fee account")
s.Require().Nil(hostZone.WithdrawalAccount, "withdrawal account")
Expand Down
22 changes: 13 additions & 9 deletions proto/stride/stakeibc/callbacks.proto
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
syntax = "proto3";
package stride.stakeibc;
option go_package = "github.com/Stride-Labs/stride/v8/x/stakeibc/types";

import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "stride/stakeibc/lsm.proto";

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

// ---------------------- Delegation Callbacks ---------------------- //
message SplitDelegation {
string validator = 1;
string amount = 2 [
Expand All @@ -19,15 +21,12 @@ message DelegateCallback {
repeated SplitDelegation split_delegations = 3;
}

// ---------------------- Claim Callbacks ---------------------- //

message ClaimCallback {
string user_redemption_record_id = 1;
string chain_id = 2;
uint64 epoch_number = 3;
}

// ---------------------- Reinvest Callback ---------------------- //
message ReinvestCallback {
cosmos.base.v1beta1.Coin reinvest_amount = 1 [
(gogoproto.nullable) = false,
Expand All @@ -36,21 +35,17 @@ message ReinvestCallback {
string host_zone_id = 3;
}

// ---------------------- Undelegation Callbacks ---------------------- //
message UndelegateCallback {
string host_zone_id = 1;
repeated SplitDelegation split_delegations = 2;
repeated uint64 epoch_unbonding_record_ids = 3;
}

// ---------------------- Redemption Callbacks ---------------------- //
message RedemptionCallback {
string host_zone_id = 1;
repeated uint64 epoch_unbonding_record_ids = 2;
}

// ---------------- Validator Rebalance Callbacks ---------------------- //

message Rebalancing {
string src_validator = 1;
string dst_validator = 2;
Expand All @@ -63,4 +58,13 @@ message Rebalancing {
message RebalanceCallback {
string host_zone_id = 1;
repeated Rebalancing rebalancings = 2;
}

message TransferLSMTokenCallback { LSMTokenDeposit deposit = 1; }

message DetokenizeSharesCallback { LSMTokenDeposit deposit = 1; }

message RebalanceTokenizedDepositsCallback {
string chain_id = 1;
repeated SplitDelegation split_delegations = 2;
}
11 changes: 6 additions & 5 deletions proto/stride/stakeibc/host_zone.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "cosmos_proto/cosmos.proto";

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

// next id: 22
// next id: 23
message HostZone {
string chain_id = 1;
string connection_id = 2;
Expand All @@ -24,8 +24,6 @@ message HostZone {
string ibc_denom = 8;
// native denom on host zone
string host_denom = 9;
// TODO(TEST-68): Should we make this an array and store the last n redemption
// rates then calculate a TWARR?
string last_redemption_rate = 10 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
Expand All @@ -38,8 +36,11 @@ message HostZone {
];
// stores how many days we should wait before issuing unbondings
uint64 unbonding_frequency = 14;
// TODO(TEST-101) int to dec
string staked_bal = 13 [
string total_balanced_delegations = 13 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string total_unbalanced_delegations = 22 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
Expand Down
36 changes: 36 additions & 0 deletions proto/stride/stakeibc/lsm.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
syntax = "proto3";
package stride.stakeibc;

import "cosmos/base/v1beta1/coin.proto";
import "gogoproto/gogo.proto";

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

enum LSMDepositStatus {
option (gogoproto.goproto_enum_prefix) = false;

TRANSFER_IN_PROGRESS = 0;
TRANSFER_FAILED = 1;
ethan-stride marked this conversation as resolved.
Show resolved Hide resolved
DETOKENIZATION_QUEUE = 2;
DETOKENIZATION_IN_PROGRESS = 3;
DETOKENIZATION_FAILED = 4;
}

message LSMTokenDeposit {
string denom = 1;
string chain_id = 2;
string validator_address = 3;
string amount = 4 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
LSMDepositStatus status = 5;
}

message LSMLiquidStake {
string staker = 1;
cosmos.base.v1beta1.Coin lsm_token = 2 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"
];
}
16 changes: 11 additions & 5 deletions proto/stride/stakeibc/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import "cosmos_proto/cosmos.proto";
// Msg defines the Msg service.
service Msg {
rpc LiquidStake(MsgLiquidStake) returns (MsgLiquidStakeResponse);
rpc LSMLiquidStake(MsgLSMLiquidStake) returns (MsgLSMLiquidStakeResponse);
rpc RedeemStake(MsgRedeemStake) returns (MsgRedeemStakeResponse);
rpc RegisterHostZone(MsgRegisterHostZone)
returns (MsgRegisterHostZoneResponse);
Expand All @@ -37,9 +38,18 @@ message MsgLiquidStake {
];
string host_denom = 3;
}

message MsgLiquidStakeResponse {}

message MsgLSMLiquidStake {
string creator = 1;
string amount = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string lsm_token_denom = 3;
}
message MsgLSMLiquidStakeResponse { bool transaction_complete = 1; }

message MsgClearBalance {
string creator = 1;
string chain_id = 2;
Expand All @@ -49,7 +59,6 @@ message MsgClearBalance {
];
string channel = 4;
}

message MsgClearBalanceResponse {}

message MsgRedeemStake {
Expand All @@ -61,7 +70,6 @@ message MsgRedeemStake {
string host_zone = 3;
string receiver = 4;
}

message MsgRedeemStakeResponse {}

// next: 15
Expand Down Expand Up @@ -89,7 +97,6 @@ message MsgRegisterHostZone {
(gogoproto.nullable) = false
];
}

message MsgRegisterHostZoneResponse {}

message MsgClaimUndelegatedTokens {
Expand All @@ -99,7 +106,6 @@ message MsgClaimUndelegatedTokens {
uint64 epoch = 3;
string sender = 4;
}

message MsgClaimUndelegatedTokensResponse {}

message MsgRebalanceValidators {
Expand Down
10 changes: 9 additions & 1 deletion proto/stride/stakeibc/validator.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,15 @@ message ValidatorExchangeRate {
message Validator {
string name = 1;
string address = 2 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
string delegation_amt = 5 [
string balanced_delegation = 5 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string unbalanced_delegation = 8 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
string progress_towards_exchange_rate_query = 9 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
Expand Down
27 changes: 27 additions & 0 deletions x/records/keeper/callback_lsm_transfer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package keeper

import (
"github.com/Stride-Labs/stride/v8/utils"
icacallbackstypes "github.com/Stride-Labs/stride/v8/x/icacallbacks/types"
"github.com/Stride-Labs/stride/v8/x/records/types"
stakeibctypes "github.com/Stride-Labs/stride/v8/x/stakeibc/types"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types"
"github.com/golang/protobuf/proto" //nolint:staticcheck
)

func LSMTransferCallback(k Keeper, ctx sdk.Context, packet channeltypes.Packet, ackResponse *icacallbackstypes.AcknowledgementResponse, args []byte) error {
// Fetch callback args
transferCallback := stakeibctypes.TransferLSMTokenCallback{}
if err := proto.Unmarshal(args, &transferCallback); err != nil {
return errorsmod.Wrapf(types.ErrUnmarshalFailure, "unable to unmarshal LSM transfer callback: %s", err.Error())
}
chainId := transferCallback.Deposit.ChainId
k.Logger(ctx).Info(utils.LogICACallbackWithHostZone(chainId, IBCCallbacksID_LSMTransfer, "Starting LSM transfer callback"))

// TODO [LSM]

return nil
}
7 changes: 5 additions & 2 deletions x/records/keeper/callbacks.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import (
channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types"
)

const TRANSFER = "transfer"
const IBCCallbacksID_NativeTransfer = "transfer"
const IBCCallbacksID_LSMTransfer = "lsm-transfer"

// ICACallbacks wrapper struct for stakeibc keeper
type ICACallback func(Keeper, sdk.Context, channeltypes.Packet, *icacallbackstypes.AcknowledgementResponse, []byte) error
Expand Down Expand Up @@ -38,6 +39,8 @@ func (c ICACallbacks) AddICACallback(id string, fn interface{}) icacallbackstype
}

func (c ICACallbacks) RegisterICACallbacks() icacallbackstypes.ICACallbackHandler {
a := c.AddICACallback(TRANSFER, ICACallback(TransferCallback))
a := c.
AddICACallback(IBCCallbacksID_NativeTransfer, ICACallback(TransferCallback)).
AddICACallback(IBCCallbacksID_LSMTransfer, ICACallback(LSMTransferCallback))
return a.(ICACallbacks)
}
2 changes: 1 addition & 1 deletion x/records/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ func (k Keeper) Transfer(ctx sdk.Context, msg *ibctypes.MsgTransfer, depositReco
PortId: msg.SourcePort,
ChannelId: msg.SourceChannel,
Sequence: sequence,
CallbackId: TRANSFER,
CallbackId: IBCCallbacksID_NativeTransfer,
CallbackArgs: marshalledCallbackArgs,
}
k.Logger(ctx).Info(utils.LogWithHostZone(depositRecord.HostZoneId, "Storing callback data: %+v", callback))
Expand Down
1 change: 1 addition & 0 deletions x/stakeibc/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func GetTxCmd() *cobra.Command {
}

cmd.AddCommand(CmdLiquidStake())
cmd.AddCommand(CmdLSMLiquidStake())
cmd.AddCommand(CmdRegisterHostZone())
cmd.AddCommand(CmdRedeemStake())
cmd.AddCommand(CmdClaimUndelegatedTokens())
Expand Down
48 changes: 48 additions & 0 deletions x/stakeibc/client/cli/tx_lsm_liquid_stake.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package cli

import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"

errorsmod "cosmossdk.io/errors"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/spf13/cobra"

"github.com/Stride-Labs/stride/v8/x/stakeibc/types"
)

func CmdLSMLiquidStake() *cobra.Command {
cmd := &cobra.Command{
Use: "lsm-liquid-stake [amount] [lsm-token-denom]",
Short: "Broadcast message lsm-liquid-stake",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) (err error) {
amount, found := sdk.NewIntFromString(args[0])
if !found {
return errorsmod.Wrap(sdkerrors.ErrInvalidType, "can not convert string to int")
}
denom := args[1]

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgLSMLiquidStake(
clientCtx.GetFromAddress().String(),
amount,
denom,
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
1 change: 0 additions & 1 deletion x/stakeibc/client/cli/tx_register_host_zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const (

var _ = strconv.Itoa(0)

// TODO(TEST-53): Remove this pre-launch (no need for clients to create / interact with ICAs)
func CmdRegisterHostZone() *cobra.Command {
cmd := &cobra.Command{
Use: "register-host-zone [connection-id] [host-denom] [bech32prefix] [ibc-denom] [channel-id] [unbonding-frequency]",
Expand Down
3 changes: 3 additions & 0 deletions x/stakeibc/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
case *types.MsgLiquidStake:
res, err := msgServer.LiquidStake(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgLSMLiquidStake:
res, err := msgServer.LSMLiquidStake(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgClearBalance:
res, err := msgServer.ClearBalance(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
Expand Down
Loading