diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b771e1..7810811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## Unreleased +* [#102](https://github.com/babylonlabs-io/btc-staker/pull/102) Bump babylon v18 +and fix incompatibilities + ## v0.12.0 ### Improvements diff --git a/babylonclient/babyloncontroller.go b/babylonclient/babyloncontroller.go index 347f660..406c5ca 100644 --- a/babylonclient/babyloncontroller.go +++ b/babylonclient/babyloncontroller.go @@ -105,7 +105,7 @@ type StakingTrackerResponse struct { CovenantPks []*btcec.PublicKey CovenantQuruomThreshold uint32 MinSlashingFee btcutil.Amount - MinUnbondingTime uint16 + UnbondingTime uint16 UnbondingFee btcutil.Amount MinStakingTime uint16 MaxStakingTime uint16 @@ -133,15 +133,19 @@ func (bc *BabylonController) Stop() error { return bc.bbnClient.Stop() } -func (bc *BabylonController) Params() (*StakingParams, error) { - // TODO: it would probably be good to have separate methods for those - var bccParams *btcctypes.Params +func (bc *BabylonController) btccheckpointParamsWithRetry() (*BTCCheckpointParams, error) { + var bccParams *BTCCheckpointParams if err := retry.Do(func() error { response, err := bc.bbnClient.BTCCheckpointParams() if err != nil { return err } - bccParams = &response.Params + + bccParams = &BTCCheckpointParams{ + ConfirmationTimeBlocks: response.Params.BtcConfirmationDepth, + FinalizationTimeoutBlocks: response.Params.CheckpointFinalizationTimeout, + } + return nil }, RtyAtt, RtyDel, RtyErr, retry.OnRetry(func(n uint, err error) { bc.logger.WithFields(logrus.Fields{ @@ -153,6 +157,14 @@ func (bc *BabylonController) Params() (*StakingParams, error) { return nil, err } + return bccParams, nil +} + +func (bc *BabylonController) BTCCheckpointParams() (*BTCCheckpointParams, error) { + return bc.btccheckpointParamsWithRetry() +} + +func (bc *BabylonController) queryStakingTrackerWithRetries() (*StakingTrackerResponse, error) { var stakingTrackerParams *StakingTrackerResponse if err := retry.Do(func() error { trackerParams, err := bc.QueryStakingTracker() @@ -171,15 +183,86 @@ func (bc *BabylonController) Params() (*StakingParams, error) { return nil, err } + return stakingTrackerParams, nil +} + +func (bc *BabylonController) Params() (*StakingParams, error) { + bccParams, err := bc.btccheckpointParamsWithRetry() + + if err != nil { + return nil, err + } + + stakingTrackerParams, err := bc.queryStakingTrackerWithRetries() + + if err != nil { + return nil, err + } + + return &StakingParams{ + ConfirmationTimeBlocks: bccParams.ConfirmationTimeBlocks, + FinalizationTimeoutBlocks: bccParams.FinalizationTimeoutBlocks, + SlashingPkScript: stakingTrackerParams.SlashingPkScript, + CovenantPks: stakingTrackerParams.CovenantPks, + MinSlashingTxFeeSat: stakingTrackerParams.MinSlashingFee, + SlashingRate: stakingTrackerParams.SlashingRate, + CovenantQuruomThreshold: stakingTrackerParams.CovenantQuruomThreshold, + UnbondingTime: stakingTrackerParams.UnbondingTime, + UnbondingFee: stakingTrackerParams.UnbondingFee, + MinStakingTime: stakingTrackerParams.MinStakingTime, + MaxStakingTime: stakingTrackerParams.MaxStakingTime, + MinStakingValue: stakingTrackerParams.MinStakingValue, + MaxStakingValue: stakingTrackerParams.MaxStakingValue, + AllowListExpirationHeight: stakingTrackerParams.AllowListExpirationHeight, + }, nil +} + +func (bc *BabylonController) queryStakingTrackerByBtcHeightWithRetries( + btcHeight uint32, +) (*StakingTrackerResponse, error) { + var stakingTrackerParams *StakingTrackerResponse + if err := retry.Do(func() error { + trackerParams, err := bc.QueryStakingTrackerByBtcHeight(btcHeight) + if err != nil { + return err + } + stakingTrackerParams = trackerParams + return nil + }, RtyAtt, RtyDel, RtyErr, retry.OnRetry(func(n uint, err error) { + bc.logger.WithFields(logrus.Fields{ + "attempt": n + 1, + "max_attempts": RtyAttNum, + "error": err, + }).Error("Failed to query babylon client for staking tracker params") + })); err != nil { + return nil, err + } + + return stakingTrackerParams, nil +} + +func (bc *BabylonController) ParamsByBtcHeight(btcHeight uint32) (*StakingParams, error) { + bccParams, err := bc.btccheckpointParamsWithRetry() + + if err != nil { + return nil, err + } + + stakingTrackerParams, err := bc.queryStakingTrackerByBtcHeightWithRetries(btcHeight) + + if err != nil { + return nil, err + } + return &StakingParams{ - ConfirmationTimeBlocks: bccParams.BtcConfirmationDepth, - FinalizationTimeoutBlocks: bccParams.CheckpointFinalizationTimeout, + ConfirmationTimeBlocks: bccParams.ConfirmationTimeBlocks, + FinalizationTimeoutBlocks: bccParams.FinalizationTimeoutBlocks, SlashingPkScript: stakingTrackerParams.SlashingPkScript, CovenantPks: stakingTrackerParams.CovenantPks, MinSlashingTxFeeSat: stakingTrackerParams.MinSlashingFee, SlashingRate: stakingTrackerParams.SlashingRate, CovenantQuruomThreshold: stakingTrackerParams.CovenantQuruomThreshold, - MinUnbondingTime: stakingTrackerParams.MinUnbondingTime, + UnbondingTime: stakingTrackerParams.UnbondingTime, UnbondingFee: stakingTrackerParams.UnbondingFee, MinStakingTime: stakingTrackerParams.MinStakingTime, MaxStakingTime: stakingTrackerParams.MaxStakingTime, @@ -444,33 +527,22 @@ func getQueryContext(timeout time.Duration) (context.Context, context.CancelFunc return ctx, cancel } -func (bc *BabylonController) QueryStakingTracker() (*StakingTrackerResponse, error) { - ctx, cancel := getQueryContext(bc.cfg.Timeout) - defer cancel() - - clientCtx := client.Context{Client: bc.bbnClient.RPCClient} - queryClient := btcstypes.NewQueryClient(clientCtx) - - response, err := queryClient.Params(ctx, &btcstypes.QueryParamsRequest{}) - if err != nil { - return nil, err - } - +func parseParams(params *btcstypes.Params) (*StakingTrackerResponse, error) { // check early that the covenant config makes sense, so that rest of the // code can assume that: // 1. covenant quorum is less or equal to number of covenant pks // 2. covenant pks are not empty - if len(response.Params.CovenantPks) == 0 { + if len(params.CovenantPks) == 0 { return nil, fmt.Errorf("empty list of covenant pks: %w", ErrInvalidValueReceivedFromBabylonNode) } - if int(response.Params.CovenantQuorum) > len(response.Params.CovenantPks) { + if int(params.CovenantQuorum) > len(params.CovenantPks) { return nil, fmt.Errorf("covenant quorum is bigger than number of covenant pks: %w", ErrInvalidValueReceivedFromBabylonNode) } var covenantPks []*btcec.PublicKey - for _, covenantPk := range response.Params.CovenantPks { + for _, covenantPk := range params.CovenantPks { covenantBtcPk, err := covenantPk.ToBTCPK() if err != nil { return nil, err @@ -478,50 +550,83 @@ func (bc *BabylonController) QueryStakingTracker() (*StakingTrackerResponse, err covenantPks = append(covenantPks, covenantBtcPk) } - minUnbondingTimeBlocksU32 := response.Params.MinUnbondingTimeBlocks - if minUnbondingTimeBlocksU32 > math.MaxUint16 { - return nil, fmt.Errorf("min unbonding time is bigger than uint16: %w", ErrInvalidValueReceivedFromBabylonNode) + unbondingTime := params.UnbondingTimeBlocks + if unbondingTime > math.MaxUint16 { + return nil, fmt.Errorf("unbonding time is bigger than uint16: %w", ErrInvalidValueReceivedFromBabylonNode) } - minStakingTimeBlocksU32 := response.Params.MinStakingTimeBlocks + minStakingTimeBlocksU32 := params.MinStakingTimeBlocks if minStakingTimeBlocksU32 > math.MaxUint16 { return nil, fmt.Errorf("min staking time is bigger than uint16: %w", ErrInvalidValueReceivedFromBabylonNode) } - maxStakingTimeBlocksU32 := response.Params.MaxStakingTimeBlocks + maxStakingTimeBlocksU32 := params.MaxStakingTimeBlocks if maxStakingTimeBlocksU32 > math.MaxUint16 { return nil, fmt.Errorf("max staking time is bigger than uint16: %w", ErrInvalidValueReceivedFromBabylonNode) } - if response.Params.MinStakingValueSat < 0 { + if params.MinStakingValueSat < 0 { return nil, fmt.Errorf("min staking value is negative: %w", ErrInvalidValueReceivedFromBabylonNode) } - if response.Params.MaxStakingValueSat < 0 { + if params.MaxStakingValueSat < 0 { return nil, fmt.Errorf("max staking value is negative: %w", ErrInvalidValueReceivedFromBabylonNode) } - if response.Params.UnbondingFeeSat < 0 { + if params.UnbondingFeeSat < 0 { return nil, fmt.Errorf("unbonding fee is negative: %w", ErrInvalidValueReceivedFromBabylonNode) } return &StakingTrackerResponse{ - SlashingPkScript: response.Params.SlashingPkScript, - SlashingRate: response.Params.SlashingRate, - MinComissionRate: response.Params.MinCommissionRate, + SlashingPkScript: params.SlashingPkScript, + SlashingRate: params.SlashingRate, + MinComissionRate: params.MinCommissionRate, CovenantPks: covenantPks, - MinSlashingFee: btcutil.Amount(response.Params.MinSlashingTxFeeSat), - CovenantQuruomThreshold: response.Params.CovenantQuorum, - MinUnbondingTime: uint16(minUnbondingTimeBlocksU32), - UnbondingFee: btcutil.Amount(response.Params.UnbondingFeeSat), + MinSlashingFee: btcutil.Amount(params.MinSlashingTxFeeSat), + CovenantQuruomThreshold: params.CovenantQuorum, + UnbondingTime: uint16(unbondingTime), + UnbondingFee: btcutil.Amount(params.UnbondingFeeSat), MinStakingTime: uint16(minStakingTimeBlocksU32), MaxStakingTime: uint16(maxStakingTimeBlocksU32), - MinStakingValue: btcutil.Amount(response.Params.MinStakingValueSat), - MaxStakingValue: btcutil.Amount(response.Params.MaxStakingValueSat), - AllowListExpirationHeight: response.Params.AllowListExpirationHeight, + MinStakingValue: btcutil.Amount(params.MinStakingValueSat), + MaxStakingValue: btcutil.Amount(params.MaxStakingValueSat), + AllowListExpirationHeight: params.AllowListExpirationHeight, }, nil } +func (bc *BabylonController) QueryStakingTracker() (*StakingTrackerResponse, error) { + ctx, cancel := getQueryContext(bc.cfg.Timeout) + defer cancel() + + clientCtx := client.Context{Client: bc.bbnClient.RPCClient} + queryClient := btcstypes.NewQueryClient(clientCtx) + + response, err := queryClient.Params(ctx, &btcstypes.QueryParamsRequest{}) + if err != nil { + return nil, err + } + + return parseParams(&response.Params) +} + +func (bc *BabylonController) QueryStakingTrackerByBtcHeight(btcHeight uint32) (*StakingTrackerResponse, error) { + ctx, cancel := getQueryContext(bc.cfg.Timeout) + defer cancel() + + clientCtx := client.Context{Client: bc.bbnClient.RPCClient} + queryClient := btcstypes.NewQueryClient(clientCtx) + + response, err := queryClient.ParamsByBTCHeight(ctx, &btcstypes.QueryParamsByBTCHeightRequest{ + BtcHeight: btcHeight, + }) + + if err != nil { + return nil, err + } + + return parseParams(&response.Params) +} + func (bc *BabylonController) QueryFinalityProviders( limit uint64, offset uint64) (*FinalityProvidersClientResponse, error) { diff --git a/babylonclient/interface.go b/babylonclient/interface.go index 79f0beb..f045b5c 100644 --- a/babylonclient/interface.go +++ b/babylonclient/interface.go @@ -16,6 +16,13 @@ import ( pv "github.com/cosmos/relayer/v2/relayer/provider" ) +type BTCCheckpointParams struct { + // K-deep + ConfirmationTimeBlocks uint32 + // W-deep + FinalizationTimeoutBlocks uint32 +} + type StakingParams struct { // K-deep ConfirmationTimeBlocks uint32 @@ -38,7 +45,7 @@ type StakingParams struct { CovenantQuruomThreshold uint32 // Minimum unbonding time required by babylon - MinUnbondingTime uint16 + UnbondingTime uint16 // Fee required by unbonding transaction UnbondingFee btcutil.Amount @@ -68,7 +75,9 @@ type SingleKeyKeyring interface { type BabylonClient interface { SingleKeyKeyring + BTCCheckpointParams() (*BTCCheckpointParams, error) Params() (*StakingParams, error) + ParamsByBtcHeight(btcHeight uint32) (*StakingParams, error) Delegate(dg *DelegationData) (*pv.RelayerTxResponse, error) QueryFinalityProviders(limit uint64, offset uint64) (*FinalityProvidersClientResponse, error) QueryFinalityProvider(btcPubKey *btcec.PublicKey) (*FinalityProviderClientResponse, error) @@ -91,6 +100,17 @@ func (m *MockBabylonClient) Params() (*StakingParams, error) { return m.ClientParams, nil } +func (m *MockBabylonClient) ParamsByBtcHeight(_ uint32) (*StakingParams, error) { + return m.ClientParams, nil +} + +func (m *MockBabylonClient) BTCCheckpointParams() (*BTCCheckpointParams, error) { + return &BTCCheckpointParams{ + ConfirmationTimeBlocks: m.ClientParams.ConfirmationTimeBlocks, + FinalizationTimeoutBlocks: m.ClientParams.FinalizationTimeoutBlocks, + }, nil +} + func (m *MockBabylonClient) Sign(msg []byte) ([]byte, error) { sig, err := m.babylonKey.Sign(msg) diff --git a/go.mod b/go.mod index aaddc01..e9ee1f2 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( cosmossdk.io/errors v1.0.1 cosmossdk.io/math v1.4.0 github.com/avast/retry-go/v4 v4.5.1 - github.com/babylonlabs-io/babylon v0.17.1 + github.com/babylonlabs-io/babylon v0.18.0 github.com/babylonlabs-io/networks/parameters v0.2.2 github.com/btcsuite/btcd v0.24.2 github.com/btcsuite/btcd/btcec/v2 v2.3.2 @@ -22,6 +22,7 @@ require ( github.com/cosmos/cosmos-sdk v0.50.9 github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/relayer/v2 v2.5.2 + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 github.com/jessevdk/go-flags v1.5.0 github.com/jsternberg/zap-logfmt v1.3.0 github.com/lightningnetwork/lnd v0.16.4-beta.rc1 @@ -113,7 +114,6 @@ require ( github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/decred/dcrd/lru v1.0.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgraph-io/badger/v4 v4.3.0 // indirect diff --git a/go.sum b/go.sum index e78a14b..d363731 100644 --- a/go.sum +++ b/go.sum @@ -1432,8 +1432,8 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX github.com/aws/aws-sdk-go v1.44.312 h1:llrElfzeqG/YOLFFKjg1xNpZCFJ2xraIi3PqSuP+95k= github.com/aws/aws-sdk-go v1.44.312/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/babylonlabs-io/babylon v0.17.1 h1:lyWGdR7B49qDw5pllLyTW/HAM5uQWXXPZefjFzy/Xy0= -github.com/babylonlabs-io/babylon v0.17.1/go.mod h1:sT+KG2U+M0tDMNZZ2L5CwlXX0OpagGEs56BiWXqaZFw= +github.com/babylonlabs-io/babylon v0.18.0 h1:phMY/GiR9N5MpD3XCmvyPpZkc1I3kTM9yX+Cf0h3OnU= +github.com/babylonlabs-io/babylon v0.18.0/go.mod h1:sT+KG2U+M0tDMNZZ2L5CwlXX0OpagGEs56BiWXqaZFw= github.com/babylonlabs-io/networks/parameters v0.2.2 h1:TCu39fZvjX5f6ZZrjhYe54M6wWxglNewuKu56yE+zrc= github.com/babylonlabs-io/networks/parameters v0.2.2/go.mod h1:iEJVOzaLsE33vpP7J4u+CRGfkSIfErUAwRmgCFCBpyI= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= diff --git a/itest/containers/containers.go b/itest/containers/containers.go index 31d498d..6140d28 100644 --- a/itest/containers/containers.go +++ b/itest/containers/containers.go @@ -190,7 +190,7 @@ func (m *Manager) RunBabylondResource( "sh", "-c", fmt.Sprintf( "babylond testnet --v=1 --output-dir=/home --starting-ip-address=192.168.10.2 "+ "--keyring-backend=test --chain-id=chain-test --btc-finalization-timeout=4 "+ - "--btc-confirmation-depth=2 --min-unbonding-time=5 --additional-sender-account --btc-network=regtest "+ + "--btc-confirmation-depth=2 --unbonding-time=5 --additional-sender-account --btc-network=regtest "+ "--min-staking-time-blocks=200 --min-staking-amount-sat=10000 "+ "--slashing-pk-script=%s --btc-base-header=%s --covenant-quorum=%d "+ "--covenant-pks=%s && chmod -R 777 /home && "+ diff --git a/staker/babylontypes.go b/staker/babylontypes.go index 17758e7..a88164e 100644 --- a/staker/babylontypes.go +++ b/staker/babylontypes.go @@ -21,9 +21,10 @@ import ( // retrieving data from babylon chain, sending data to babylon chain, queuing data to be send etc. type inclusionInfo struct { - txIndex uint32 - inclusionBlock *wire.MsgBlock - inclusionProof []byte + txIndex uint32 + inclusionBlock *wire.MsgBlock + inclusionBlockBtcHeight uint32 + inclusionProof []byte } type sendDelegationRequest struct { @@ -39,7 +40,7 @@ func (app *App) buildOwnedDelegation( stakerAddress btcutil.Address, storedTx *stakerdb.StoredTransaction, ) (*cl.DelegationData, error) { - externalData, err := app.retrieveExternalDelegationData(stakerAddress) + externalData, err := app.retrieveExternalDelegationData(stakerAddress, req.inclusionInfo) if err != nil { return nil, err } @@ -70,8 +71,7 @@ func (app *App) buildOwnedDelegation( externalData.babylonParams.CovenantQuruomThreshold, externalData.babylonParams.SlashingPkScript, externalData.babylonParams.UnbondingFee, - // TODO: Possiblity to customize finalization time - externalData.babylonParams.MinUnbondingTime, + externalData.babylonParams.UnbondingTime, app.getSlashingFee(externalData.babylonParams.MinSlashingTxFeeSat), externalData.babylonParams.SlashingRate, app.network, diff --git a/staker/stakerapp.go b/staker/stakerapp.go index 79ffa46..9e6b70d 100644 --- a/staker/stakerapp.go +++ b/staker/stakerapp.go @@ -960,8 +960,9 @@ func (app *App) mustBuildInclusionProof( func (app *App) newBtcInclusionInfo(notifierTx *notifier.TxConfirmation) *inclusionInfo { return &inclusionInfo{ - txIndex: notifierTx.TxIndex, - inclusionBlock: notifierTx.Block, + txIndex: notifierTx.TxIndex, + inclusionBlock: notifierTx.Block, + inclusionBlockBtcHeight: notifierTx.BlockHeight, inclusionProof: app.mustBuildInclusionProof( notifierTx.Block, notifierTx.TxIndex, @@ -969,10 +970,28 @@ func (app *App) newBtcInclusionInfo(notifierTx *notifier.TxConfirmation) *inclus } } -func (app *App) retrieveExternalDelegationData(stakerAddress btcutil.Address) (*externalDelegationData, error) { - params, err := app.babylonClient.Params() - if err != nil { - return nil, err +func (app *App) retrieveExternalDelegationData( + stakerAddress btcutil.Address, + inclusionInfo *inclusionInfo, +) (*externalDelegationData, error) { + var params *cl.StakingParams + + if inclusionInfo == nil { + p, err := app.babylonClient.Params() + + if err != nil { + return nil, err + } + + params = p + } else { + p, err := app.babylonClient.ParamsByBtcHeight(inclusionInfo.inclusionBlockBtcHeight) + + if err != nil { + return nil, err + } + + params = p } stakerPublicKey, err := app.wc.AddressPublicKey(stakerAddress) @@ -1540,7 +1559,8 @@ func (app *App) handleStakingCommands() { case cmd := <-app.migrateStakingCmd: stkTxHash := cmd.notifierTx.Tx.TxHash() - stkParams, err := app.babylonClient.Params() + + btcCheckpointParams, err := app.babylonClient.BTCCheckpointParams() if err != nil { cmd.errChan <- err continue @@ -1548,7 +1568,7 @@ func (app *App) handleStakingCommands() { bestBlockHeight := app.currentBestBlockHeight.Load() // check confirmation is deep enough - if err := checkConfirmationDepth(bestBlockHeight, cmd.notifierTx.BlockHeight, stkParams.ConfirmationTimeBlocks); err != nil { + if err := checkConfirmationDepth(bestBlockHeight, cmd.notifierTx.BlockHeight, btcCheckpointParams.ConfirmationTimeBlocks); err != nil { cmd.errChan <- err continue } @@ -1556,7 +1576,7 @@ func (app *App) handleStakingCommands() { _, btcDelTxHash, err := app.handleSendDelegationRequest( cmd.stakerAddr, cmd.parsedStakingTx.OpReturnData.StakingTime, - stkParams.ConfirmationTimeBlocks, + btcCheckpointParams.ConfirmationTimeBlocks, []*btcec.PublicKey{cmd.parsedStakingTx.OpReturnData.FinalityProviderPublicKey.PubKey}, cmd.pop, cmd.notifierTx.Tx, @@ -1616,9 +1636,10 @@ func (app *App) handleStakingEvents() { req := newSendDelegationRequest( &ev.stakingTxHash, &inclusionInfo{ - txIndex: ev.txIndex, - inclusionBlock: ev.inlusionBlock, - inclusionProof: proof, + txIndex: ev.txIndex, + inclusionBlock: ev.inlusionBlock, + inclusionBlockBtcHeight: ev.blockHeight, + inclusionProof: proof, }, ev.blockDepth, ) diff --git a/staker/types.go b/staker/types.go index 5da833b..9f83e27 100644 --- a/staker/types.go +++ b/staker/types.go @@ -115,7 +115,7 @@ func slashingTxForStakingTx( net *chaincfg.Params, ) (*wire.MsgTx, *staking.SpendInfo, error) { stakerPubKey := delegationData.stakerPublicKey - lockSlashTxLockTime := delegationData.babylonParams.MinUnbondingTime + lockSlashTxLockTime := delegationData.babylonParams.UnbondingTime slashingTx, err := staking.BuildSlashingTxFromStakingTxStrict( storedTx.StakingTx, @@ -509,8 +509,8 @@ func parseWatchStakingRequest( return nil, fmt.Errorf("failed to watch staking tx due to tx not matching current data: %w", err) } - if unbondingTime < currentParams.MinUnbondingTime { - return nil, fmt.Errorf("failed to watch staking tx. Unbonding time must be greater or equal min unbonding time. Unbonding time: %d, min unbonding time: %d", unbondingTime, currentParams.MinUnbondingTime) + if unbondingTime != currentParams.UnbondingTime { + return nil, fmt.Errorf("failed to watch staking tx. Unbonding time must be equal to unbonding time in babylon. Unbonding time: %d, unbonding time in babylon: %d", unbondingTime, currentParams.UnbondingTime) } // 2. Check whether slashing tx match staking tx