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 all 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
7 changes: 4 additions & 3 deletions x/paramHub/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
SideChainDelegateFee = 1e5
SideChainRedelegateFee = 3e5
SideChainUndelegateFee = 2e5
SideChainStakeMigrationFee = 3e5

// beacon chain stake fee
EditChainValidatorFee = 1e8
Expand Down Expand Up @@ -73,7 +74,7 @@ const (
CrossBindRelayFee = 2e6
CrossUnbindRelayFee = 2e6

//MiniToken fee
// MiniToken fee
TinyIssueFee = 2e8
MiniIssueFee = 3e8
MiniSetUriFee = 37500
Expand All @@ -87,7 +88,7 @@ const (
var DefaultGenesisState = param.GenesisState{
FeeGenesis: FeeGenesisState,

//Add other param genesis here
// Add other param genesis here
}

// --------- Definition about fee prams ------------------- //
Expand Down Expand Up @@ -131,4 +132,4 @@ var FeeGenesisState = []param.FeeParam{
},
}

//---------- End definition about fee param ---------------- //
// ---------- End definition about fee param ---------------- //
6 changes: 6 additions & 0 deletions x/paramHub/hub.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ func RegisterUpgradeBeginBlocker(paramHub *ParamHub) {
}
paramHub.UpdateFeeParams(ctx, updateFeeParams)
})
sdk.UpgradeMgr.RegisterBeginBlocker(sdk.FirstSunsetFork, func(ctx sdk.Context) {
updateFeeParams := []param.FeeParam{
&param.FixedFeeParams{MsgType: "side_stake_migration", Fee: SideChainStakeMigrationFee, FeeFor: sdk.FeeForProposer},
}
paramHub.UpdateFeeParams(ctx, updateFeeParams)
})
}

func EndBreatheBlock(ctx sdk.Context, paramHub *ParamHub) {
Expand Down
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
Loading
Loading