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

feat: add MsgSideChainStakeMigration and StakeMigrationApp #367

Merged
merged 6 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions x/stake/client/cli/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func AddCommands(root *cobra.Command, cdc *codec.Codec) {
GetCmdSideChainDelegate(cdc),
GetCmdSideChainRedelegate(cdc),
GetCmdSideChainUnbond(cdc),
GetCmdSideChainStakeMigration(cdc),
)...,
)
stakingCmd.AddCommand(client.LineBreak)
Expand Down
48 changes: 27 additions & 21 deletions x/stake/client/cli/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import (

// nolint
const (
FlagAddressDelegator = "address-delegator"
FlagAddressValidator = "validator"
FlagAddressValidatorSrc = "addr-validator-source"
FlagAddressValidatorDst = "addr-validator-dest"
FlagPubKey = "pubkey"
FlagAmount = "amount"
FlagSharesAmount = "shares-amount"
FlagSharesPercent = "shares-percent"
FlagAddressDelegator = "address-delegator"
FlagAddressValidator = "validator"
FlagAddressValidatorSrc = "addr-validator-source"
FlagAddressValidatorDst = "addr-validator-dest"
FlagAddressSmartChainValidator = "address-smart-chain-validator"
FlagAddressSmartChainBeneficiary = "address-smart-chain-beneficiary"
FlagPubKey = "pubkey"
FlagAmount = "amount"
FlagSharesAmount = "shares-amount"
FlagSharesPercent = "shares-percent"

FlagMoniker = "moniker"
FlagIdentity = "identity"
Expand Down Expand Up @@ -48,19 +50,21 @@ const (

// common flagsets to add to various functions
var (
fsPk = flag.NewFlagSet("", flag.ContinueOnError)
fsAmount = flag.NewFlagSet("", flag.ContinueOnError)
fsShares = flag.NewFlagSet("", flag.ContinueOnError)
fsDescriptionCreate = flag.NewFlagSet("", flag.ContinueOnError)
fsCommissionCreate = flag.NewFlagSet("", flag.ContinueOnError)
fsCommissionUpdate = flag.NewFlagSet("", flag.ContinueOnError)
fsDescriptionEdit = flag.NewFlagSet("", flag.ContinueOnError)
fsValidator = flag.NewFlagSet("", flag.ContinueOnError)
fsDelegator = flag.NewFlagSet("", flag.ContinueOnError)
fsRedelegation = flag.NewFlagSet("", flag.ContinueOnError)
fsSideChainFull = flag.NewFlagSet("", flag.ContinueOnError)
fsSideChainEdit = flag.NewFlagSet("", flag.ContinueOnError)
fsSideChainId = flag.NewFlagSet("", flag.ContinueOnError)
fsPk = flag.NewFlagSet("", flag.ContinueOnError)
fsAmount = flag.NewFlagSet("", flag.ContinueOnError)
fsShares = flag.NewFlagSet("", flag.ContinueOnError)
fsDescriptionCreate = flag.NewFlagSet("", flag.ContinueOnError)
fsCommissionCreate = flag.NewFlagSet("", flag.ContinueOnError)
fsCommissionUpdate = flag.NewFlagSet("", flag.ContinueOnError)
fsDescriptionEdit = flag.NewFlagSet("", flag.ContinueOnError)
fsValidator = flag.NewFlagSet("", flag.ContinueOnError)
fsDelegator = flag.NewFlagSet("", flag.ContinueOnError)
fsRedelegation = flag.NewFlagSet("", flag.ContinueOnError)
fsSideChainFull = flag.NewFlagSet("", flag.ContinueOnError)
fsSideChainEdit = flag.NewFlagSet("", flag.ContinueOnError)
fsSideChainId = flag.NewFlagSet("", flag.ContinueOnError)
fsSmartChainValidator = flag.NewFlagSet("", flag.ContinueOnError)
fsSmartChainBeneficiary = flag.NewFlagSet("", flag.ContinueOnError)
)

func init() {
Expand Down Expand Up @@ -97,4 +101,6 @@ func init() {
fsSideChainEdit.String(FlagBLSWalletDir, "", "Absolute path of BLS wallet, should be provided if the side vote address is provided")
fsSideChainEdit.String(FlagBLSPassword, "", "Password for BLS wallet")
fsSideChainId.String(FlagSideChainId, "", "Chain-id of the side chain the validator belongs to")
fsSmartChainValidator.String(FlagAddressSmartChainValidator, "", "Smart chain operator address of the validator")
fsSmartChainBeneficiary.String(FlagAddressSmartChainBeneficiary, "", "Smart chain address of the delegation's beneficiary")
}
59 changes: 57 additions & 2 deletions x/stake/client/cli/tx_sidechain.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/stake"
sTypes "github.com/cosmos/cosmos-sdk/x/stake/types"

"github.com/prysmaticlabs/prysm/v4/crypto/bls"
"github.com/prysmaticlabs/prysm/v4/crypto/bls/common"
validatorpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1/validator-client"
Expand Down Expand Up @@ -161,7 +163,6 @@ func GetCmdEditSideChainValidator(cdc *codec.Codec) *cobra.Command {
msg = stake.NewMsgEditSideChainValidatorWithVoteAddr(sideChainId, sdk.ValAddress(valAddr), description, newRate, sideFeeAddr, sideConsAddr, sideVoteAddr)
} else {
msg = stake.NewMsgEditSideChainValidator(sideChainId, sdk.ValAddress(valAddr), description, newRate, sideFeeAddr, sideConsAddr)

}
return utils.GenerateOrBroadcastMsgs(txBldr, cliCtx, []sdk.Msg{msg})
}
Expand Down Expand Up @@ -263,7 +264,7 @@ func GetCmdSideChainRedelegate(cdc *codec.Codec) *cobra.Command {
func GetCmdSideChainUnbond(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "bsc-unbond",
Short: "",
Short: "Undelegate illiquid tokens from the validator",
RunE: func(cmd *cobra.Command, args []string) error {
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
Expand Down Expand Up @@ -300,6 +301,51 @@ func GetCmdSideChainUnbond(cdc *codec.Codec) *cobra.Command {
return cmd
}

func GetCmdSideChainStakeMigration(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "bsc-stake-migration",
Short: "Migrate delegation from Beacon Chain to Smart Chain",
RunE: func(cmd *cobra.Command, args []string) error {
txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))

valAddr, err := getValidatorAddr(FlagAddressValidator)
if err != nil {
return err
}
operatorAddr, err := getSmartChainAddr(FlagAddressSmartChainValidator)
if err != nil {
return err
}
delAddr, err := getSmartChainAddr(FlagAddressSmartChainBeneficiary)
if err != nil {
return err
}
refundAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}

amount, err := getAmount()
if err != nil {
return err
}

msg := sTypes.NewMsgSideChainStakeMigration(valAddr, operatorAddr, delAddr, refundAddr, amount)
return utils.GenerateOrBroadcastMsgs(txBldr, cliCtx, []sdk.Msg{msg})
},
}

cmd.Flags().AddFlagSet(fsAmount)
cmd.Flags().AddFlagSet(fsValidator)
cmd.Flags().AddFlagSet(fsSmartChainValidator)
cmd.Flags().AddFlagSet(fsSmartChainBeneficiary)

return cmd
}

func getSideChainId() (sideChainId string, err error) {
sideChainId = viper.GetString(FlagSideChainId)
if len(sideChainId) == 0 {
Expand Down Expand Up @@ -412,6 +458,15 @@ func getValidatorAddr(flagName string) (valAddr sdk.ValAddress, err error) {
return sdk.ValAddressFromBech32(valAddrStr)
}

func getSmartChainAddr(flagName string) (addr sdk.SmartChainAddress, err error) {
addrStr := viper.GetString(flagName)
if len(addrStr) == 0 {
err = fmt.Errorf("%s is required", flagName)
return
}
return sdk.NewSmartChainAddress(addrStr)
}

func getBLSPassword() (string, error) {
blsPassword := viper.GetString(FlagBLSPassword)
if len(blsPassword) > 0 {
Expand Down
4 changes: 2 additions & 2 deletions x/stake/cross_stake/cross_stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ func (app *CrossStakeApp) handleDistributeRewardRefund(ctx sdk.Context, pack *ty
return sdk.ExecuteResult{}, err
}

// publish event
// publish event
if app.stakeKeeper.PbsbServer != nil && ctx.IsDeliverTx() {
app.stakeKeeper.AddrPool.AddAddrs([]sdk.AccAddress{sdk.PegAccount, refundAddr})
PublishCrossStakeEvent(ctx, app.stakeKeeper, sdk.PegAccount.String(), []pubsub.CrossReceiver{{refundAddr.String(), pack.Amount.Int64()}},
Expand All @@ -368,7 +368,7 @@ func (app *CrossStakeApp) handleDistributeUndelegatedRefund(ctx sdk.Context, pac
return sdk.ExecuteResult{}, err
}

// publish event
// publish event
if app.stakeKeeper.PbsbServer != nil && ctx.IsDeliverTx() {
app.stakeKeeper.AddrPool.AddAddrs([]sdk.AccAddress{sdk.PegAccount, refundAddr})
PublishCrossStakeEvent(ctx, app.stakeKeeper, sdk.PegAccount.String(), []pubsub.CrossReceiver{{refundAddr.String(), pack.Amount.Int64()}},
Expand Down
7 changes: 6 additions & 1 deletion x/stake/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ func NewHandler(k keeper.Keeper, govKeeper gov.Keeper) sdk.Handler {
return handleMsgSideChainRedelegate(ctx, msg, k)
case types.MsgSideChainUndelegate:
return handleMsgSideChainUndelegate(ctx, msg, k)
case types.MsgSideChainStakeMigration:
if !sdk.IsUpgrade(sdk.FirstSunsetFork) || sdk.IsUpgrade(sdk.SecondSunsetFork) {
return sdk.ErrMsgNotSupported("MsgSideChainStakeMigration is only enabled between FirstSunsetFork and SecondSunsetFork").Result()
}
return handleMsgSideChainStakeMigration(ctx, msg, k)
default:
return sdk.ErrTxDecode("invalid message parse in staking module").Result()
}
Expand All @@ -97,7 +102,7 @@ func NewStakeHandler(k Keeper) sdk.Handler {
}
}

//_____________________________________________________________________
// _____________________________________________________________________

// These functions assume everything has been authenticated,
// now we just perform action and save
Expand Down
98 changes: 98 additions & 0 deletions x/stake/handler_sidechain.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ package stake
import (
"bytes"
"fmt"
"strconv"

"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/bsc"
"github.com/cosmos/cosmos-sdk/bsc/rlp"
"github.com/cosmos/cosmos-sdk/pubsub"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/keeper"
"github.com/cosmos/cosmos-sdk/x/stake/tags"
Expand Down Expand Up @@ -476,6 +480,100 @@ func handleMsgSideChainUndelegate(ctx sdk.Context, msg MsgSideChainUndelegate, k
return sdk.Result{Data: finishTime, Tags: tags, Events: events}
}

func handleMsgSideChainStakeMigration(ctx sdk.Context, msg MsgSideChainStakeMigration, k keeper.Keeper) sdk.Result {
if scCtx, err := k.ScKeeper.PrepareCtxForSideChain(ctx, k.DestChainName); err != nil {
return ErrInvalidSideChainId(k.Codespace()).Result()
} else {
forcodedancing marked this conversation as resolved.
Show resolved Hide resolved
ctx = scCtx
}

denom := k.BondDenom(ctx)
if msg.Amount.Denom != denom {
return ErrBadDenom(k.Codespace()).Result()
}

shares, sdkErr := k.ValidateUnbondAmount(ctx, msg.RefundAddr, msg.ValidatorSrcAddr, msg.Amount.Amount)
if sdkErr != nil {
return sdkErr.Result()
}

// unbond immediately
unclezoro marked this conversation as resolved.
Show resolved Hide resolved
ubd, events, sdkErr := k.UnboundDelegation(ctx, msg.RefundAddr, msg.ValidatorSrcAddr, shares)
if sdkErr != nil {
return sdkErr.Result()
}

// send coins to pegAccount
relayFee := sdk.NewCoin(denom, types.StakeMigrationRelayFee)
transferAmt := sdk.Coins{ubd.Balance}.Plus(sdk.Coins{relayFee})
_, sdkErr = k.BankKeeper.SendCoins(ctx, msg.RefundAddr, sdk.PegAccount, transferAmt)
if sdkErr != nil {
return sdkErr.Result()
}

// send cross-chain package
bscAmount := bsc.ConvertBCAmountToBSCAmount(ubd.Balance.Amount)
stakeMigrationSynPackage := types.StakeMigrationSynPackage{
OperatorAddress: msg.ValidatorDstAddr,
DelegatorAddress: msg.DelegatorAddr,
RefundAddress: msg.RefundAddr,
Amount: bscAmount,
}

encodedPackage, err := rlp.EncodeToBytes(stakeMigrationSynPackage)
if err != nil {
return sdk.ErrInternal("encode stake migration package error").Result()
}

bscRelayFee := bsc.ConvertBCAmountToBSCAmount(relayFee.Amount)
sendSeq, sdkErr := k.IbcKeeper.CreateRawIBCPackageByIdWithFee(ctx, k.DestChainId, types.StakeMigrationChannelID, sdk.SynCrossChainPackageType,
encodedPackage, *bscRelayFee)
if sdkErr != nil {
return sdkErr.Result()
}

if k.PbsbServer != nil && ctx.IsDeliverTx() {
uEvent := types.ChainUndelegateEvent{
UndelegateEvent: types.UndelegateEvent{
StakeEvent: types.StakeEvent{
IsFromTx: true,
},
Delegator: msg.RefundAddr,
Validator: msg.ValidatorSrcAddr,
Amount: msg.Amount.Amount,
Denom: msg.Amount.Denom,
TxHash: ctx.Value(baseapp.TxHashKey).(string),
},
ChainId: k.DestChainName,
}
k.PbsbServer.Publish(uEvent)

ctEvent := pubsub.CrossTransferEvent{
unclezoro marked this conversation as resolved.
Show resolved Hide resolved
ChainId: k.DestChainName,
RelayerFee: types.StakeMigrationRelayFee,
Type: types.TransferOutType,
From: msg.RefundAddr.String(),
Denom: denom,
To: []pubsub.CrossReceiver{{sdk.PegAccount.String(), ubd.Balance.Amount}},
}
k.PbsbServer.Publish(ctEvent)
}

finishTime := types.MsgCdc.MustMarshalBinaryLengthPrefixed(ubd.MinTime)
txTags := sdk.NewTags(
tags.Delegator, []byte(msg.RefundAddr.String()),
tags.SrcValidator, []byte(msg.ValidatorSrcAddr.String()),
tags.EndTime, finishTime,
)
txTags = append(txTags, sdk.GetPegInTag(denom, ubd.Balance.Amount))
txTags = append(txTags, sdk.MakeTag(types.TagStakeMigrationSendSequence, []byte(strconv.FormatUint(sendSeq, 10))))

return sdk.Result{
Tags: txTags,
Events: events,
}
}

// we allow the self-delegator delegating/redelegating to its validator.
// but the operator is not allowed if it is not a self-delegator
func checkOperatorAsDelegator(k Keeper, delegator sdk.AccAddress, validator Validator) sdk.Error {
Expand Down
12 changes: 6 additions & 6 deletions x/stake/keeper/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func (k Keeper) RemoveDelegationByVal(ctx sdk.Context, delAddr sdk.AccAddress, v
store.Delete(GetDelegationKeyByValIndexKey(valAddr, delAddr))
}

//_____________________________________________________________________________________
// _____________________________________________________________________________________

func (k Keeper) SetSimplifiedDelegations(ctx sdk.Context, height int64, validator sdk.ValAddress, simDels []types.SimplifiedDelegation) {
store := ctx.KVStore(k.storeKey)
Expand All @@ -185,7 +185,7 @@ func (k Keeper) RemoveSimplifiedDelegations(ctx sdk.Context, height int64, valid
store.Delete(GetSimplifiedDelegationsKey(height, validator))
}

//_____________________________________________________________________________________
// _____________________________________________________________________________________

// return a given amount of all the delegator unbonding-delegations
func (k Keeper) GetUnbondingDelegations(ctx sdk.Context, delegator sdk.AccAddress,
Expand Down Expand Up @@ -336,7 +336,7 @@ func (k Keeper) DequeueAllMatureUnbondingQueue(ctx sdk.Context, currTime time.Ti
return matureUnbonds
}

//_____________________________________________________________________________________
// _____________________________________________________________________________________

// return a given amount of all the delegator redelegations
func (k Keeper) GetRedelegations(ctx sdk.Context, delegator sdk.AccAddress,
Expand Down Expand Up @@ -489,7 +489,7 @@ func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time
return matureRedelegations
}

//_____________________________________________________________________________________
// _____________________________________________________________________________________

func (k Keeper) SyncDelegationByValDel(ctx sdk.Context, valAddr sdk.ValAddress, delAddr sdk.AccAddress) {
delegation, found := k.GetDelegation(ctx, delAddr, valAddr)
Expand Down Expand Up @@ -619,7 +619,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
return amount, nil
}

//______________________________________________________________________________________________________
// ______________________________________________________________________________________________________

// get info for begin functions: MinTime and CreationHeight
func (k Keeper) getBeginInfo(ctx sdk.Context, valSrcAddr sdk.ValAddress) (
Expand Down Expand Up @@ -886,7 +886,7 @@ func (k Keeper) crossDistributeUndelegated(ctx sdk.Context, delAddr sdk.AccAddre
return sdk.Events{}, sdk.ErrInternal(err.Error())
}

sendSeq, sdkErr := k.ibcKeeper.CreateRawIBCPackageByIdWithFee(ctx.DepriveSideChainKeyPrefix(), k.DestChainId, types.CrossStakeChannelID,
sendSeq, sdkErr := k.IbcKeeper.CreateRawIBCPackageByIdWithFee(ctx.DepriveSideChainKeyPrefix(), k.DestChainId, types.CrossStakeChannelID,
sdk.SynCrossChainPackageType, encodedPackage, *bscRelayFee)
if sdkErr != nil {
return sdk.Events{}, sdkErr
Expand Down
Loading
Loading