From 1aed9a07274d2f7c74b7d49b1d2cb4a25ba7bdee Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Fri, 17 Jan 2025 13:26:04 -0300
Subject: [PATCH 01/31] chore: init of copying relayer msgs

---
 clientcontroller/babylon.go     |  16 +
 clientcontroller/babylon_msg.go | 749 ++++++++++++++++++++++++++++++++
 2 files changed, 765 insertions(+)
 create mode 100644 clientcontroller/babylon_msg.go

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index 2b7efaa..c3fae18 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -156,6 +156,22 @@ func (bc *BabylonController) reliablySendMsgs(msgs []sdk.Msg) (*provider.Relayer
 	)
 }
 
+func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) (*provider.RelayerTxResponse, error) {
+	// ctx := context.Background()
+
+	// c := bc.bbnClient.GetConfig()
+	// c.acc
+
+	return nil, nil
+	// bc.bbnClient.SendMsgToMempool()
+	// return bc.bbnClient.ReliablySendMsgs(
+	// 	context.Background(),
+	// 	msgs,
+	// 	expectedErrors,
+	// 	unrecoverableErrors,
+	// )
+}
+
 // SubmitCovenantSigs submits the Covenant signature via a MsgAddCovenantSig to Babylon if the daemon runs in Covenant mode
 // it returns tx hash and error
 func (bc *BabylonController) SubmitCovenantSigs(covSigs []*types.CovenantSigs) (*types.TxResponse, error) {
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
new file mode 100644
index 0000000..02a20c4
--- /dev/null
+++ b/clientcontroller/babylon_msg.go
@@ -0,0 +1,749 @@
+package clientcontroller
+
+import (
+	"context"
+	"fmt"
+	"math"
+	"os"
+	"path"
+	"strings"
+	"sync"
+	"time"
+
+	"errors"
+
+	sdkerrors "cosmossdk.io/errors"
+	"cosmossdk.io/store/rootmulti"
+	"github.com/avast/retry-go/v4"
+	bbn "github.com/babylonlabs-io/babylon/app"
+	"github.com/babylonlabs-io/babylon/client/config"
+	abci "github.com/cometbft/cometbft/abci/types"
+	"github.com/cosmos/cosmos-sdk/client"
+	"github.com/cosmos/cosmos-sdk/client/tx"
+	"github.com/cosmos/cosmos-sdk/crypto/keyring"
+	"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
+	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
+	sdk "github.com/cosmos/cosmos-sdk/types"
+	legacyerrors "github.com/cosmos/cosmos-sdk/types/errors"
+	txtypes "github.com/cosmos/cosmos-sdk/types/tx"
+	"github.com/cosmos/cosmos-sdk/types/tx/signing"
+	chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
+	"github.com/cosmos/relayer/v2/relayer/provider"
+	"github.com/juju/fslock"
+	abcistrange "github.com/strangelove-ventures/cometbft-client/abci/types"
+	strangeloveclient "github.com/strangelove-ventures/cometbft-client/client"
+	rpcclient "github.com/strangelove-ventures/cometbft-client/rpc/client"
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+var (
+	rtyAttNum                   = uint(5)
+	rtyAtt                      = retry.Attempts(rtyAttNum)
+	rtyDel                      = retry.Delay(time.Millisecond * 400)
+	rtyErr                      = retry.LastErrorOnly(true)
+	defaultBroadcastWaitTimeout = 10 * time.Minute
+	spTag                       = "send_packet"
+	waTag                       = "write_acknowledgement"
+	srcChanTag                  = "packet_src_channel"
+	dstChanTag                  = "packet_dst_channel"
+)
+
+func reliablySendMsgsAsMultipleTxs(
+	cfg *config.BabylonConfig,
+	msgs []sdk.Msg,
+) error {
+
+	c, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// ReliablySendMsgs reliably sends a list of messages to the chain.
+// It utilizes a file lock as well as a keyring lock to ensure atomic access.
+func ReliablySendMsgs(
+	ctx context.Context,
+	logger *zap.Logger,
+	cfg *config.BabylonConfig,
+	msgs []sdk.Msg,
+	expectedErrors, unrecoverableErrors []*errors.Error,
+) (*sdk.TxResponse, error) {
+	var (
+		rlyResp     *sdk.TxResponse
+		callbackErr error
+		wg          sync.WaitGroup
+	)
+
+	callback := func(rtr *sdk.TxResponse, err error) {
+		rlyResp = rtr
+		callbackErr = err
+		wg.Done()
+	}
+
+	wg.Add(1)
+
+	if err := retry.Do(func() error {
+		var sendMsgErr error
+		krErr := AccessKeyWithLock(cfg.KeyDirectory, func() {
+			sendMsgErr = c.provider.SendMessagesToMempool(ctx, msgs, "", ctx, []func(*sdk.TxResponse, error){callback})
+		})
+		if krErr != nil {
+			logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(krErr))
+			return retry.Unrecoverable(krErr)
+		}
+		if sendMsgErr != nil {
+			if ErrorContained(sendMsgErr, unrecoverableErrors) {
+				logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
+				return retry.Unrecoverable(sendMsgErr)
+			}
+			if ErrorContained(sendMsgErr, expectedErrors) {
+				// this is necessary because if err is returned
+				// the callback function will not be executed so
+				// that the inside wg.Done will not be executed
+				wg.Done()
+				logger.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
+				return nil
+			}
+			return sendMsgErr
+		}
+		return nil
+	}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, err error) {
+		logger.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
+	})); err != nil {
+		return nil, err
+	}
+
+	wg.Wait()
+
+	if callbackErr != nil {
+		if ErrorContained(callbackErr, expectedErrors) {
+			return nil, nil
+		}
+		return nil, callbackErr
+	}
+
+	if rlyResp == nil {
+		// this case could happen if the error within the retry is an expected error
+		return nil, nil
+	}
+
+	if rlyResp.Code != 0 {
+		return rlyResp, fmt.Errorf("transaction failed with code: %d", rlyResp.Code)
+	}
+
+	return rlyResp, nil
+}
+
+// SendMessagesToMempool simulates and broadcasts a transaction with the given msgs and memo.
+// This method will return once the transaction has entered the mempool.
+// In an async goroutine, will wait for the tx to be included in the block unless asyncCtx exits.
+// If there is no error broadcasting, the asyncCallback will be called with success/failure of the wait for block inclusion.
+func SendMessagesToMempool(
+	ctx context.Context,
+	cfg *config.BabylonConfig,
+	cometClient client.CometRPC,
+	rpcClient *strangeloveclient.Client,
+	ar client.AccountRetriever,
+
+	msgs []sdk.Msg,
+	memo string,
+
+	txSignerKey string,
+	sequence uint64,
+
+	asyncCtx context.Context,
+	asyncCallbacks []func(sdk.TxResponse, error),
+) error {
+
+	txBytes, fees, err := BuildMessages(
+		ctx, cfg, cometClient, rpcClient, ar, msgs, memo, 0, txSignerKey, sequence,
+	)
+	if err != nil {
+		return err
+	}
+
+	if err := cc.broadcastTx(ctx, txBytes, msgs, fees, asyncCtx, defaultBroadcastWaitTimeout, asyncCallbacks); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func BuildMessages(
+	ctx context.Context,
+	cfg *config.BabylonConfig,
+	cometClient client.CometRPC,
+	rpcClient *strangeloveclient.Client,
+	ar client.AccountRetriever,
+	msgs []sdk.Msg,
+	memo string,
+	gas uint64,
+	txSignerKey string,
+	sequence uint64,
+) (
+	txBytes []byte,
+	fees sdk.Coins,
+	err error,
+) {
+	encCfg := bbn.GetEncodingConfig()
+
+	keybase, err := keyring.New(
+		cfg.ChainID,
+		cfg.KeyringBackend,
+		cfg.KeyDirectory,
+		os.Stdin,
+		encCfg.Codec,
+	)
+	if err != nil {
+		return nil, sdk.Coins{}, err
+	}
+
+	cliCtx := client.Context{}.WithClient(cometClient).
+		WithInterfaceRegistry(encCfg.InterfaceRegistry).
+		WithChainID(cfg.ChainID).
+		WithCodec(encCfg.Codec)
+
+	txf := TxFactory(cfg, ar, encCfg.TxConfig, keybase)
+	txf, err = PrepareFactory(cliCtx, txf, keybase, txSignerKey)
+	if err != nil {
+		return nil, sdk.Coins{}, err
+	}
+
+	if memo != "" {
+		txf = txf.WithMemo(memo)
+	}
+
+	txf = txf.WithSequence(sequence)
+
+	adjusted := gas
+
+	if gas == 0 {
+		_, adjusted, err = CalculateGas(ctx, rpcClient, keybase, txf, txSignerKey, cfg.GasAdjustment, msgs...)
+
+		if err != nil {
+			return nil, sdk.Coins{}, err
+		}
+	}
+
+	// Set the gas amount on the transaction factory
+	txf = txf.WithGas(adjusted)
+
+	// Build the transaction builder
+	txb, err := txf.BuildUnsignedTx(msgs...)
+	if err != nil {
+		return nil, sdk.Coins{}, err
+	}
+
+	if err = tx.Sign(ctx, txf, txSignerKey, txb, false); err != nil {
+		return nil, sdk.Coins{}, err
+	}
+
+	tx := txb.GetTx()
+	fees = tx.GetFee()
+
+	// Generate the transaction bytes
+	txBytes, err = encCfg.TxConfig.TxEncoder()(tx)
+	if err != nil {
+		return nil, sdk.Coins{}, err
+	}
+
+	return txBytes, fees, nil
+}
+
+// BroadcastTx broadcasts a transaction with the given raw bytes and then, in an async goroutine, waits for the tx to be included in the block.
+// The wait will end after either the asyncTimeout has run out or the asyncCtx exits.
+// If there is no error broadcasting, the asyncCallback will be called with success/failure of the wait for block inclusion.
+func BroadcastTx(
+	ctx context.Context, // context for tx broadcast
+	logger *zap.Logger,
+	cfg *config.BabylonConfig,
+
+	rpcClient *strangeloveclient.Client,
+	tx []byte, // raw tx to be broadcasted
+	msgs []provider.RelayerMessage, // used for logging only
+	fees sdk.Coins, // used for metrics
+
+	asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast
+	asyncTimeout time.Duration, // timeout for waiting for block inclusion
+	asyncCallbacks []func(*provider.RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion
+) error {
+	res, err := rpcClient.BroadcastTxSync(ctx, tx)
+	isErr := err != nil
+	isFailed := res != nil && res.Code != 0
+	if isErr || isFailed {
+		if isErr && res == nil {
+			// There are some cases where BroadcastTxSync will return an error but the associated
+			// ResultBroadcastTx will be nil.
+			return err
+		}
+		rlyResp := &provider.RelayerTxResponse{
+			TxHash:    res.Hash.String(),
+			Codespace: res.Codespace,
+			Code:      res.Code,
+			Data:      res.Data.String(),
+		}
+		if isFailed {
+			err = sdkError(res.Codespace, res.Code)
+			if err == nil {
+				err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.Log)
+			}
+		}
+		LogFailedTx(logger, cfg.ChainID, rlyResp, err, msgs)
+		return err
+	}
+
+	// TODO: maybe we need to check if the node has tx indexing enabled?
+	// if not, we need to find a new way to block until inclusion in a block
+
+	go cc.waitForTx(asyncCtx, res.Hash, msgs, asyncTimeout, asyncCallbacks)
+
+	return nil
+}
+
+// CalculateGas simulates a tx to generate the appropriate gas settings before broadcasting a tx.
+func CalculateGas(
+	ctx context.Context,
+	rpcClient *strangeloveclient.Client,
+	keybase keyring.Keyring,
+	txf tx.Factory,
+	signingKey string,
+	gasAdjustment float64,
+	msgs ...sdk.Msg,
+) (txtypes.SimulateResponse, uint64, error) {
+	keyInfo, err := keybase.Key(signingKey)
+	if err != nil {
+		return txtypes.SimulateResponse{}, 0, err
+	}
+
+	var txBytes []byte
+	if err := retry.Do(func() error {
+		var err error
+		txBytes, err = BuildSimTx(keyInfo, txf, msgs...)
+		if err != nil {
+			return err
+		}
+		return nil
+	}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr); err != nil {
+		return txtypes.SimulateResponse{}, 0, err
+	}
+
+	simQuery := abci.RequestQuery{
+		Path: "/cosmos.tx.v1beta1.Service/Simulate",
+		Data: txBytes,
+	}
+
+	var res abcistrange.ResponseQuery
+	if err := retry.Do(func() error {
+		var err error
+		res, err = QueryABCI(ctx, rpcClient, simQuery)
+		if err != nil {
+			return err
+		}
+		return nil
+	}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr); err != nil {
+		return txtypes.SimulateResponse{}, 0, err
+	}
+
+	var simRes txtypes.SimulateResponse
+	if err := simRes.Unmarshal(res.Value); err != nil {
+		return txtypes.SimulateResponse{}, 0, err
+	}
+
+	gas, err := AdjustEstimatedGas(gasAdjustment, simRes.GasInfo.GasUsed)
+	return simRes, gas, err
+}
+
+// waitForTx waits for a transaction to be included in a block, logs success/fail, then invokes callback.
+// This is intended to be called as an async goroutine.
+func waitForTx(
+	ctx context.Context,
+	log *zap.Logger,
+	txHash []byte,
+	msgs []provider.RelayerMessage, // used for logging only
+	waitTimeout time.Duration,
+	callbacks []func(*provider.RelayerTxResponse, error),
+) {
+	res, err := cc.waitForBlockInclusion(ctx, txHash, waitTimeout)
+	if err != nil {
+		log.Error("Failed to wait for block inclusion", zap.Error(err))
+		if len(callbacks) > 0 {
+			for _, cb := range callbacks {
+				//Call each callback in order since waitForTx is already invoked asyncronously
+				cb(nil, err)
+			}
+		}
+		return
+	}
+
+	rlyResp := &provider.RelayerTxResponse{
+		Height:    res.Height,
+		TxHash:    res.TxHash,
+		Codespace: res.Codespace,
+		Code:      res.Code,
+		Data:      res.Data,
+		Events:    parseEventsFromTxResponse(res),
+	}
+
+	// transaction was executed, log the success or failure using the tx response code
+	// NOTE: error is nil, logic should use the returned error to determine if the
+	// transaction was successfully executed.
+
+	if res.Code != 0 {
+		// Check for any registered SDK errors
+		err := cc.sdkError(res.Codespace, res.Code)
+		if err == nil {
+			err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.RawLog)
+		}
+		if len(callbacks) > 0 {
+			for _, cb := range callbacks {
+				//Call each callback in order since waitForTx is already invoked asyncronously
+				cb(nil, err)
+			}
+		}
+		LogFailedTx(log, rlyResp, nil, msgs)
+		return
+	}
+
+	if len(callbacks) > 0 {
+		for _, cb := range callbacks {
+			//Call each callback in order since waitForTx is already invoked asyncronously
+			cb(rlyResp, nil)
+		}
+	}
+	cc.LogSuccessTx(res, msgs)
+}
+
+func AccessKeyWithLock(keyDir string, accessFunc func()) error {
+	// use lock file to guard concurrent access to the keyring
+	lockFilePath := path.Join(keyDir, "keys.lock")
+	lock := fslock.New(lockFilePath)
+	if err := lock.Lock(); err != nil {
+		return fmt.Errorf("failed to acquire file system lock (%s): %w", lockFilePath, err)
+	}
+
+	// trigger function that access keyring
+	accessFunc()
+
+	// unlock and release access
+	if err := lock.Unlock(); err != nil {
+		return fmt.Errorf("error unlocking file system lock (%s), please manually delete", lockFilePath)
+	}
+
+	return nil
+}
+
+// QueryABCI performs an ABCI query and returns the appropriate response and error sdk error code.
+func QueryABCI(ctx context.Context, rpcClient *strangeloveclient.Client, req abci.RequestQuery) (abcistrange.ResponseQuery, error) {
+	opts := rpcclient.ABCIQueryOptions{
+		Height: req.Height,
+		Prove:  req.Prove,
+	}
+
+	result, err := rpcClient.ABCIQueryWithOptions(ctx, req.Path, req.Data, opts)
+	if err != nil {
+		return abcistrange.ResponseQuery{}, err
+	}
+
+	if !result.Response.IsOK() {
+		return abcistrange.ResponseQuery{}, sdkErrorToGRPCError(result.Response.Code, result.Response.Log)
+	}
+
+	// data from trusted node or subspace query doesn't need verification
+	if !opts.Prove || !isQueryStoreWithProof(req.Path) {
+		return result.Response, nil
+	}
+
+	return result.Response, nil
+}
+
+// isQueryStoreWithProof expects a format like /<queryType>/<storeName>/<subpath>
+// queryType must be "store" and subpath must be "key" to require a proof.
+func isQueryStoreWithProof(path string) bool {
+	if !strings.HasPrefix(path, "/") {
+		return false
+	}
+
+	paths := strings.SplitN(path[1:], "/", 3)
+
+	switch {
+	case len(paths) != 3:
+		return false
+	case paths[0] != "store":
+		return false
+	case rootmulti.RequireProof("/" + paths[2]):
+		return true
+	}
+
+	return false
+}
+
+func ErrorContained(err error, errList []*sdkerrors.Error) bool {
+	for _, e := range errList {
+		if strings.Contains(err.Error(), e.Error()) {
+			return true
+		}
+	}
+
+	return false
+}
+
+// PrepareFactory mutates the tx factory with the appropriate account number, sequence number, and min gas settings.
+func PrepareFactory(
+	cliCtx client.Context,
+	txf tx.Factory,
+	keybase keyring.Keyring,
+	signingKey string,
+) (tx.Factory, error) {
+	var (
+		err      error
+		from     sdk.AccAddress
+		num, seq uint64
+	)
+
+	// Get key address and retry if fail
+	if err = retry.Do(func() error {
+		from, err = GetKeyAddressForKey(keybase, signingKey)
+		if err != nil {
+			return err
+		}
+		return err
+	}, rtyAtt, rtyDel, rtyErr); err != nil {
+		return tx.Factory{}, err
+	}
+
+	cliCtx = cliCtx.WithFromAddress(from)
+
+	// Set the account number and sequence on the transaction factory and retry if fail
+	if err = retry.Do(func() error {
+		if err = txf.AccountRetriever().EnsureExists(cliCtx, from); err != nil {
+			return err
+		}
+		return err
+	}, rtyAtt, rtyDel, rtyErr); err != nil {
+		return txf, err
+	}
+
+	// TODO: why this code? this may potentially require another query when we don't want one
+	initNum, initSeq := txf.AccountNumber(), txf.Sequence()
+	if initNum == 0 || initSeq == 0 {
+		if err = retry.Do(func() error {
+			num, seq, err = txf.AccountRetriever().GetAccountNumberSequence(cliCtx, from)
+			if err != nil {
+				return err
+			}
+			return err
+		}, rtyAtt, rtyDel, rtyErr); err != nil {
+			return txf, err
+		}
+
+		if initNum == 0 {
+			txf = txf.WithAccountNumber(num)
+		}
+
+		if initSeq == 0 {
+			txf = txf.WithSequence(seq)
+		}
+	}
+
+	return txf, nil
+}
+
+func GetKeyAddressForKey(keybase keyring.Keyring, key string) (sdk.AccAddress, error) {
+	info, err := keybase.Key(key)
+	if err != nil {
+		return nil, err
+	}
+	return info.GetAddress()
+}
+
+// TxFactory instantiates a new tx factory with the appropriate configuration settings for this chain.
+func TxFactory(
+	cfg *config.BabylonConfig,
+	ar client.AccountRetriever,
+	txConf client.TxConfig,
+	keybase keyring.Keyring,
+) tx.Factory {
+	return tx.Factory{}.
+		WithAccountRetriever(ar).
+		WithChainID(cfg.ChainID).
+		WithTxConfig(txConf).
+		WithGasAdjustment(cfg.GasAdjustment).
+		WithGasPrices(cfg.GasPrices).
+		WithKeybase(keybase).
+		WithSignMode(SignMode(cfg.SignModeStr))
+}
+
+func SignMode(signModeStr string) signing.SignMode {
+	switch signModeStr {
+	case "direct":
+		return signing.SignMode_SIGN_MODE_DIRECT
+	case "amino-json":
+		return signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON
+	default:
+		return signing.SignMode_SIGN_MODE_UNSPECIFIED
+	}
+}
+
+// BuildSimTx creates an unsigned tx with an empty single signature and returns
+// the encoded transaction or an error if the unsigned transaction cannot be built.
+func BuildSimTx(info *keyring.Record, txf tx.Factory, msgs ...sdk.Msg) ([]byte, error) {
+	txb, err := txf.BuildUnsignedTx(msgs...)
+	if err != nil {
+		return nil, err
+	}
+
+	var pk cryptotypes.PubKey = &secp256k1.PubKey{} // use default public key type
+
+	pk, err = info.GetPubKey()
+	if err != nil {
+		return nil, err
+	}
+
+	// Create an empty signature literal as the ante handler will populate with a
+	// sentinel pubkey.
+	sig := signing.SignatureV2{
+		PubKey: pk,
+		Data: &signing.SingleSignatureData{
+			SignMode: txf.SignMode(),
+		},
+		Sequence: txf.Sequence(),
+	}
+	if err := txb.SetSignatures(sig); err != nil {
+		return nil, err
+	}
+
+	protoProvider, ok := txb.(protoTxProvider)
+	if !ok {
+		return nil, fmt.Errorf("cannot simulate amino tx")
+	}
+
+	simReq := txtypes.SimulateRequest{Tx: protoProvider.GetProtoTx()}
+	return simReq.Marshal()
+}
+
+// protoTxProvider is a type which can provide a proto transaction. It is a
+// workaround to get access to the wrapper TxBuilder's method GetProtoTx().
+type protoTxProvider interface {
+	GetProtoTx() *txtypes.Tx
+}
+
+func sdkErrorToGRPCError(code uint32, log string) error {
+	switch code {
+	case legacyerrors.ErrInvalidRequest.ABCICode():
+		return status.Error(codes.InvalidArgument, log)
+	case legacyerrors.ErrUnauthorized.ABCICode():
+		return status.Error(codes.Unauthenticated, log)
+	case legacyerrors.ErrKeyNotFound.ABCICode():
+		return status.Error(codes.NotFound, log)
+	default:
+		return status.Error(codes.Unknown, log)
+	}
+}
+
+// AdjustEstimatedGas adjusts the estimated gas usage by multiplying it by the gas adjustment factor
+// and return estimated gas is higher than max gas error. If the gas usage is zero, the adjusted gas
+// is also zero.
+func AdjustEstimatedGas(gasAdjustment float64, gasUsed uint64) (uint64, error) {
+	if gasUsed == 0 {
+		return gasUsed, nil
+	}
+
+	gas := gasAdjustment * float64(gasUsed)
+	if math.IsInf(gas, 1) {
+		return 0, fmt.Errorf("infinite gas used")
+	}
+	return uint64(gas), nil
+}
+
+// sdkError will return the Cosmos SDK registered error for a given codespace/code combo if registered, otherwise nil.
+func sdkError(codespace string, code uint32) error {
+	// ABCIError will return an error other than "unknown" if syncRes.Code is a registered error in syncRes.Codespace
+	// This catches all of the sdk errors https://github.com/cosmos/cosmos-sdk/blob/f10f5e5974d2ecbf9efc05bc0bfe1c99fdeed4b6/types/errors/errors.go
+	err := errors.Unwrap(sdkerrors.ABCIError(codespace, code, "error broadcasting transaction"))
+	if err.Error() != "unknown" {
+		return err
+	}
+	return nil
+}
+
+// LogFailedTx takes the transaction and the messages to create it and logs the appropriate data
+func LogFailedTx(log *zap.Logger, chainId string, res *provider.RelayerTxResponse, err error, msgs []provider.RelayerMessage) {
+	// Include the chain_id
+	fields := []zapcore.Field{zap.String("chain_id", chainId)}
+
+	// Extract the channels from the events, if present
+	if res != nil {
+		channels := getChannelsIfPresent(res.Events)
+		fields = append(fields, channels...)
+	}
+	fields = append(fields, msgTypesField(msgs))
+
+	if err != nil {
+
+		if errors.Is(err, chantypes.ErrRedundantTx) {
+			log.Debug("Redundant message(s)", fields...)
+			return
+		}
+
+		// Make a copy since we may continue to the warning
+		errorFields := append(fields, zap.Error(err))
+		log.Error(
+			"Failed sending cosmos transaction",
+			errorFields...,
+		)
+
+		if res == nil {
+			return
+		}
+	}
+
+	if res.Code != 0 {
+		if sdkErr := cc.sdkError(res.Codespace, res.Code); err != nil {
+			fields = append(fields, zap.NamedError("sdk_error", sdkErr))
+		}
+		fields = append(fields, zap.Object("response", res))
+		cc.log.Warn(
+			"Sent transaction but received failure response",
+			fields...,
+		)
+	}
+}
+
+// getChannelsIfPresent scans the events for channel tags
+func getChannelsIfPresent(events []provider.RelayerEvent) []zapcore.Field {
+	channelTags := []string{srcChanTag, dstChanTag}
+	fields := []zap.Field{}
+
+	// While a transaction may have multiple messages, we just need to first
+	// pair of channels
+	foundTag := map[string]struct{}{}
+
+	for _, event := range events {
+		for _, tag := range channelTags {
+			for attributeKey, attributeValue := range event.Attributes {
+				if attributeKey == tag {
+					// Only append the tag once
+					// TODO: what if they are different?
+					if _, ok := foundTag[tag]; !ok {
+						fields = append(fields, zap.String(tag, attributeValue))
+						foundTag[tag] = struct{}{}
+					}
+				}
+			}
+		}
+	}
+	return fields
+}
+
+func msgTypesField(msgs []provider.RelayerMessage) zap.Field {
+	msgTypes := make([]string, len(msgs))
+	for i, m := range msgs {
+		msgTypes[i] = m.Type()
+	}
+	return zap.Strings("msg_types", msgTypes)
+}

From c8f253a2a0a6fc6384daa43a8b1e797edbbf38dc Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Fri, 17 Jan 2025 23:20:09 -0300
Subject: [PATCH 02/31] chore: build message complete

---
 clientcontroller/babylon_msg.go     | 245 +++++++++++++++++-----------
 clientcontroller/babylon_msg_log.go | 224 +++++++++++++++++++++++++
 2 files changed, 371 insertions(+), 98 deletions(-)
 create mode 100644 clientcontroller/babylon_msg_log.go

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 02a20c4..7c538ed 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -16,10 +16,17 @@ import (
 	"cosmossdk.io/store/rootmulti"
 	"github.com/avast/retry-go/v4"
 	bbn "github.com/babylonlabs-io/babylon/app"
+	appparams "github.com/babylonlabs-io/babylon/app/params"
 	"github.com/babylonlabs-io/babylon/client/config"
 	abci "github.com/cometbft/cometbft/abci/types"
+	"github.com/cometbft/cometbft/crypto/merkle"
+	"github.com/cometbft/cometbft/libs/bytes"
+	coretypes "github.com/cometbft/cometbft/rpc/core/types"
+	tmtypes "github.com/cometbft/cometbft/types"
 	"github.com/cosmos/cosmos-sdk/client"
 	"github.com/cosmos/cosmos-sdk/client/tx"
+	"github.com/cosmos/cosmos-sdk/codec"
+	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
 	"github.com/cosmos/cosmos-sdk/crypto/keyring"
 	"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
 	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
@@ -27,14 +34,13 @@ import (
 	legacyerrors "github.com/cosmos/cosmos-sdk/types/errors"
 	txtypes "github.com/cosmos/cosmos-sdk/types/tx"
 	"github.com/cosmos/cosmos-sdk/types/tx/signing"
-	chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
+	rlycosmos "github.com/cosmos/relayer/v2/chains/cosmos"
 	"github.com/cosmos/relayer/v2/relayer/provider"
 	"github.com/juju/fslock"
 	abcistrange "github.com/strangelove-ventures/cometbft-client/abci/types"
 	strangeloveclient "github.com/strangelove-ventures/cometbft-client/client"
 	rpcclient "github.com/strangelove-ventures/cometbft-client/rpc/client"
 	"go.uber.org/zap"
-	"go.uber.org/zap/zapcore"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -56,22 +62,31 @@ func reliablySendMsgsAsMultipleTxs(
 	msgs []sdk.Msg,
 ) error {
 
+	encCfg := bbn.GetEncodingConfig()
+
 	c, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
 	if err != nil {
 		return err
 	}
 
-	return nil
+	ctx := context.Background()
+	return ReliablySendMsgs(ctx, cfg)
 }
 
 // ReliablySendMsgs reliably sends a list of messages to the chain.
 // It utilizes a file lock as well as a keyring lock to ensure atomic access.
 func ReliablySendMsgs(
 	ctx context.Context,
-	logger *zap.Logger,
 	cfg *config.BabylonConfig,
+	logger *zap.Logger,
+	cometClient client.CometRPC,
+	rpcClient *strangeloveclient.Client,
+	encCfg *appparams.EncodingConfig,
+	ar client.AccountRetriever,
+
+	accSequence uint64,
 	msgs []sdk.Msg,
-	expectedErrors, unrecoverableErrors []*errors.Error,
+	expectedErrors, unrecoverableErrors []*sdkerrors.Error,
 ) (*sdk.TxResponse, error) {
 	var (
 		rlyResp     *sdk.TxResponse
@@ -90,7 +105,7 @@ func ReliablySendMsgs(
 	if err := retry.Do(func() error {
 		var sendMsgErr error
 		krErr := AccessKeyWithLock(cfg.KeyDirectory, func() {
-			sendMsgErr = c.provider.SendMessagesToMempool(ctx, msgs, "", ctx, []func(*sdk.TxResponse, error){callback})
+			sendMsgErr = SendMessagesToMempool(ctx, cfg, logger, cometClient, rpcClient, encCfg, ar, msgs, "", accSequence, []func(*sdk.TxResponse, error){callback})
 		})
 		if krErr != nil {
 			logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(krErr))
@@ -146,28 +161,30 @@ func ReliablySendMsgs(
 func SendMessagesToMempool(
 	ctx context.Context,
 	cfg *config.BabylonConfig,
+	logger *zap.Logger,
 	cometClient client.CometRPC,
 	rpcClient *strangeloveclient.Client,
+	encCfg *appparams.EncodingConfig,
 	ar client.AccountRetriever,
 
 	msgs []sdk.Msg,
 	memo string,
 
-	txSignerKey string,
 	sequence uint64,
 
-	asyncCtx context.Context,
-	asyncCallbacks []func(sdk.TxResponse, error),
+	asyncCallbacks []func(*sdk.TxResponse, error),
 ) error {
+	txSignerKey := cfg.Key
 
 	txBytes, fees, err := BuildMessages(
-		ctx, cfg, cometClient, rpcClient, ar, msgs, memo, 0, txSignerKey, sequence,
+		ctx, cfg, cometClient, rpcClient, encCfg, ar, msgs, memo, 0, txSignerKey, sequence,
 	)
 	if err != nil {
 		return err
 	}
 
-	if err := cc.broadcastTx(ctx, txBytes, msgs, fees, asyncCtx, defaultBroadcastWaitTimeout, asyncCallbacks); err != nil {
+	err = BroadcastTx(ctx, logger, cfg, encCfg, rpcClient, txBytes, msgs, fees, ctx, defaultBroadcastWaitTimeout, asyncCallbacks)
+	if err != nil {
 		return err
 	}
 
@@ -179,6 +196,7 @@ func BuildMessages(
 	cfg *config.BabylonConfig,
 	cometClient client.CometRPC,
 	rpcClient *strangeloveclient.Client,
+	encCfg *appparams.EncodingConfig,
 	ar client.AccountRetriever,
 	msgs []sdk.Msg,
 	memo string,
@@ -190,7 +208,6 @@ func BuildMessages(
 	fees sdk.Coins,
 	err error,
 ) {
-	encCfg := bbn.GetEncodingConfig()
 
 	keybase, err := keyring.New(
 		cfg.ChainID,
@@ -262,15 +279,16 @@ func BroadcastTx(
 	ctx context.Context, // context for tx broadcast
 	logger *zap.Logger,
 	cfg *config.BabylonConfig,
+	encCfg *appparams.EncodingConfig,
 
 	rpcClient *strangeloveclient.Client,
 	tx []byte, // raw tx to be broadcasted
-	msgs []provider.RelayerMessage, // used for logging only
+	msgs []sdk.Msg, // used for logging only
 	fees sdk.Coins, // used for metrics
 
 	asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast
 	asyncTimeout time.Duration, // timeout for waiting for block inclusion
-	asyncCallbacks []func(*provider.RelayerTxResponse, error), // callback for success/fail of the wait for block inclusion
+	asyncCallbacks []func(*sdk.TxResponse, error), // callback for success/fail of the wait for block inclusion
 ) error {
 	res, err := rpcClient.BroadcastTxSync(ctx, tx)
 	isErr := err != nil
@@ -299,8 +317,8 @@ func BroadcastTx(
 
 	// TODO: maybe we need to check if the node has tx indexing enabled?
 	// if not, we need to find a new way to block until inclusion in a block
-
-	go cc.waitForTx(asyncCtx, res.Hash, msgs, asyncTimeout, asyncCallbacks)
+	protoCdc := codec.NewProtoCodec(encCfg.InterfaceRegistry)
+	go waitForTx(asyncCtx, logger, rpcClient, protoCdc, encCfg.TxConfig, cfg.ChainID, res.Hash, msgs, asyncTimeout, asyncCallbacks)
 
 	return nil
 }
@@ -363,12 +381,16 @@ func CalculateGas(
 func waitForTx(
 	ctx context.Context,
 	log *zap.Logger,
+	rpcClient *strangeloveclient.Client,
+	cdc *codec.ProtoCodec,
+	txConfig client.TxConfig,
+	chainId string,
 	txHash []byte,
-	msgs []provider.RelayerMessage, // used for logging only
+	msgs []sdk.Msg, // used for logging only
 	waitTimeout time.Duration,
-	callbacks []func(*provider.RelayerTxResponse, error),
+	callbacks []func(*sdk.TxResponse, error),
 ) {
-	res, err := cc.waitForBlockInclusion(ctx, txHash, waitTimeout)
+	res, err := waitForBlockInclusion(ctx, rpcClient, txConfig, txHash, waitTimeout)
 	if err != nil {
 		log.Error("Failed to wait for block inclusion", zap.Error(err))
 		if len(callbacks) > 0 {
@@ -395,7 +417,7 @@ func waitForTx(
 
 	if res.Code != 0 {
 		// Check for any registered SDK errors
-		err := cc.sdkError(res.Codespace, res.Code)
+		err := sdkError(res.Codespace, res.Code)
 		if err == nil {
 			err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.RawLog)
 		}
@@ -405,17 +427,115 @@ func waitForTx(
 				cb(nil, err)
 			}
 		}
-		LogFailedTx(log, rlyResp, nil, msgs)
+		LogFailedTx(log, chainId, rlyResp, nil, msgs)
 		return
 	}
 
 	if len(callbacks) > 0 {
 		for _, cb := range callbacks {
 			//Call each callback in order since waitForTx is already invoked asyncronously
-			cb(rlyResp, nil)
+			cb(res, nil)
+		}
+	}
+	LogSuccessTx(log, chainId, cdc, res, msgs)
+}
+
+// waitForBlockInclusion will wait for a transaction to be included in a block, up to waitTimeout or context cancellation.
+func waitForBlockInclusion(
+	ctx context.Context,
+	rpcClient *strangeloveclient.Client,
+	txConfig client.TxConfig,
+	txHash []byte,
+	waitTimeout time.Duration,
+) (*sdk.TxResponse, error) {
+	exitAfter := time.After(waitTimeout)
+	for {
+		select {
+		case <-exitAfter:
+			return nil, fmt.Errorf("timed out after: %d; %w", waitTimeout, rlycosmos.ErrTimeoutAfterWaitingForTxBroadcast)
+		// This fixed poll is fine because it's only for logging and updating prometheus metrics currently.
+		case <-time.After(time.Millisecond * 100):
+			res, err := rpcClient.Tx(ctx, txHash, false)
+			if err == nil {
+				return mkTxResult(convertResultTx(res), txConfig)
+			}
+			if strings.Contains(err.Error(), "transaction indexing is disabled") {
+				return nil, fmt.Errorf("cannot determine success/failure of tx because transaction indexing is disabled on rpc url")
+			}
+		case <-ctx.Done():
+			return nil, ctx.Err()
+		}
+	}
+}
+
+func convertResultTx(res *strangeloveclient.TxResponse) *coretypes.ResultTx {
+	return &coretypes.ResultTx{
+		Hash:   bytes.HexBytes(res.Hash),
+		Height: res.Height,
+		Index:  res.Index,
+		TxResult: abci.ExecTxResult{
+			Code:      res.ExecTx.Code,
+			Data:      res.ExecTx.Data,
+			Log:       res.ExecTx.Log,
+			Info:      res.ExecTx.Info,
+			GasWanted: res.ExecTx.GasWanted,
+			GasUsed:   res.ExecTx.GasUsed,
+			Events:    converStringEvents(res.ExecTx.Events),
+			Codespace: res.ExecTx.Codespace,
+		},
+		Tx: tmtypes.Tx(res.Tx),
+		Proof: tmtypes.TxProof{
+			RootHash: bytes.HexBytes(res.Proof.RootHash),
+			Data:     tmtypes.Tx(res.Proof.Data),
+			Proof: merkle.Proof{
+				Total:    res.Proof.Proof.Total,
+				Index:    res.Proof.Proof.Index,
+				LeafHash: res.Proof.Proof.LeafHash,
+				Aunts:    res.Proof.Proof.Aunts,
+			},
+		},
+	}
+}
+
+func converStringEvents(events sdk.StringEvents) []abci.Event {
+	evts := make([]abci.Event, len(events))
+
+	for i, evt := range events {
+		attributes := make([]abci.EventAttribute, len(evt.Attributes))
+
+		for j, attr := range evt.Attributes {
+			attributes[j] = abci.EventAttribute{
+				Key:   attr.Key,
+				Value: attr.Value,
+			}
+		}
+
+		evts[i] = abci.Event{
+			Type:       evt.Type,
+			Attributes: attributes,
 		}
 	}
-	cc.LogSuccessTx(res, msgs)
+
+	return evts
+}
+
+// mkTxResult decodes a comet transaction into an SDK TxResponse.
+func mkTxResult(
+	resTx *coretypes.ResultTx,
+	txConfig client.TxConfig,
+) (*sdk.TxResponse, error) {
+	txbz, err := txConfig.TxDecoder()(resTx.Tx)
+	if err != nil {
+		return nil, err
+	}
+
+	p, ok := txbz.(intoAny)
+	if !ok {
+		return nil, fmt.Errorf("expecting a type implementing intoAny, got: %T", txbz)
+	}
+
+	any := p.AsAny()
+	return sdk.NewResponseResultTx(resTx, any, ""), nil
 }
 
 func AccessKeyWithLock(keyDir string, accessFunc func()) error {
@@ -671,79 +791,8 @@ func sdkError(codespace string, code uint32) error {
 	return nil
 }
 
-// LogFailedTx takes the transaction and the messages to create it and logs the appropriate data
-func LogFailedTx(log *zap.Logger, chainId string, res *provider.RelayerTxResponse, err error, msgs []provider.RelayerMessage) {
-	// Include the chain_id
-	fields := []zapcore.Field{zap.String("chain_id", chainId)}
-
-	// Extract the channels from the events, if present
-	if res != nil {
-		channels := getChannelsIfPresent(res.Events)
-		fields = append(fields, channels...)
-	}
-	fields = append(fields, msgTypesField(msgs))
-
-	if err != nil {
-
-		if errors.Is(err, chantypes.ErrRedundantTx) {
-			log.Debug("Redundant message(s)", fields...)
-			return
-		}
-
-		// Make a copy since we may continue to the warning
-		errorFields := append(fields, zap.Error(err))
-		log.Error(
-			"Failed sending cosmos transaction",
-			errorFields...,
-		)
-
-		if res == nil {
-			return
-		}
-	}
-
-	if res.Code != 0 {
-		if sdkErr := cc.sdkError(res.Codespace, res.Code); err != nil {
-			fields = append(fields, zap.NamedError("sdk_error", sdkErr))
-		}
-		fields = append(fields, zap.Object("response", res))
-		cc.log.Warn(
-			"Sent transaction but received failure response",
-			fields...,
-		)
-	}
-}
-
-// getChannelsIfPresent scans the events for channel tags
-func getChannelsIfPresent(events []provider.RelayerEvent) []zapcore.Field {
-	channelTags := []string{srcChanTag, dstChanTag}
-	fields := []zap.Field{}
-
-	// While a transaction may have multiple messages, we just need to first
-	// pair of channels
-	foundTag := map[string]struct{}{}
-
-	for _, event := range events {
-		for _, tag := range channelTags {
-			for attributeKey, attributeValue := range event.Attributes {
-				if attributeKey == tag {
-					// Only append the tag once
-					// TODO: what if they are different?
-					if _, ok := foundTag[tag]; !ok {
-						fields = append(fields, zap.String(tag, attributeValue))
-						foundTag[tag] = struct{}{}
-					}
-				}
-			}
-		}
-	}
-	return fields
-}
-
-func msgTypesField(msgs []provider.RelayerMessage) zap.Field {
-	msgTypes := make([]string, len(msgs))
-	for i, m := range msgs {
-		msgTypes[i] = m.Type()
-	}
-	return zap.Strings("msg_types", msgTypes)
+// Deprecated: this interface is used only internally for scenario we are
+// deprecating (StdTxConfig support)
+type intoAny interface {
+	AsAny() *codectypes.Any
 }
diff --git a/clientcontroller/babylon_msg_log.go b/clientcontroller/babylon_msg_log.go
new file mode 100644
index 0000000..aeb0ef0
--- /dev/null
+++ b/clientcontroller/babylon_msg_log.go
@@ -0,0 +1,224 @@
+package clientcontroller
+
+import (
+	"errors"
+	"reflect"
+
+	"github.com/cosmos/cosmos-sdk/codec"
+	sdk "github.com/cosmos/cosmos-sdk/types"
+	typestx "github.com/cosmos/cosmos-sdk/types/tx"
+	feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"
+	transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
+	clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
+	chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
+	"github.com/cosmos/relayer/v2/relayer/provider"
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+// LogFailedTx takes the transaction and the messages to create it and logs the appropriate data
+func LogFailedTx(log *zap.Logger, chainId string, res *provider.RelayerTxResponse, err error, msgs []sdk.Msg) {
+	// Include the chain_id
+	fields := []zapcore.Field{zap.String("chain_id", chainId)}
+
+	// Extract the channels from the events, if present
+	if res != nil {
+		channels := getChannelsIfPresent(res.Events)
+		fields = append(fields, channels...)
+	}
+	fields = append(fields, msgTypesField(msgs))
+
+	if err != nil {
+
+		if errors.Is(err, chantypes.ErrRedundantTx) {
+			log.Debug("Redundant message(s)", fields...)
+			return
+		}
+
+		// Make a copy since we may continue to the warning
+		errorFields := append(fields, zap.Error(err))
+		log.Error(
+			"Failed sending cosmos transaction",
+			errorFields...,
+		)
+
+		if res == nil {
+			return
+		}
+	}
+
+	if res.Code != 0 {
+		if sdkErr := sdkError(res.Codespace, res.Code); err != nil {
+			fields = append(fields, zap.NamedError("sdk_error", sdkErr))
+		}
+		fields = append(fields, zap.Object("response", res))
+		log.Warn(
+			"Sent transaction but received failure response",
+			fields...,
+		)
+	}
+}
+
+// LogSuccessTx take the transaction and the messages to create it and logs the appropriate data
+func LogSuccessTx(log *zap.Logger, chainId string, cdc *codec.ProtoCodec, res *sdk.TxResponse, msgs []sdk.Msg) {
+	// Include the chain_id
+	fields := []zapcore.Field{zap.String("chain_id", chainId)}
+
+	// Extract the channels from the events, if present
+	if res != nil {
+		events := parseEventsFromTxResponse(res)
+		fields = append(fields, getChannelsIfPresent(events)...)
+	}
+
+	// Include the gas used
+	fields = append(fields, zap.Int64("gas_used", res.GasUsed))
+
+	var m sdk.Msg
+	if err := cdc.InterfaceRegistry().UnpackAny(res.Tx, &m); err == nil {
+		if tx, ok := m.(*typestx.Tx); ok {
+			fields = append(fields, zap.Stringer("fees", tx.GetFee()))
+			if feePayer := getFeePayer(log, cdc, tx); feePayer != "" {
+				fields = append(fields, zap.String("fee_payer", feePayer))
+			}
+		} else {
+			log.Debug(
+				"Failed to convert message to Tx type",
+				zap.Stringer("type", reflect.TypeOf(m)),
+			)
+		}
+	} else {
+		log.Debug("Failed to unpack response Tx into sdk.Msg", zap.Error(err))
+	}
+
+	// Include the height, msgType, and tx_hash
+	fields = append(fields,
+		zap.Int64("height", res.Height),
+		msgTypesField(msgs),
+		zap.String("tx_hash", res.TxHash),
+	)
+
+	// Log the successful transaction with fields
+	log.Info(
+		"Successful transaction",
+		fields...,
+	)
+}
+
+// getChannelsIfPresent scans the events for channel tags
+func getChannelsIfPresent(events []provider.RelayerEvent) []zapcore.Field {
+	channelTags := []string{srcChanTag, dstChanTag}
+	fields := []zap.Field{}
+
+	// While a transaction may have multiple messages, we just need to first
+	// pair of channels
+	foundTag := map[string]struct{}{}
+
+	for _, event := range events {
+		for _, tag := range channelTags {
+			for attributeKey, attributeValue := range event.Attributes {
+				if attributeKey == tag {
+					// Only append the tag once
+					// TODO: what if they are different?
+					if _, ok := foundTag[tag]; !ok {
+						fields = append(fields, zap.String(tag, attributeValue))
+						foundTag[tag] = struct{}{}
+					}
+				}
+			}
+		}
+	}
+	return fields
+}
+
+func msgTypesField(msgs []sdk.Msg) zap.Field {
+	msgTypes := make([]string, len(msgs))
+	for i, m := range msgs {
+		msgTypes[i] = sdk.MsgTypeURL(m)
+	}
+	return zap.Strings("msg_types", msgTypes)
+}
+
+// getFeePayer returns the bech32 address of the fee payer of a transaction.
+// This uses the fee payer field if set,
+// otherwise falls back to the address of whoever signed the first message.
+func getFeePayer(log *zap.Logger, cdc *codec.ProtoCodec, tx *typestx.Tx) string {
+	payer := tx.AuthInfo.Fee.Payer
+	if payer != "" {
+		return payer
+	}
+
+	switch firstMsg := tx.GetMsgs()[0].(type) {
+	case *transfertypes.MsgTransfer:
+		// There is a possible data race around concurrent map access
+		// in the cosmos sdk when it converts the address from bech32.
+		// We don't need the address conversion; just the sender is all that
+		// GetSigners is doing under the hood anyway.
+		return firstMsg.Sender
+	case *clienttypes.MsgCreateClient:
+		// Without this particular special case, there is a panic in ibc-go
+		// due to the sdk config singleton expecting one bech32 prefix but seeing another.
+		return firstMsg.Signer
+	case *clienttypes.MsgUpdateClient:
+		// Same failure mode as MsgCreateClient.
+		return firstMsg.Signer
+	case *clienttypes.MsgUpgradeClient:
+		return firstMsg.Signer
+	case *clienttypes.MsgSubmitMisbehaviour:
+		// Same failure mode as MsgCreateClient.
+		return firstMsg.Signer
+	case *feetypes.MsgRegisterPayee:
+		return firstMsg.Relayer
+	case *feetypes.MsgRegisterCounterpartyPayee:
+		return firstMsg.Relayer
+	case *feetypes.MsgPayPacketFee:
+		return firstMsg.Signer
+	case *feetypes.MsgPayPacketFeeAsync:
+		return firstMsg.PacketFee.RefundAddress
+	default:
+		signers, _, err := cdc.GetMsgV1Signers(firstMsg)
+		if err != nil {
+			log.Info("Could not get signers for msg when attempting to get the fee payer", zap.Error(err))
+			return ""
+		}
+
+		return string(signers[0])
+	}
+}
+
+func parseEventsFromTxResponse(resp *sdk.TxResponse) []provider.RelayerEvent {
+	var events []provider.RelayerEvent
+
+	if resp == nil {
+		return events
+	}
+
+	for _, logs := range resp.Logs {
+		for _, event := range logs.Events {
+			attributes := make(map[string]string)
+			for _, attribute := range event.Attributes {
+				attributes[attribute.Key] = attribute.Value
+			}
+			events = append(events, provider.RelayerEvent{
+				EventType:  event.Type,
+				Attributes: attributes,
+			})
+		}
+	}
+
+	// After SDK v0.50, indexed events are no longer provided in the logs on
+	// transaction execution, the response events can be directly used
+	if len(events) == 0 {
+		for _, event := range resp.Events {
+			attributes := make(map[string]string)
+			for _, attribute := range event.Attributes {
+				attributes[attribute.Key] = attribute.Value
+			}
+			events = append(events, provider.RelayerEvent{
+				EventType:  event.Type,
+				Attributes: attributes,
+			})
+		}
+	}
+
+	return events
+}

From df5f9ed452fc01bb0592e34f059df7ab64de186a Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Mon, 20 Jan 2025 23:14:46 -0300
Subject: [PATCH 03/31] chore: trytest with acc sequence increment

---
 clientcontroller/babylon.go     |  40 +++++++++-
 clientcontroller/babylon_msg.go | 125 ++++++++++++++++++++++----------
 2 files changed, 123 insertions(+), 42 deletions(-)

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index 6de78f4..4300318 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -8,8 +8,11 @@ import (
 
 	sdkmath "cosmossdk.io/math"
 	"github.com/btcsuite/btcd/btcec/v2"
+	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
 	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
 
+	bbn "github.com/babylonlabs-io/babylon/app"
+	appparams "github.com/babylonlabs-io/babylon/app/params"
 	bbnclient "github.com/babylonlabs-io/babylon/client/client"
 	bbntypes "github.com/babylonlabs-io/babylon/types"
 	btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types"
@@ -36,6 +39,7 @@ type BabylonController struct {
 	bbnClient *bbnclient.Client
 	cfg       *config.BBNConfig
 	btcParams *chaincfg.Params
+	encCfg    *appparams.EncodingConfig
 	logger    *zap.Logger
 }
 
@@ -63,6 +67,7 @@ func NewBabylonController(
 		bc,
 		cfg,
 		btcParams,
+		bbn.GetEncodingConfig(),
 		logger,
 	}, nil
 }
@@ -165,7 +170,9 @@ func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) (*pro
 	// c := bc.bbnClient.GetConfig()
 	// c.acc
 
-	return nil, nil
+	_, _, err := reliablySendEachMsgAsTx(bc.bbnClient.GetConfig(), msgs, bc.logger, bc.bbnClient.RPCClient, bc.encCfg, bc.QueryAccount, expectedErrors, unrecoverableErrors)
+
+	return nil, err
 	// bc.bbnClient.SendMsgToMempool()
 	// return bc.bbnClient.ReliablySendMsgs(
 	// 	context.Background(),
@@ -190,7 +197,11 @@ func (bc *BabylonController) SubmitCovenantSigs(covSigs []*types.CovenantSigs) (
 			SlashingUnbondingTxSigs: covSig.SlashingUnbondingSigs,
 		})
 	}
-	res, err := bc.reliablySendMsgs(msgs)
+	// res, err := bc.reliablySendMsgs(msgs)
+	// if err != nil {
+	// 	return nil, err
+	// }
+	res, err := bc.reliablySendMsgsAsMultipleTxs(msgs)
 	if err != nil {
 		return nil, err
 	}
@@ -525,3 +536,28 @@ func (bc *BabylonController) QueryBtcLightClientTip() (*btclctypes.BTCHeaderInfo
 
 	return res.Header, nil
 }
+
+// QueryAccount returns the account interface based on the address
+func (bc *BabylonController) QueryAccount(addr string) (sdk.AccountI, error) {
+	ctx, cancel := getContextWithCancel(bc.cfg.Timeout)
+	defer cancel()
+
+	clientCtx := sdkclient.Context{Client: bc.bbnClient.RPCClient}
+
+	queryClient := authtypes.NewQueryClient(clientCtx)
+
+	req := &authtypes.QueryAccountRequest{
+		Address: addr,
+	}
+	resp, err := queryClient.Account(ctx, req)
+	if err != nil {
+		return nil, fmt.Errorf("failed to query account: %v", err)
+	}
+
+	var account sdk.AccountI
+	if err := bc.encCfg.InterfaceRegistry.UnpackAny(resp.Account, &account); err != nil {
+		return nil, err
+	}
+
+	return account, nil
+}
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 7c538ed..794372c 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -15,7 +15,6 @@ import (
 	sdkerrors "cosmossdk.io/errors"
 	"cosmossdk.io/store/rootmulti"
 	"github.com/avast/retry-go/v4"
-	bbn "github.com/babylonlabs-io/babylon/app"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
 	"github.com/babylonlabs-io/babylon/client/config"
 	abci "github.com/cometbft/cometbft/abci/types"
@@ -34,7 +33,7 @@ import (
 	legacyerrors "github.com/cosmos/cosmos-sdk/types/errors"
 	txtypes "github.com/cosmos/cosmos-sdk/types/tx"
 	"github.com/cosmos/cosmos-sdk/types/tx/signing"
-	rlycosmos "github.com/cosmos/relayer/v2/chains/cosmos"
+	"github.com/cosmos/relayer/v2/relayer/chains/cosmos"
 	"github.com/cosmos/relayer/v2/relayer/provider"
 	"github.com/juju/fslock"
 	abcistrange "github.com/strangelove-ventures/cometbft-client/abci/types"
@@ -57,32 +56,82 @@ var (
 	dstChanTag                  = "packet_dst_channel"
 )
 
-func reliablySendMsgsAsMultipleTxs(
+func reliablySendEachMsgAsTx(
 	cfg *config.BabylonConfig,
 	msgs []sdk.Msg,
-) error {
-
-	encCfg := bbn.GetEncodingConfig()
-
+	logger *zap.Logger,
+	cometClient client.CometRPC,
+	encCfg *appparams.EncodingConfig,
+	getAcc func(addr string) (sdk.AccountI, error),
+	expectedErrors, unrecoverableErrors []*sdkerrors.Error,
+) (txResponses []*sdk.TxResponse, failedMsgs []sdk.Msg, err error) {
 	c, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
 	if err != nil {
-		return err
+		return nil, nil, err
 	}
 
 	ctx := context.Background()
-	return ReliablySendMsgs(ctx, cfg)
+	txResponses = make([]*sdk.TxResponse, 0)
+	failedMsgs = make([]sdk.Msg, 0)
+
+	errAccKey := AccessKeyWithLock(cfg.KeyDirectory, func() error {
+		keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
+		if err != nil {
+			return err
+		}
+
+		covAddr, err := GetKeyAddressForKey(keybase, cfg.Key)
+		if err != nil {
+			return err
+		}
+
+		covAcc, err := getAcc(covAddr.String())
+		if err != nil {
+			return err
+		}
+
+		accSequence := covAcc.GetSequence()
+
+		for _, msg := range msgs {
+			txResp, err := ReliablySendMsgsWithSequence(
+				ctx,
+				cfg,
+				logger,
+				cometClient,
+				c,
+				encCfg,
+				accSequence,
+				[]sdk.Msg{msg},
+				expectedErrors, unrecoverableErrors,
+			)
+			if err != nil {
+				// log msg fail
+				failedMsgs = append(failedMsgs, msg)
+			}
+
+			accSequence++
+			logger.Debug("resp", zap.String("txHash", txResp.TxHash))
+			txResponses = append(txResponses, txResp)
+		}
+
+		return nil
+	})
+	if errAccKey != nil {
+		return nil, nil, err
+	}
+
+	return txResponses, failedMsgs, nil
 }
 
-// ReliablySendMsgs reliably sends a list of messages to the chain.
+// ReliablySendMsgsWithSequence reliably sends a list of messages to the chain.
 // It utilizes a file lock as well as a keyring lock to ensure atomic access.
-func ReliablySendMsgs(
+func ReliablySendMsgsWithSequence(
 	ctx context.Context,
 	cfg *config.BabylonConfig,
 	logger *zap.Logger,
 	cometClient client.CometRPC,
 	rpcClient *strangeloveclient.Client,
 	encCfg *appparams.EncodingConfig,
-	ar client.AccountRetriever,
 
 	accSequence uint64,
 	msgs []sdk.Msg,
@@ -103,14 +152,7 @@ func ReliablySendMsgs(
 	wg.Add(1)
 
 	if err := retry.Do(func() error {
-		var sendMsgErr error
-		krErr := AccessKeyWithLock(cfg.KeyDirectory, func() {
-			sendMsgErr = SendMessagesToMempool(ctx, cfg, logger, cometClient, rpcClient, encCfg, ar, msgs, "", accSequence, []func(*sdk.TxResponse, error){callback})
-		})
-		if krErr != nil {
-			logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(krErr))
-			return retry.Unrecoverable(krErr)
-		}
+		sendMsgErr := SendMessagesToMempool(ctx, cfg, logger, cometClient, rpcClient, encCfg, msgs, "", accSequence, []func(*sdk.TxResponse, error){callback})
 		if sendMsgErr != nil {
 			if ErrorContained(sendMsgErr, unrecoverableErrors) {
 				logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
@@ -165,7 +207,6 @@ func SendMessagesToMempool(
 	cometClient client.CometRPC,
 	rpcClient *strangeloveclient.Client,
 	encCfg *appparams.EncodingConfig,
-	ar client.AccountRetriever,
 
 	msgs []sdk.Msg,
 	memo string,
@@ -177,7 +218,7 @@ func SendMessagesToMempool(
 	txSignerKey := cfg.Key
 
 	txBytes, fees, err := BuildMessages(
-		ctx, cfg, cometClient, rpcClient, encCfg, ar, msgs, memo, 0, txSignerKey, sequence,
+		ctx, cfg, cometClient, rpcClient, encCfg, msgs, memo, 0, txSignerKey, sequence,
 	)
 	if err != nil {
 		return err
@@ -197,7 +238,6 @@ func BuildMessages(
 	cometClient client.CometRPC,
 	rpcClient *strangeloveclient.Client,
 	encCfg *appparams.EncodingConfig,
-	ar client.AccountRetriever,
 	msgs []sdk.Msg,
 	memo string,
 	gas uint64,
@@ -208,14 +248,7 @@ func BuildMessages(
 	fees sdk.Coins,
 	err error,
 ) {
-
-	keybase, err := keyring.New(
-		cfg.ChainID,
-		cfg.KeyringBackend,
-		cfg.KeyDirectory,
-		os.Stdin,
-		encCfg.Codec,
-	)
+	keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
 	if err != nil {
 		return nil, sdk.Coins{}, err
 	}
@@ -225,7 +258,7 @@ func BuildMessages(
 		WithChainID(cfg.ChainID).
 		WithCodec(encCfg.Codec)
 
-	txf := TxFactory(cfg, ar, encCfg.TxConfig, keybase)
+	txf := TxFactory(cfg, encCfg.TxConfig, keybase)
 	txf, err = PrepareFactory(cliCtx, txf, keybase, txSignerKey)
 	if err != nil {
 		return nil, sdk.Coins{}, err
@@ -452,7 +485,7 @@ func waitForBlockInclusion(
 	for {
 		select {
 		case <-exitAfter:
-			return nil, fmt.Errorf("timed out after: %d; %w", waitTimeout, rlycosmos.ErrTimeoutAfterWaitingForTxBroadcast)
+			return nil, fmt.Errorf("timed out after: %d; %w", waitTimeout, cosmos.ErrTimeoutAfterWaitingForTxBroadcast)
 		// This fixed poll is fine because it's only for logging and updating prometheus metrics currently.
 		case <-time.After(time.Millisecond * 100):
 			res, err := rpcClient.Tx(ctx, txHash, false)
@@ -538,23 +571,24 @@ func mkTxResult(
 	return sdk.NewResponseResultTx(resTx, any, ""), nil
 }
 
-func AccessKeyWithLock(keyDir string, accessFunc func()) error {
+func AccessKeyWithLock(keyDir string, accessFunc func() error) error {
 	// use lock file to guard concurrent access to the keyring
 	lockFilePath := path.Join(keyDir, "keys.lock")
 	lock := fslock.New(lockFilePath)
-	if err := lock.Lock(); err != nil {
+	err := lock.Lock()
+	if err != nil {
 		return fmt.Errorf("failed to acquire file system lock (%s): %w", lockFilePath, err)
 	}
 
 	// trigger function that access keyring
-	accessFunc()
+	err = accessFunc()
 
 	// unlock and release access
-	if err := lock.Unlock(); err != nil {
+	if errUnlock := lock.Unlock(); errUnlock != nil {
 		return fmt.Errorf("error unlocking file system lock (%s), please manually delete", lockFilePath)
 	}
 
-	return nil
+	return err
 }
 
 // QueryABCI performs an ABCI query and returns the appropriate response and error sdk error code.
@@ -612,6 +646,19 @@ func ErrorContained(err error, errList []*sdkerrors.Error) bool {
 	return false
 }
 
+func KeybaseFromCfg(
+	cfg *config.BabylonConfig,
+	cdc codec.Codec,
+) (keyring.Keyring, error) {
+	return keyring.New(
+		cfg.ChainID,
+		cfg.KeyringBackend,
+		cfg.KeyDirectory,
+		os.Stdin,
+		cdc,
+	)
+}
+
 // PrepareFactory mutates the tx factory with the appropriate account number, sequence number, and min gas settings.
 func PrepareFactory(
 	cliCtx client.Context,
@@ -684,12 +731,10 @@ func GetKeyAddressForKey(keybase keyring.Keyring, key string) (sdk.AccAddress, e
 // TxFactory instantiates a new tx factory with the appropriate configuration settings for this chain.
 func TxFactory(
 	cfg *config.BabylonConfig,
-	ar client.AccountRetriever,
 	txConf client.TxConfig,
 	keybase keyring.Keyring,
 ) tx.Factory {
 	return tx.Factory{}.
-		WithAccountRetriever(ar).
 		WithChainID(cfg.ChainID).
 		WithTxConfig(txConf).
 		WithGasAdjustment(cfg.GasAdjustment).

From fe84b511898fa765b137b73a8e96947f4121262a Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Mon, 20 Jan 2025 23:36:31 -0300
Subject: [PATCH 04/31] chore: passing with account sequence

---
 clientcontroller/babylon.go     |  2 +-
 clientcontroller/babylon_msg.go | 27 +++++++++------------------
 2 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index 4300318..6d930cf 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -542,7 +542,7 @@ func (bc *BabylonController) QueryAccount(addr string) (sdk.AccountI, error) {
 	ctx, cancel := getContextWithCancel(bc.cfg.Timeout)
 	defer cancel()
 
-	clientCtx := sdkclient.Context{Client: bc.bbnClient.RPCClient}
+	clientCtx := sdkclient.Context{Client: bc.bbnClient.RPCClient}.WithCodec(bc.encCfg.Codec)
 
 	queryClient := authtypes.NewQueryClient(clientCtx)
 
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 794372c..37e86cd 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -253,16 +253,17 @@ func BuildMessages(
 		return nil, sdk.Coins{}, err
 	}
 
-	cliCtx := client.Context{}.WithClient(cometClient).
-		WithInterfaceRegistry(encCfg.InterfaceRegistry).
-		WithChainID(cfg.ChainID).
-		WithCodec(encCfg.Codec)
+	// cliCtx := client.Context{}.
+	// 	WithClient(cometClient).
+	// 	WithInterfaceRegistry(encCfg.InterfaceRegistry).
+	// 	WithChainID(cfg.ChainID).
+	// 	WithCodec(encCfg.Codec)
 
 	txf := TxFactory(cfg, encCfg.TxConfig, keybase)
-	txf, err = PrepareFactory(cliCtx, txf, keybase, txSignerKey)
-	if err != nil {
-		return nil, sdk.Coins{}, err
-	}
+	// txf, err = PrepareFactory(cliCtx, txf, keybase, txSignerKey)
+	// if err != nil {
+	// 	return nil, sdk.Coins{}, err
+	// }
 
 	if memo != "" {
 		txf = txf.WithMemo(memo)
@@ -685,16 +686,6 @@ func PrepareFactory(
 
 	cliCtx = cliCtx.WithFromAddress(from)
 
-	// Set the account number and sequence on the transaction factory and retry if fail
-	if err = retry.Do(func() error {
-		if err = txf.AccountRetriever().EnsureExists(cliCtx, from); err != nil {
-			return err
-		}
-		return err
-	}, rtyAtt, rtyDel, rtyErr); err != nil {
-		return txf, err
-	}
-
 	// TODO: why this code? this may potentially require another query when we don't want one
 	initNum, initSeq := txf.AccountNumber(), txf.Sequence()
 	if initNum == 0 || initSeq == 0 {

From f0296c86e33051fb9db6ac6d4f472583a7581c8d Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Mon, 20 Jan 2025 23:38:21 -0300
Subject: [PATCH 05/31] fix: lint

---
 clientcontroller/babylon_msg.go     | 8 +-------
 clientcontroller/babylon_msg_log.go | 3 ---
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 37e86cd..74ac9ae 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -27,8 +27,6 @@ import (
 	"github.com/cosmos/cosmos-sdk/codec"
 	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
 	"github.com/cosmos/cosmos-sdk/crypto/keyring"
-	"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
-	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	legacyerrors "github.com/cosmos/cosmos-sdk/types/errors"
 	txtypes "github.com/cosmos/cosmos-sdk/types/tx"
@@ -50,8 +48,6 @@ var (
 	rtyDel                      = retry.Delay(time.Millisecond * 400)
 	rtyErr                      = retry.LastErrorOnly(true)
 	defaultBroadcastWaitTimeout = 10 * time.Minute
-	spTag                       = "send_packet"
-	waTag                       = "write_acknowledgement"
 	srcChanTag                  = "packet_src_channel"
 	dstChanTag                  = "packet_dst_channel"
 )
@@ -753,9 +749,7 @@ func BuildSimTx(info *keyring.Record, txf tx.Factory, msgs ...sdk.Msg) ([]byte,
 		return nil, err
 	}
 
-	var pk cryptotypes.PubKey = &secp256k1.PubKey{} // use default public key type
-
-	pk, err = info.GetPubKey()
+	pk, err := info.GetPubKey()
 	if err != nil {
 		return nil, err
 	}
diff --git a/clientcontroller/babylon_msg_log.go b/clientcontroller/babylon_msg_log.go
index aeb0ef0..1d197f9 100644
--- a/clientcontroller/babylon_msg_log.go
+++ b/clientcontroller/babylon_msg_log.go
@@ -163,9 +163,6 @@ func getFeePayer(log *zap.Logger, cdc *codec.ProtoCodec, tx *typestx.Tx) string
 		return firstMsg.Signer
 	case *clienttypes.MsgUpgradeClient:
 		return firstMsg.Signer
-	case *clienttypes.MsgSubmitMisbehaviour:
-		// Same failure mode as MsgCreateClient.
-		return firstMsg.Signer
 	case *feetypes.MsgRegisterPayee:
 		return firstMsg.Relayer
 	case *feetypes.MsgRegisterCounterpartyPayee:

From 530b7e13f085f0a877516ca4176f5f39b41ebcfd Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Mon, 20 Jan 2025 23:40:18 -0300
Subject: [PATCH 06/31] chore: add #98 to changelog

---
 CHANGELOG.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 03153b3..ca7b822 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -43,6 +43,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 * [#95](https://github.com/babylonlabs-io/covenant-emulator/pull/95) removed local signer option
 as the covenant emulator should only connect to a remote signer
 * [#96](https://github.com/babylonlabs-io/covenant-emulator/pull/96) add pagination to `queryDelegationsWithStatus`
+* [#98](https://github.com/babylonlabs-io/covenant-emulator/pull/98) add submission of covenant
+signatures as one msg per transaction if batch of transactions fails
 
 ## v0.11.3
 

From 614717df76a382d7f7db704cc084432b4dfc86a7 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 06:51:30 -0300
Subject: [PATCH 07/31] fix: sending with acc number

---
 clientcontroller/babylon_msg.go | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 74ac9ae..6179583 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -81,12 +81,16 @@ func reliablySendEachMsgAsTx(
 			return err
 		}
 
-		covAcc, err := getAcc(covAddr.String())
+		covAddrStr := covAddr.String()
+		logger.Debug("covenant_signing", zap.String("address", covAddrStr))
+
+		covAcc, err := getAcc(covAddrStr)
 		if err != nil {
 			return err
 		}
 
 		accSequence := covAcc.GetSequence()
+		accNumber := covAcc.GetAccountNumber()
 
 		for _, msg := range msgs {
 			txResp, err := ReliablySendMsgsWithSequence(
@@ -96,7 +100,9 @@ func reliablySendEachMsgAsTx(
 				cometClient,
 				c,
 				encCfg,
+				covAddrStr,
 				accSequence,
+				accNumber,
 				[]sdk.Msg{msg},
 				expectedErrors, unrecoverableErrors,
 			)
@@ -129,7 +135,8 @@ func ReliablySendMsgsWithSequence(
 	rpcClient *strangeloveclient.Client,
 	encCfg *appparams.EncodingConfig,
 
-	accSequence uint64,
+	accAddress string,
+	accSequence, accNumber uint64,
 	msgs []sdk.Msg,
 	expectedErrors, unrecoverableErrors []*sdkerrors.Error,
 ) (*sdk.TxResponse, error) {
@@ -148,7 +155,7 @@ func ReliablySendMsgsWithSequence(
 	wg.Add(1)
 
 	if err := retry.Do(func() error {
-		sendMsgErr := SendMessagesToMempool(ctx, cfg, logger, cometClient, rpcClient, encCfg, msgs, "", accSequence, []func(*sdk.TxResponse, error){callback})
+		sendMsgErr := SendMessagesToMempool(ctx, cfg, logger, cometClient, rpcClient, encCfg, msgs, "", accAddress, accSequence, accNumber, []func(*sdk.TxResponse, error){callback})
 		if sendMsgErr != nil {
 			if ErrorContained(sendMsgErr, unrecoverableErrors) {
 				logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
@@ -207,14 +214,15 @@ func SendMessagesToMempool(
 	msgs []sdk.Msg,
 	memo string,
 
-	sequence uint64,
+	accAddress string,
+	accSequence, accNumber uint64,
 
 	asyncCallbacks []func(*sdk.TxResponse, error),
 ) error {
 	txSignerKey := cfg.Key
 
 	txBytes, fees, err := BuildMessages(
-		ctx, cfg, cometClient, rpcClient, encCfg, msgs, memo, 0, txSignerKey, sequence,
+		ctx, cfg, cometClient, rpcClient, encCfg, msgs, memo, 0, txSignerKey, accAddress, accSequence, accNumber,
 	)
 	if err != nil {
 		return err
@@ -238,7 +246,8 @@ func BuildMessages(
 	memo string,
 	gas uint64,
 	txSignerKey string,
-	sequence uint64,
+	accAddress string,
+	accSequence, accNumber uint64,
 ) (
 	txBytes []byte,
 	fees sdk.Coins,
@@ -265,7 +274,8 @@ func BuildMessages(
 		txf = txf.WithMemo(memo)
 	}
 
-	txf = txf.WithSequence(sequence)
+	txf = txf.WithSequence(accSequence).
+		WithAccountNumber(accNumber)
 
 	adjusted := gas
 
@@ -720,6 +730,7 @@ func TxFactory(
 	cfg *config.BabylonConfig,
 	txConf client.TxConfig,
 	keybase keyring.Keyring,
+
 ) tx.Factory {
 	return tx.Factory{}.
 		WithChainID(cfg.ChainID).

From b36e916437e126954e71297473b702477bb3b836 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 07:01:19 -0300
Subject: [PATCH 08/31] fix: panic

---
 clientcontroller/babylon_msg.go | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 6179583..12423f2 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -55,7 +55,7 @@ var (
 func reliablySendEachMsgAsTx(
 	cfg *config.BabylonConfig,
 	msgs []sdk.Msg,
-	logger *zap.Logger,
+	log *zap.Logger,
 	cometClient client.CometRPC,
 	encCfg *appparams.EncodingConfig,
 	getAcc func(addr string) (sdk.AccountI, error),
@@ -82,7 +82,10 @@ func reliablySendEachMsgAsTx(
 		}
 
 		covAddrStr := covAddr.String()
-		logger.Debug("covenant_signing", zap.String("address", covAddrStr))
+		log.Debug(
+			"covenant_signing",
+			zap.String("address", covAddrStr),
+		)
 
 		covAcc, err := getAcc(covAddrStr)
 		if err != nil {
@@ -96,7 +99,7 @@ func reliablySendEachMsgAsTx(
 			txResp, err := ReliablySendMsgsWithSequence(
 				ctx,
 				cfg,
-				logger,
+				log,
 				cometClient,
 				c,
 				encCfg,
@@ -110,10 +113,15 @@ func reliablySendEachMsgAsTx(
 				// log msg fail
 				failedMsgs = append(failedMsgs, msg)
 			}
+			if txResp != nil {
+				log.Debug("resp", zap.String("txHash", txResp.TxHash))
+
+				txResponses = append(txResponses, txResp)
+			} else {
+				failedMsgs = append(failedMsgs, msg)
+			}
 
 			accSequence++
-			logger.Debug("resp", zap.String("txHash", txResp.TxHash))
-			txResponses = append(txResponses, txResp)
 		}
 
 		return nil
@@ -141,13 +149,13 @@ func ReliablySendMsgsWithSequence(
 	expectedErrors, unrecoverableErrors []*sdkerrors.Error,
 ) (*sdk.TxResponse, error) {
 	var (
-		rlyResp     *sdk.TxResponse
+		tx          *sdk.TxResponse
 		callbackErr error
 		wg          sync.WaitGroup
 	)
 
-	callback := func(rtr *sdk.TxResponse, err error) {
-		rlyResp = rtr
+	callback := func(txResp *sdk.TxResponse, err error) {
+		tx = txResp
 		callbackErr = err
 		wg.Done()
 	}
@@ -187,16 +195,16 @@ func ReliablySendMsgsWithSequence(
 		return nil, callbackErr
 	}
 
-	if rlyResp == nil {
+	if tx == nil {
 		// this case could happen if the error within the retry is an expected error
 		return nil, nil
 	}
 
-	if rlyResp.Code != 0 {
-		return rlyResp, fmt.Errorf("transaction failed with code: %d", rlyResp.Code)
+	if tx.Code != 0 {
+		return tx, fmt.Errorf("transaction failed with code: %d", tx.Code)
 	}
 
-	return rlyResp, nil
+	return tx, nil
 }
 
 // SendMessagesToMempool simulates and broadcasts a transaction with the given msgs and memo.

From 1e149e01a10fdc6566087da96532813d5a74b720 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 07:43:16 -0300
Subject: [PATCH 09/31] chore: add errgroup

---
 clientcontroller/babylon_msg.go | 121 +++++++++++++++++++-------------
 1 file changed, 72 insertions(+), 49 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 12423f2..5f73403 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -38,10 +38,13 @@ import (
 	strangeloveclient "github.com/strangelove-ventures/cometbft-client/client"
 	rpcclient "github.com/strangelove-ventures/cometbft-client/rpc/client"
 	"go.uber.org/zap"
+	"golang.org/x/sync/errgroup"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
 
+const MaxParallelMsgs = 20
+
 var (
 	rtyAttNum                   = uint(5)
 	rtyAtt                      = retry.Attempts(rtyAttNum)
@@ -52,6 +55,8 @@ var (
 	dstChanTag                  = "packet_dst_channel"
 )
 
+type callbackTx func(*sdk.TxResponse, error)
+
 func reliablySendEachMsgAsTx(
 	cfg *config.BabylonConfig,
 	msgs []sdk.Msg,
@@ -67,8 +72,14 @@ func reliablySendEachMsgAsTx(
 	}
 
 	ctx := context.Background()
-	txResponses = make([]*sdk.TxResponse, 0)
-	failedMsgs = make([]sdk.Msg, 0)
+
+	// create outputs at msg len capacity to handle each msg in parallel
+	// as it is easier than pass 2 channels for each func
+	txResponses = make([]*sdk.TxResponse, len(msgs))
+	failedMsgs = make([]sdk.Msg, len(msgs))
+
+	eg, egCtx := errgroup.WithContext(ctx)
+	eg.SetLimit(MaxParallelMsgs)
 
 	errAccKey := AccessKeyWithLock(cfg.KeyDirectory, func() error {
 		keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
@@ -95,32 +106,49 @@ func reliablySendEachMsgAsTx(
 		accSequence := covAcc.GetSequence()
 		accNumber := covAcc.GetAccountNumber()
 
-		for _, msg := range msgs {
-			txResp, err := ReliablySendMsgsWithSequence(
-				ctx,
-				cfg,
-				log,
-				cometClient,
-				c,
-				encCfg,
-				covAddrStr,
-				accSequence,
-				accNumber,
-				[]sdk.Msg{msg},
-				expectedErrors, unrecoverableErrors,
-			)
-			if err != nil {
-				// log msg fail
-				failedMsgs = append(failedMsgs, msg)
-			}
-			if txResp != nil {
-				log.Debug("resp", zap.String("txHash", txResp.TxHash))
-
-				txResponses = append(txResponses, txResp)
-			} else {
-				failedMsgs = append(failedMsgs, msg)
-			}
-
+		for i, msg := range msgs {
+			eg.Go(func() error {
+				txResp, err := ReliablySendMsgsWithSequence(
+					egCtx,
+					cfg,
+					log,
+					cometClient,
+					c,
+					encCfg,
+					covAddrStr,
+					accSequence,
+					accNumber,
+					[]sdk.Msg{msg},
+					expectedErrors, unrecoverableErrors,
+				)
+
+				if err != nil {
+					failedMsgs[i] = msg
+					log.Error(
+						"failed to submit message",
+						zap.Int("msg_index", i),
+						zap.String("msg_data", msg.String()),
+						zap.Error(err),
+					)
+					return err
+				}
+
+				if txResp != nil {
+					log.Debug(
+						"sucessfully submit message",
+						zap.Int("msg_index", i),
+						zap.String("tx_hash", txResp.TxHash),
+					)
+					txResponses[i] = txResp
+				} else {
+					log.Debug(
+						"sucessfully submit message, got expected error",
+						zap.Int("msg_index", i),
+					)
+					failedMsgs[i] = msg
+				}
+				return nil
+			})
 			accSequence++
 		}
 
@@ -130,9 +158,19 @@ func reliablySendEachMsgAsTx(
 		return nil, nil, err
 	}
 
+	err = eg.Wait()
+
+	// clean the outputs
+
+	if err != nil {
+		return txResponses, failedMsgs, err
+	}
+
 	return txResponses, failedMsgs, nil
 }
 
+// func cleanNil()
+
 // ReliablySendMsgsWithSequence reliably sends a list of messages to the chain.
 // It utilizes a file lock as well as a keyring lock to ensure atomic access.
 func ReliablySendMsgsWithSequence(
@@ -163,7 +201,7 @@ func ReliablySendMsgsWithSequence(
 	wg.Add(1)
 
 	if err := retry.Do(func() error {
-		sendMsgErr := SendMessagesToMempool(ctx, cfg, logger, cometClient, rpcClient, encCfg, msgs, "", accAddress, accSequence, accNumber, []func(*sdk.TxResponse, error){callback})
+		sendMsgErr := SendMessagesToMempool(ctx, cfg, logger, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, []callbackTx{callback})
 		if sendMsgErr != nil {
 			if ErrorContained(sendMsgErr, unrecoverableErrors) {
 				logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
@@ -220,17 +258,16 @@ func SendMessagesToMempool(
 	encCfg *appparams.EncodingConfig,
 
 	msgs []sdk.Msg,
-	memo string,
 
-	accAddress string,
 	accSequence, accNumber uint64,
 
-	asyncCallbacks []func(*sdk.TxResponse, error),
+	asyncCallbacks []callbackTx,
 ) error {
 	txSignerKey := cfg.Key
+	memo, gas := "", uint64(0)
 
 	txBytes, fees, err := BuildMessages(
-		ctx, cfg, cometClient, rpcClient, encCfg, msgs, memo, 0, txSignerKey, accAddress, accSequence, accNumber,
+		ctx, cfg, cometClient, rpcClient, encCfg, msgs, memo, gas, txSignerKey, accSequence, accNumber,
 	)
 	if err != nil {
 		return err
@@ -254,7 +291,6 @@ func BuildMessages(
 	memo string,
 	gas uint64,
 	txSignerKey string,
-	accAddress string,
 	accSequence, accNumber uint64,
 ) (
 	txBytes []byte,
@@ -266,18 +302,7 @@ func BuildMessages(
 		return nil, sdk.Coins{}, err
 	}
 
-	// cliCtx := client.Context{}.
-	// 	WithClient(cometClient).
-	// 	WithInterfaceRegistry(encCfg.InterfaceRegistry).
-	// 	WithChainID(cfg.ChainID).
-	// 	WithCodec(encCfg.Codec)
-
 	txf := TxFactory(cfg, encCfg.TxConfig, keybase)
-	// txf, err = PrepareFactory(cliCtx, txf, keybase, txSignerKey)
-	// if err != nil {
-	// 	return nil, sdk.Coins{}, err
-	// }
-
 	if memo != "" {
 		txf = txf.WithMemo(memo)
 	}
@@ -286,7 +311,6 @@ func BuildMessages(
 		WithAccountNumber(accNumber)
 
 	adjusted := gas
-
 	if gas == 0 {
 		_, adjusted, err = CalculateGas(ctx, rpcClient, keybase, txf, txSignerKey, cfg.GasAdjustment, msgs...)
 
@@ -336,7 +360,7 @@ func BroadcastTx(
 
 	asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast
 	asyncTimeout time.Duration, // timeout for waiting for block inclusion
-	asyncCallbacks []func(*sdk.TxResponse, error), // callback for success/fail of the wait for block inclusion
+	asyncCallbacks []callbackTx, // callback for success/fail of the wait for block inclusion
 ) error {
 	res, err := rpcClient.BroadcastTxSync(ctx, tx)
 	isErr := err != nil
@@ -436,7 +460,7 @@ func waitForTx(
 	txHash []byte,
 	msgs []sdk.Msg, // used for logging only
 	waitTimeout time.Duration,
-	callbacks []func(*sdk.TxResponse, error),
+	callbacks []callbackTx,
 ) {
 	res, err := waitForBlockInclusion(ctx, rpcClient, txConfig, txHash, waitTimeout)
 	if err != nil {
@@ -738,7 +762,6 @@ func TxFactory(
 	cfg *config.BabylonConfig,
 	txConf client.TxConfig,
 	keybase keyring.Keyring,
-
 ) tx.Factory {
 	return tx.Factory{}.
 		WithChainID(cfg.ChainID).

From 5bb07890fb5ce5949bd8339a72c36765d845aacb Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 09:57:36 -0300
Subject: [PATCH 10/31] fix: finally signing

---
 clientcontroller/babylon_msg.go | 125 ++++++++++++++++++++------------
 1 file changed, 79 insertions(+), 46 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 5f73403..0d80fa2 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -38,7 +38,6 @@ import (
 	strangeloveclient "github.com/strangelove-ventures/cometbft-client/client"
 	rpcclient "github.com/strangelove-ventures/cometbft-client/rpc/client"
 	"go.uber.org/zap"
-	"golang.org/x/sync/errgroup"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 )
@@ -65,8 +64,8 @@ func reliablySendEachMsgAsTx(
 	encCfg *appparams.EncodingConfig,
 	getAcc func(addr string) (sdk.AccountI, error),
 	expectedErrors, unrecoverableErrors []*sdkerrors.Error,
-) (txResponses []*sdk.TxResponse, failedMsgs []sdk.Msg, err error) {
-	c, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
+) (txResponses []*sdk.TxResponse, failedMsgs []*sdk.Msg, err error) {
+	rpcClient, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -76,10 +75,12 @@ func reliablySendEachMsgAsTx(
 	// create outputs at msg len capacity to handle each msg in parallel
 	// as it is easier than pass 2 channels for each func
 	txResponses = make([]*sdk.TxResponse, len(msgs))
-	failedMsgs = make([]sdk.Msg, len(msgs))
+	failedMsgs = make([]*sdk.Msg, len(msgs))
 
-	eg, egCtx := errgroup.WithContext(ctx)
-	eg.SetLimit(MaxParallelMsgs)
+	// eg, egCtx := errgroup.WithContext(ctx)
+	// eg.SetLimit(MaxParallelMsgs)
+
+	var wg sync.WaitGroup
 
 	errAccKey := AccessKeyWithLock(cfg.KeyDirectory, func() error {
 		keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
@@ -107,66 +108,86 @@ func reliablySendEachMsgAsTx(
 		accNumber := covAcc.GetAccountNumber()
 
 		for i, msg := range msgs {
-			eg.Go(func() error {
-				txResp, err := ReliablySendMsgsWithSequence(
-					egCtx,
-					cfg,
-					log,
-					cometClient,
-					c,
-					encCfg,
-					covAddrStr,
-					accSequence,
-					accNumber,
-					[]sdk.Msg{msg},
-					expectedErrors, unrecoverableErrors,
-				)
+			wg.Add(1)
+
+			callback := func(txResp *sdk.TxResponse, err error) {
+				defer wg.Done()
 
 				if err != nil {
-					failedMsgs[i] = msg
+					failedMsgs[i] = &msg
+
+					if ErrorContained(err, expectedErrors) {
+						log.Debug(
+							"sucessfully submit message, got expected error",
+							zap.Int("msg_index", i),
+						)
+						return
+					}
+
 					log.Error(
 						"failed to submit message",
 						zap.Int("msg_index", i),
 						zap.String("msg_data", msg.String()),
 						zap.Error(err),
 					)
-					return err
+					return
 				}
 
-				if txResp != nil {
-					log.Debug(
-						"sucessfully submit message",
-						zap.Int("msg_index", i),
-						zap.String("tx_hash", txResp.TxHash),
-					)
-					txResponses[i] = txResp
-				} else {
-					log.Debug(
-						"sucessfully submit message, got expected error",
-						zap.Int("msg_index", i),
-					)
-					failedMsgs[i] = msg
+				log.Debug(
+					"sucessfully submit message",
+					zap.Int("msg_index", i),
+					zap.String("tx_hash", txResp.TxHash),
+				)
+				txResponses[i] = txResp
+			}
+
+			errRetry := retry.Do(func() error {
+				sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, []callbackTx{callback})
+				if sendMsgErr != nil {
+					if ErrorContained(sendMsgErr, unrecoverableErrors) {
+						log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
+						return retry.Unrecoverable(sendMsgErr)
+					}
+					if ErrorContained(sendMsgErr, expectedErrors) {
+						// this is necessary because if err is returned
+						// the callback function will not be executed so
+						// that the inside wg.Done will not be executed
+						wg.Done()
+						log.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
+						return nil
+					}
+					return sendMsgErr
 				}
 				return nil
-			})
+			}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, err error) {
+				log.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
+			}))
+
+			if errRetry != nil {
+				return errRetry
+			}
+
 			accSequence++
 		}
 
 		return nil
 	})
+
+	wg.Wait()
+
 	if errAccKey != nil {
 		return nil, nil, err
 	}
 
-	err = eg.Wait()
+	// err = eg.Wait()
 
 	// clean the outputs
 
-	if err != nil {
-		return txResponses, failedMsgs, err
-	}
+	// if err != nil {
+	// 	return txResponses, failedMsgs, err
+	// }
 
-	return txResponses, failedMsgs, nil
+	return CleanSlice(txResponses), CleanSlice(failedMsgs), nil
 }
 
 // func cleanNil()
@@ -176,7 +197,7 @@ func reliablySendEachMsgAsTx(
 func ReliablySendMsgsWithSequence(
 	ctx context.Context,
 	cfg *config.BabylonConfig,
-	logger *zap.Logger,
+	log *zap.Logger,
 	cometClient client.CometRPC,
 	rpcClient *strangeloveclient.Client,
 	encCfg *appparams.EncodingConfig,
@@ -192,6 +213,7 @@ func ReliablySendMsgsWithSequence(
 		wg          sync.WaitGroup
 	)
 
+	// todo: callback needs to be in outside func
 	callback := func(txResp *sdk.TxResponse, err error) {
 		tx = txResp
 		callbackErr = err
@@ -201,10 +223,10 @@ func ReliablySendMsgsWithSequence(
 	wg.Add(1)
 
 	if err := retry.Do(func() error {
-		sendMsgErr := SendMessagesToMempool(ctx, cfg, logger, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, []callbackTx{callback})
+		sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, []callbackTx{callback})
 		if sendMsgErr != nil {
 			if ErrorContained(sendMsgErr, unrecoverableErrors) {
-				logger.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
+				log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
 				return retry.Unrecoverable(sendMsgErr)
 			}
 			if ErrorContained(sendMsgErr, expectedErrors) {
@@ -212,14 +234,14 @@ func ReliablySendMsgsWithSequence(
 				// the callback function will not be executed so
 				// that the inside wg.Done will not be executed
 				wg.Done()
-				logger.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
+				log.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
 				return nil
 			}
 			return sendMsgErr
 		}
 		return nil
 	}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, err error) {
-		logger.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
+		log.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
 	})); err != nil {
 		return nil, err
 	}
@@ -868,3 +890,14 @@ func sdkError(codespace string, code uint32) error {
 type intoAny interface {
 	AsAny() *codectypes.Any
 }
+
+// CleanSlice removes nil values from a slice of pointers.
+func CleanSlice[T any](slice []*T) []*T {
+	result := make([]*T, 0, len(slice))
+	for _, item := range slice {
+		if item != nil {
+			result = append(result, item)
+		}
+	}
+	return result
+}

From 2ecb65aa8c6d1e575f1ce47dbe0d2c83ba02de08 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 10:13:38 -0300
Subject: [PATCH 11/31] fix: lint and notes

---
 clientcontroller/babylon_msg.go | 98 +++++++++++++++++----------------
 1 file changed, 51 insertions(+), 47 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 0d80fa2..180b887 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -42,8 +42,8 @@ import (
 	"google.golang.org/grpc/status"
 )
 
-const MaxParallelMsgs = 20
-
+// Note: most of the functions were adappt from
+// https://github.com/babylonlabs-io/babylon/blob/cd0bbcd98be5e4dda081f7330140cf9dbee4c94d/client/client/tx.go#L76
 var (
 	rtyAttNum                   = uint(5)
 	rtyAtt                      = retry.Attempts(rtyAttNum)
@@ -54,8 +54,10 @@ var (
 	dstChanTag                  = "packet_dst_channel"
 )
 
+// callbackTx is the expected type that waits for the inclusion of a transaction on the chain to be called
 type callbackTx func(*sdk.TxResponse, error)
 
+// reliablySendEachMsgAsTx creates multiple
 func reliablySendEachMsgAsTx(
 	cfg *config.BabylonConfig,
 	msgs []sdk.Msg,
@@ -72,13 +74,11 @@ func reliablySendEachMsgAsTx(
 
 	ctx := context.Background()
 
+	msgLen := len(msgs)
 	// create outputs at msg len capacity to handle each msg in parallel
 	// as it is easier than pass 2 channels for each func
-	txResponses = make([]*sdk.TxResponse, len(msgs))
-	failedMsgs = make([]*sdk.Msg, len(msgs))
-
-	// eg, egCtx := errgroup.WithContext(ctx)
-	// eg.SetLimit(MaxParallelMsgs)
+	txResponses = make([]*sdk.TxResponse, msgLen)
+	failedMsgs = make([]*sdk.Msg, msgLen)
 
 	var wg sync.WaitGroup
 
@@ -110,38 +110,9 @@ func reliablySendEachMsgAsTx(
 		for i, msg := range msgs {
 			wg.Add(1)
 
-			callback := func(txResp *sdk.TxResponse, err error) {
-				defer wg.Done()
-
-				if err != nil {
-					failedMsgs[i] = &msg
-
-					if ErrorContained(err, expectedErrors) {
-						log.Debug(
-							"sucessfully submit message, got expected error",
-							zap.Int("msg_index", i),
-						)
-						return
-					}
-
-					log.Error(
-						"failed to submit message",
-						zap.Int("msg_index", i),
-						zap.String("msg_data", msg.String()),
-						zap.Error(err),
-					)
-					return
-				}
-
-				log.Debug(
-					"sucessfully submit message",
-					zap.Int("msg_index", i),
-					zap.String("tx_hash", txResp.TxHash),
-				)
-				txResponses[i] = txResp
-			}
-
+			callback := reliablySendEachMsgAsTxCallback(log, &wg, msg, i, txResponses, failedMsgs)
 			errRetry := retry.Do(func() error {
+				// SendMessagesToMempool launches a go routine to wait for the tx be included and call the callback func
 				sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, []callbackTx{callback})
 				if sendMsgErr != nil {
 					if ErrorContained(sendMsgErr, unrecoverableErrors) {
@@ -149,10 +120,10 @@ func reliablySendEachMsgAsTx(
 						return retry.Unrecoverable(sendMsgErr)
 					}
 					if ErrorContained(sendMsgErr, expectedErrors) {
+						defer wg.Done()
 						// this is necessary because if err is returned
 						// the callback function will not be executed so
 						// that the inside wg.Done will not be executed
-						wg.Done()
 						log.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
 						return nil
 					}
@@ -179,14 +150,6 @@ func reliablySendEachMsgAsTx(
 		return nil, nil, err
 	}
 
-	// err = eg.Wait()
-
-	// clean the outputs
-
-	// if err != nil {
-	// 	return txResponses, failedMsgs, err
-	// }
-
 	return CleanSlice(txResponses), CleanSlice(failedMsgs), nil
 }
 
@@ -901,3 +864,44 @@ func CleanSlice[T any](slice []*T) []*T {
 	}
 	return result
 }
+
+func reliablySendEachMsgAsTxCallback(
+	log *zap.Logger,
+	wg *sync.WaitGroup,
+	msg sdk.Msg,
+	index int,
+	txResponses []*sdk.TxResponse,
+	failedMsgs []*sdk.Msg,
+) callbackTx {
+	return func(txResp *sdk.TxResponse, err error) {
+		defer wg.Done()
+
+		if err != nil {
+			failedMsgs[index] = &msg
+
+			if ErrorContained(err, expectedErrors) {
+				log.Debug(
+					"sucessfully submit message, got expected error",
+					zap.Int("msg_index", index),
+				)
+				return
+			}
+
+			log.Error(
+				"failed to submit message",
+				zap.Int("msg_index", index),
+				zap.String("msg_data", msg.String()),
+				zap.Error(err),
+			)
+			return
+		}
+
+		log.Debug(
+			"sucessfully submit message",
+			zap.Int("msg_index", index),
+			zap.String("tx_hash", txResp.TxHash),
+		)
+		txResponses[index] = txResp
+	}
+
+}

From 502cf0e86b92c6912981f0e0c30897ec88c03721 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 10:15:08 -0300
Subject: [PATCH 12/31] chore: remove split of e2e test runs, failing to start

---
 itest/e2e_test.go | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/itest/e2e_test.go b/itest/e2e_test.go
index b2ba621..fd44893 100644
--- a/itest/e2e_test.go
+++ b/itest/e2e_test.go
@@ -48,13 +48,8 @@ func TestCovenantEmulatorLifeCycle(t *testing.T) {
 	res, err := tm.CovenantEmulator.AddCovenantSignatures(dels)
 	require.NoError(t, err)
 	require.Empty(t, res)
-}
-
-func TestQueryPendingDelegations(t *testing.T) {
-	tm, btcPks := StartManagerWithFinalityProvider(t, 1)
-	defer tm.Stop(t)
 
-	// manually sets the pg to a low value
+	// Check pending dels
 	clientcontroller.MaxPaginationLimit = 2
 
 	numDels := 3
@@ -62,7 +57,7 @@ func TestQueryPendingDelegations(t *testing.T) {
 		_ = tm.InsertBTCDelegation(t, btcPks, stakingTime, stakingAmount, false)
 	}
 
-	dels, err := tm.CovBBNClient.QueryPendingDelegations(uint64(numDels), nil)
+	dels, err = tm.CovBBNClient.QueryPendingDelegations(uint64(numDels), nil)
 	require.NoError(t, err)
 	require.Len(t, dels, numDels)
 }

From 81f31d38b69a2554b7b944dd25bfe3f45ba7eaae Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 10:53:17 -0300
Subject: [PATCH 13/31] chore: split e2e run on covenant emulator

---
 .github/workflows/ci.yml        |  60 +++++++++++++++++-
 Makefile                        |  10 ++-
 clientcontroller/babylon.go     |  31 ++++++---
 clientcontroller/babylon_msg.go | 108 ++------------------------------
 itest/e2e_test.go               |   9 ++-
 5 files changed, 103 insertions(+), 115 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 691d0e5..074fed1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -12,7 +12,7 @@ jobs:
       go-version: '1.23'
       go-lint-version: 'v1.60.2'
       run-unit-tests: true
-      run-integration-tests: true
+      run-integration-tests: false
       run-lint: true
       run-build: true
       run-gosec: true
@@ -55,3 +55,61 @@ jobs:
       dockerContext: ./
       repoName: covenant-signer
       docker_scan: true
+
+###############################################################################
+###                                   E2E                                   ###
+###############################################################################
+
+  e2e-cov-signer:
+      runs-on: ubuntu-22.04
+      steps:
+        - name: Checkout repository
+          uses: actions/checkout@v4
+        - name: Login to Docker Hub
+          uses: docker/login-action@v3
+          with:
+            username: ${{ secrets.DOCKERHUB_USERNAME }}
+            password: ${{ secrets.DOCKERHUB_TOKEN }}
+        - name: Cache Go
+          uses: actions/setup-go@v5
+          with:
+            go-version: 1.23.1
+        - name: Run e2e covenant signer
+          run: |
+            cd covenant-signer; make test-e2e
+
+  e2e-cov-emulator-life:
+      runs-on: ubuntu-22.04
+      steps:
+        - name: Checkout repository
+          uses: actions/checkout@v4
+        - name: Login to Docker Hub
+          uses: docker/login-action@v3
+          with:
+            username: ${{ secrets.DOCKERHUB_USERNAME }}
+            password: ${{ secrets.DOCKERHUB_TOKEN }}
+        - name: Cache Go
+          uses: actions/setup-go@v5
+          with:
+            go-version: 1.23.1
+        - name: Run e2e covenant emulator life cycle
+          run: |
+            make test-e2e-cov-emu-life
+
+  e2e-cov-pending-dels:
+      runs-on: ubuntu-22.04
+      steps:
+        - name: Checkout repository
+          uses: actions/checkout@v4
+        - name: Login to Docker Hub
+          uses: docker/login-action@v3
+          with:
+            username: ${{ secrets.DOCKERHUB_USERNAME }}
+            password: ${{ secrets.DOCKERHUB_TOKEN }}
+        - name: Cache Go
+          uses: actions/setup-go@v5
+          with:
+            go-version: 1.23.1
+        - name: Run e2e covenant emulator pending dels
+          run: |
+            make test-e2e-cov-pending-del
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 13a2569..3e1223b 100644
--- a/Makefile
+++ b/Makefile
@@ -59,9 +59,17 @@ test:
 
 test-e2e:
 	cd $(TOOLS_DIR); go install -trimpath $(BABYLON_PKG)
-	go test -mod=readonly -timeout=25m -v $(PACKAGES_E2E) -count=1 --tags=e2e
+	go test -mod=readonly -timeout=5m -v $(PACKAGES_E2E) --tags=e2e
 	cd covenant-signer; make test-e2e
 
+test-e2e-cov-emu-life:
+	cd $(TOOLS_DIR); go install -trimpath $(BABYLON_PKG)
+	go test -run TestCovenantEmulatorLifeCycle -mod=readonly -timeout=5m -v $(PACKAGES_E2E) --tags=e2e
+
+test-e2e-cov-pending-del:
+	cd $(TOOLS_DIR); go install -trimpath $(BABYLON_PKG)
+	go test -run TestQueryPendingDelegations -mod=readonly -timeout=5m -v $(PACKAGES_E2E) --tags=e2e
+
 mock-gen:
 	mkdir -p $(MOCKS_DIR)
 	$(MOCKGEN_CMD) -source=clientcontroller/interface.go -package mocks -destination $(MOCKS_DIR)/babylon.go
diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index 6d930cf..fcf9860 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -166,20 +166,33 @@ func (bc *BabylonController) reliablySendMsgs(msgs []sdk.Msg) (*provider.Relayer
 
 func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) (*provider.RelayerTxResponse, error) {
 	// ctx := context.Background()
-
+	cfg := bc.bbnClient.GetConfig()
+	encCfg := bc.encCfg
 	// c := bc.bbnClient.GetConfig()
 	// c.acc
+	keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
+	if err != nil {
+		return nil, err
+	}
 
-	_, _, err := reliablySendEachMsgAsTx(bc.bbnClient.GetConfig(), msgs, bc.logger, bc.bbnClient.RPCClient, bc.encCfg, bc.QueryAccount, expectedErrors, unrecoverableErrors)
+	covAddr, err := GetKeyAddressForKey(keybase, cfg.Key)
+	if err != nil {
+		return nil, err
+	}
+
+	covAddrStr := covAddr.String()
+	bc.logger.Debug(
+		"covenant_signing",
+		zap.String("address", covAddrStr),
+	)
+
+	covAcc, err := bc.QueryAccount(covAddrStr)
+	if err != nil {
+		return nil, err
+	}
 
+	_, _, err = reliablySendEachMsgAsTx(cfg, msgs, bc.logger, bc.bbnClient.RPCClient, encCfg, covAcc, expectedErrors, unrecoverableErrors)
 	return nil, err
-	// bc.bbnClient.SendMsgToMempool()
-	// return bc.bbnClient.ReliablySendMsgs(
-	// 	context.Background(),
-	// 	msgs,
-	// 	expectedErrors,
-	// 	unrecoverableErrors,
-	// )
 }
 
 // SubmitCovenantSigs submits the Covenant signature via a MsgAddCovenantSig to Babylon if the daemon runs in Covenant mode
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 180b887..19ff721 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -64,7 +64,7 @@ func reliablySendEachMsgAsTx(
 	log *zap.Logger,
 	cometClient client.CometRPC,
 	encCfg *appparams.EncodingConfig,
-	getAcc func(addr string) (sdk.AccountI, error),
+	covAcc sdk.AccountI,
 	expectedErrors, unrecoverableErrors []*sdkerrors.Error,
 ) (txResponses []*sdk.TxResponse, failedMsgs []*sdk.Msg, err error) {
 	rpcClient, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
@@ -83,27 +83,6 @@ func reliablySendEachMsgAsTx(
 	var wg sync.WaitGroup
 
 	errAccKey := AccessKeyWithLock(cfg.KeyDirectory, func() error {
-		keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
-		if err != nil {
-			return err
-		}
-
-		covAddr, err := GetKeyAddressForKey(keybase, cfg.Key)
-		if err != nil {
-			return err
-		}
-
-		covAddrStr := covAddr.String()
-		log.Debug(
-			"covenant_signing",
-			zap.String("address", covAddrStr),
-		)
-
-		covAcc, err := getAcc(covAddrStr)
-		if err != nil {
-			return err
-		}
-
 		accSequence := covAcc.GetSequence()
 		accNumber := covAcc.GetAccountNumber()
 
@@ -113,14 +92,15 @@ func reliablySendEachMsgAsTx(
 			callback := reliablySendEachMsgAsTxCallback(log, &wg, msg, i, txResponses, failedMsgs)
 			errRetry := retry.Do(func() error {
 				// SendMessagesToMempool launches a go routine to wait for the tx be included and call the callback func
-				sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, []callbackTx{callback})
+				sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback)
 				if sendMsgErr != nil {
+					defer wg.Done()
+
 					if ErrorContained(sendMsgErr, unrecoverableErrors) {
 						log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
 						return retry.Unrecoverable(sendMsgErr)
 					}
 					if ErrorContained(sendMsgErr, expectedErrors) {
-						defer wg.Done()
 						// this is necessary because if err is returned
 						// the callback function will not be executed so
 						// that the inside wg.Done will not be executed
@@ -131,6 +111,7 @@ func reliablySendEachMsgAsTx(
 				}
 				return nil
 			}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, err error) {
+				wg.Add(1)
 				log.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
 			}))
 
@@ -153,83 +134,6 @@ func reliablySendEachMsgAsTx(
 	return CleanSlice(txResponses), CleanSlice(failedMsgs), nil
 }
 
-// func cleanNil()
-
-// ReliablySendMsgsWithSequence reliably sends a list of messages to the chain.
-// It utilizes a file lock as well as a keyring lock to ensure atomic access.
-func ReliablySendMsgsWithSequence(
-	ctx context.Context,
-	cfg *config.BabylonConfig,
-	log *zap.Logger,
-	cometClient client.CometRPC,
-	rpcClient *strangeloveclient.Client,
-	encCfg *appparams.EncodingConfig,
-
-	accAddress string,
-	accSequence, accNumber uint64,
-	msgs []sdk.Msg,
-	expectedErrors, unrecoverableErrors []*sdkerrors.Error,
-) (*sdk.TxResponse, error) {
-	var (
-		tx          *sdk.TxResponse
-		callbackErr error
-		wg          sync.WaitGroup
-	)
-
-	// todo: callback needs to be in outside func
-	callback := func(txResp *sdk.TxResponse, err error) {
-		tx = txResp
-		callbackErr = err
-		wg.Done()
-	}
-
-	wg.Add(1)
-
-	if err := retry.Do(func() error {
-		sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, []callbackTx{callback})
-		if sendMsgErr != nil {
-			if ErrorContained(sendMsgErr, unrecoverableErrors) {
-				log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
-				return retry.Unrecoverable(sendMsgErr)
-			}
-			if ErrorContained(sendMsgErr, expectedErrors) {
-				// this is necessary because if err is returned
-				// the callback function will not be executed so
-				// that the inside wg.Done will not be executed
-				wg.Done()
-				log.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
-				return nil
-			}
-			return sendMsgErr
-		}
-		return nil
-	}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, err error) {
-		log.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
-	})); err != nil {
-		return nil, err
-	}
-
-	wg.Wait()
-
-	if callbackErr != nil {
-		if ErrorContained(callbackErr, expectedErrors) {
-			return nil, nil
-		}
-		return nil, callbackErr
-	}
-
-	if tx == nil {
-		// this case could happen if the error within the retry is an expected error
-		return nil, nil
-	}
-
-	if tx.Code != 0 {
-		return tx, fmt.Errorf("transaction failed with code: %d", tx.Code)
-	}
-
-	return tx, nil
-}
-
 // SendMessagesToMempool simulates and broadcasts a transaction with the given msgs and memo.
 // This method will return once the transaction has entered the mempool.
 // In an async goroutine, will wait for the tx to be included in the block unless asyncCtx exits.
@@ -246,7 +150,7 @@ func SendMessagesToMempool(
 
 	accSequence, accNumber uint64,
 
-	asyncCallbacks []callbackTx,
+	asyncCallbacks ...callbackTx,
 ) error {
 	txSignerKey := cfg.Key
 	memo, gas := "", uint64(0)
diff --git a/itest/e2e_test.go b/itest/e2e_test.go
index fd44893..b2ba621 100644
--- a/itest/e2e_test.go
+++ b/itest/e2e_test.go
@@ -48,8 +48,13 @@ func TestCovenantEmulatorLifeCycle(t *testing.T) {
 	res, err := tm.CovenantEmulator.AddCovenantSignatures(dels)
 	require.NoError(t, err)
 	require.Empty(t, res)
+}
+
+func TestQueryPendingDelegations(t *testing.T) {
+	tm, btcPks := StartManagerWithFinalityProvider(t, 1)
+	defer tm.Stop(t)
 
-	// Check pending dels
+	// manually sets the pg to a low value
 	clientcontroller.MaxPaginationLimit = 2
 
 	numDels := 3
@@ -57,7 +62,7 @@ func TestCovenantEmulatorLifeCycle(t *testing.T) {
 		_ = tm.InsertBTCDelegation(t, btcPks, stakingTime, stakingAmount, false)
 	}
 
-	dels, err = tm.CovBBNClient.QueryPendingDelegations(uint64(numDels), nil)
+	dels, err := tm.CovBBNClient.QueryPendingDelegations(uint64(numDels), nil)
 	require.NoError(t, err)
 	require.Len(t, dels, numDels)
 }

From 430ed8be6d7028dcd62937d5ff266f7fac470286 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 10:57:04 -0300
Subject: [PATCH 14/31] chore: remove login docker

---
 .github/workflows/ci.yml | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 074fed1..e90a3e3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -65,11 +65,6 @@ jobs:
       steps:
         - name: Checkout repository
           uses: actions/checkout@v4
-        - name: Login to Docker Hub
-          uses: docker/login-action@v3
-          with:
-            username: ${{ secrets.DOCKERHUB_USERNAME }}
-            password: ${{ secrets.DOCKERHUB_TOKEN }}
         - name: Cache Go
           uses: actions/setup-go@v5
           with:
@@ -83,11 +78,6 @@ jobs:
       steps:
         - name: Checkout repository
           uses: actions/checkout@v4
-        - name: Login to Docker Hub
-          uses: docker/login-action@v3
-          with:
-            username: ${{ secrets.DOCKERHUB_USERNAME }}
-            password: ${{ secrets.DOCKERHUB_TOKEN }}
         - name: Cache Go
           uses: actions/setup-go@v5
           with:
@@ -101,11 +91,6 @@ jobs:
       steps:
         - name: Checkout repository
           uses: actions/checkout@v4
-        - name: Login to Docker Hub
-          uses: docker/login-action@v3
-          with:
-            username: ${{ secrets.DOCKERHUB_USERNAME }}
-            password: ${{ secrets.DOCKERHUB_TOKEN }}
         - name: Cache Go
           uses: actions/setup-go@v5
           with:

From 130e6272170480d178a593500848c9664e3cac8d Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 11:18:31 -0300
Subject: [PATCH 15/31] fix: wait group failure

---
 clientcontroller/babylon.go     | 48 ++++++++++++++++++---------------
 clientcontroller/babylon_msg.go | 37 +++++++++----------------
 2 files changed, 40 insertions(+), 45 deletions(-)

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index fcf9860..e1fdb6b 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -165,34 +165,40 @@ func (bc *BabylonController) reliablySendMsgs(msgs []sdk.Msg) (*provider.Relayer
 }
 
 func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) (*provider.RelayerTxResponse, error) {
-	// ctx := context.Background()
 	cfg := bc.bbnClient.GetConfig()
 	encCfg := bc.encCfg
-	// c := bc.bbnClient.GetConfig()
-	// c.acc
-	keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
-	if err != nil {
-		return nil, err
-	}
 
-	covAddr, err := GetKeyAddressForKey(keybase, cfg.Key)
-	if err != nil {
-		return nil, err
-	}
+	errAccKey := AccessKeyWithLock(cfg.KeyDirectory, func() error {
+		keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
+		if err != nil {
+			return err
+		}
 
-	covAddrStr := covAddr.String()
-	bc.logger.Debug(
-		"covenant_signing",
-		zap.String("address", covAddrStr),
-	)
+		covAddr, err := GetKeyAddressForKey(keybase, cfg.Key)
+		if err != nil {
+			return err
+		}
 
-	covAcc, err := bc.QueryAccount(covAddrStr)
-	if err != nil {
-		return nil, err
+		covAddrStr := covAddr.String()
+		bc.logger.Debug(
+			"covenant_signing",
+			zap.String("address", covAddrStr),
+		)
+
+		covAcc, err := bc.QueryAccount(covAddrStr)
+		if err != nil {
+			return err
+		}
+
+		_, _, err = reliablySendEachMsgAsTx(cfg, msgs, bc.logger, bc.bbnClient.RPCClient, encCfg, covAcc)
+		return err
+	})
+
+	if errAccKey != nil {
+		return nil, errAccKey
 	}
 
-	_, _, err = reliablySendEachMsgAsTx(cfg, msgs, bc.logger, bc.bbnClient.RPCClient, encCfg, covAcc, expectedErrors, unrecoverableErrors)
-	return nil, err
+	return nil, nil
 }
 
 // SubmitCovenantSigs submits the Covenant signature via a MsgAddCovenantSig to Babylon if the daemon runs in Covenant mode
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 19ff721..7104470 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -65,7 +65,6 @@ func reliablySendEachMsgAsTx(
 	cometClient client.CometRPC,
 	encCfg *appparams.EncodingConfig,
 	covAcc sdk.AccountI,
-	expectedErrors, unrecoverableErrors []*sdkerrors.Error,
 ) (txResponses []*sdk.TxResponse, failedMsgs []*sdk.Msg, err error) {
 	rpcClient, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
 	if err != nil {
@@ -82,28 +81,23 @@ func reliablySendEachMsgAsTx(
 
 	var wg sync.WaitGroup
 
-	errAccKey := AccessKeyWithLock(cfg.KeyDirectory, func() error {
-		accSequence := covAcc.GetSequence()
-		accNumber := covAcc.GetAccountNumber()
+	accSequence := covAcc.GetSequence()
+	accNumber := covAcc.GetAccountNumber()
 
-		for i, msg := range msgs {
-			wg.Add(1)
+	for i, msg := range msgs {
+		wg.Add(1)
 
-			callback := reliablySendEachMsgAsTxCallback(log, &wg, msg, i, txResponses, failedMsgs)
+		callback := reliablySendEachMsgAsTxCallback(log, &wg, msg, i, txResponses, failedMsgs)
+
+		go func(msg sdk.Msg, index int) {
 			errRetry := retry.Do(func() error {
-				// SendMessagesToMempool launches a go routine to wait for the tx be included and call the callback func
 				sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback)
 				if sendMsgErr != nil {
-					defer wg.Done()
-
 					if ErrorContained(sendMsgErr, unrecoverableErrors) {
 						log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
 						return retry.Unrecoverable(sendMsgErr)
 					}
 					if ErrorContained(sendMsgErr, expectedErrors) {
-						// this is necessary because if err is returned
-						// the callback function will not be executed so
-						// that the inside wg.Done will not be executed
 						log.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
 						return nil
 					}
@@ -111,26 +105,21 @@ func reliablySendEachMsgAsTx(
 				}
 				return nil
 			}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, err error) {
-				wg.Add(1)
 				log.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
 			}))
 
 			if errRetry != nil {
-				return errRetry
+				log.Error("failed to retry message", zap.Int("msg_index", index), zap.Error(errRetry))
+				// If the callback was not invoked, decrement the wait group here
+				wg.Done()
 			}
+		}(msg, i) // Pass msg and i as arguments to avoid closure issues
 
-			accSequence++
-		}
-
-		return nil
-	})
+		accSequence++
+	}
 
 	wg.Wait()
 
-	if errAccKey != nil {
-		return nil, nil, err
-	}
-
 	return CleanSlice(txResponses), CleanSlice(failedMsgs), nil
 }
 

From 184c4eb43b1cfcda796f78c6ffb4a88a6e19636f Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 11:25:31 -0300
Subject: [PATCH 16/31] chore: set permissions at the job level

---
 .github/workflows/ci.yml | 72 ++++++++++++++++++++++------------------
 1 file changed, 39 insertions(+), 33 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e90a3e3..7244cc5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -61,40 +61,46 @@ jobs:
 ###############################################################################
 
   e2e-cov-signer:
-      runs-on: ubuntu-22.04
-      steps:
-        - name: Checkout repository
-          uses: actions/checkout@v4
-        - name: Cache Go
-          uses: actions/setup-go@v5
-          with:
-            go-version: 1.23.1
-        - name: Run e2e covenant signer
-          run: |
-            cd covenant-signer; make test-e2e
+    permissions:
+      contents: read
+    runs-on: ubuntu-22.04
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+      - name: Cache Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: 1.23.1
+      - name: Run e2e covenant signer
+        run: |
+          cd covenant-signer; make test-e2e
 
   e2e-cov-emulator-life:
-      runs-on: ubuntu-22.04
-      steps:
-        - name: Checkout repository
-          uses: actions/checkout@v4
-        - name: Cache Go
-          uses: actions/setup-go@v5
-          with:
-            go-version: 1.23.1
-        - name: Run e2e covenant emulator life cycle
-          run: |
-            make test-e2e-cov-emu-life
+    permissions:
+      contents: read
+    runs-on: ubuntu-22.04
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+      - name: Cache Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: 1.23.1
+      - name: Run e2e covenant emulator life cycle
+        run: |
+          make test-e2e-cov-emu-life
 
   e2e-cov-pending-dels:
-      runs-on: ubuntu-22.04
-      steps:
-        - name: Checkout repository
-          uses: actions/checkout@v4
-        - name: Cache Go
-          uses: actions/setup-go@v5
-          with:
-            go-version: 1.23.1
-        - name: Run e2e covenant emulator pending dels
-          run: |
-            make test-e2e-cov-pending-del
\ No newline at end of file
+    permissions:
+      contents: read
+    runs-on: ubuntu-22.04
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+      - name: Cache Go
+        uses: actions/setup-go@v5
+        with:
+          go-version: 1.23.1
+      - name: Run e2e covenant emulator pending dels
+        run: |
+          make test-e2e-cov-pending-del
\ No newline at end of file

From 463c313182a500802f875e395bed1e58ccceeb5c Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 11:38:41 -0300
Subject: [PATCH 17/31] chore: solve function closure of vars

---
 clientcontroller/babylon_msg.go | 95 +++++++++++++++++++++------------
 1 file changed, 62 insertions(+), 33 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 7104470..a9831a5 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -84,36 +84,32 @@ func reliablySendEachMsgAsTx(
 	accSequence := covAcc.GetSequence()
 	accNumber := covAcc.GetAccountNumber()
 
-	for i, msg := range msgs {
-		wg.Add(1)
-
-		callback := reliablySendEachMsgAsTxCallback(log, &wg, msg, i, txResponses, failedMsgs)
-
-		go func(msg sdk.Msg, index int) {
-			errRetry := retry.Do(func() error {
-				sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback)
-				if sendMsgErr != nil {
-					if ErrorContained(sendMsgErr, unrecoverableErrors) {
-						log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
-						return retry.Unrecoverable(sendMsgErr)
-					}
-					if ErrorContained(sendMsgErr, expectedErrors) {
-						log.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
-						return nil
-					}
-					return sendMsgErr
-				}
-				return nil
-			}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, err error) {
-				log.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
-			}))
-
-			if errRetry != nil {
-				log.Error("failed to retry message", zap.Int("msg_index", index), zap.Error(errRetry))
+	for msgIndex, msg := range msgs {
+
+		callback := reliablySendEachMsgAsTxCallback(log, &wg, msg, msgIndex, txResponses, failedMsgs)
+
+		go func(
+			ctx context.Context,
+			cfg *config.BabylonConfig,
+			log *zap.Logger,
+			cometClient client.CometRPC,
+			rpcClient *strangeloveclient.Client,
+			encCfg *appparams.EncodingConfig,
+			msgs []sdk.Msg,
+			accSequence, accNumber uint64,
+			callback callbackTx,
+
+			msgIndex int,
+		) {
+			wg.Add(1)
+
+			errSendMsgs := RetrySendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback)
+			if errSendMsgs != nil {
+				log.Error("failed to retry message", zap.Int("msg_index", msgIndex), zap.Error(errSendMsgs))
 				// If the callback was not invoked, decrement the wait group here
 				wg.Done()
 			}
-		}(msg, i) // Pass msg and i as arguments to avoid closure issues
+		}(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback, msgIndex)
 
 		accSequence++
 	}
@@ -123,6 +119,39 @@ func reliablySendEachMsgAsTx(
 	return CleanSlice(txResponses), CleanSlice(failedMsgs), nil
 }
 
+func RetrySendMessagesToMempool(
+	ctx context.Context,
+	cfg *config.BabylonConfig,
+	log *zap.Logger,
+	cometClient client.CometRPC,
+	rpcClient *strangeloveclient.Client,
+	encCfg *appparams.EncodingConfig,
+
+	msgs []sdk.Msg,
+
+	accSequence, accNumber uint64,
+
+	asyncCallbacks ...callbackTx,
+) error {
+	return retry.Do(func() error {
+		sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, asyncCallbacks...)
+		if sendMsgErr != nil {
+			if ErrorContained(sendMsgErr, unrecoverableErrors) {
+				log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
+				return retry.Unrecoverable(sendMsgErr)
+			}
+			if ErrorContained(sendMsgErr, expectedErrors) {
+				log.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
+				return nil
+			}
+			return sendMsgErr
+		}
+		return nil
+	}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr, retry.OnRetry(func(n uint, err error) {
+		log.Debug("retrying", zap.Uint("attempt", n+1), zap.Uint("max_attempts", rtyAttNum), zap.Error(err))
+	}))
+}
+
 // SendMessagesToMempool simulates and broadcasts a transaction with the given msgs and memo.
 // This method will return once the transaction has entered the mempool.
 // In an async goroutine, will wait for the tx to be included in the block unless asyncCtx exits.
@@ -762,7 +791,7 @@ func reliablySendEachMsgAsTxCallback(
 	log *zap.Logger,
 	wg *sync.WaitGroup,
 	msg sdk.Msg,
-	index int,
+	msgIndex int,
 	txResponses []*sdk.TxResponse,
 	failedMsgs []*sdk.Msg,
 ) callbackTx {
@@ -770,19 +799,19 @@ func reliablySendEachMsgAsTxCallback(
 		defer wg.Done()
 
 		if err != nil {
-			failedMsgs[index] = &msg
+			failedMsgs[msgIndex] = &msg
 
 			if ErrorContained(err, expectedErrors) {
 				log.Debug(
 					"sucessfully submit message, got expected error",
-					zap.Int("msg_index", index),
+					zap.Int("msg_index", msgIndex),
 				)
 				return
 			}
 
 			log.Error(
 				"failed to submit message",
-				zap.Int("msg_index", index),
+				zap.Int("msg_index", msgIndex),
 				zap.String("msg_data", msg.String()),
 				zap.Error(err),
 			)
@@ -791,10 +820,10 @@ func reliablySendEachMsgAsTxCallback(
 
 		log.Debug(
 			"sucessfully submit message",
-			zap.Int("msg_index", index),
+			zap.Int("msg_index", msgIndex),
 			zap.String("tx_hash", txResp.TxHash),
 		)
-		txResponses[index] = txResp
+		txResponses[msgIndex] = txResp
 	}
 
 }

From 18ab8ce40b1be40061f71ca5e6cb8e9f7e67c7ac Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 11:42:14 -0300
Subject: [PATCH 18/31] fix: lint call add prior to go routine

---
 clientcontroller/babylon_msg.go | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index a9831a5..a6ba7f7 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -85,6 +85,7 @@ func reliablySendEachMsgAsTx(
 	accNumber := covAcc.GetAccountNumber()
 
 	for msgIndex, msg := range msgs {
+		wg.Add(1)
 
 		callback := reliablySendEachMsgAsTxCallback(log, &wg, msg, msgIndex, txResponses, failedMsgs)
 
@@ -101,8 +102,6 @@ func reliablySendEachMsgAsTx(
 
 			msgIndex int,
 		) {
-			wg.Add(1)
-
 			errSendMsgs := RetrySendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback)
 			if errSendMsgs != nil {
 				log.Error("failed to retry message", zap.Int("msg_index", msgIndex), zap.Error(errSendMsgs))

From 64fb0438f014e217b359eb288c561e28557f95e9 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 12:16:01 -0300
Subject: [PATCH 19/31] chore: set to run a single message at a time

---
 clientcontroller/babylon_msg.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index a6ba7f7..ccd229b 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -102,13 +102,13 @@ func reliablySendEachMsgAsTx(
 
 			msgIndex int,
 		) {
-			errSendMsgs := RetrySendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback)
-			if errSendMsgs != nil {
-				log.Error("failed to retry message", zap.Int("msg_index", msgIndex), zap.Error(errSendMsgs))
+			err := RetrySendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback)
+			if err != nil {
+				log.Error("failed to retry message", zap.Int("msg_index", msgIndex), zap.Error(err))
 				// If the callback was not invoked, decrement the wait group here
 				wg.Done()
 			}
-		}(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback, msgIndex)
+		}(ctx, cfg, log, cometClient, rpcClient, encCfg, []sdk.Msg{msg}, accSequence, accNumber, callback, msgIndex)
 
 		accSequence++
 	}

From 3980368ff508efa4ebf2bbf3a63b1eda5ebacfb0 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 12:28:22 -0300
Subject: [PATCH 20/31] tryfix: e2e test wait group

---
 clientcontroller/babylon_msg.go | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index ccd229b..d16454c 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -96,19 +96,23 @@ func reliablySendEachMsgAsTx(
 			cometClient client.CometRPC,
 			rpcClient *strangeloveclient.Client,
 			encCfg *appparams.EncodingConfig,
-			msgs []sdk.Msg,
+			msg sdk.Msg,
 			accSequence, accNumber uint64,
 			callback callbackTx,
 
 			msgIndex int,
 		) {
-			err := RetrySendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, callback)
+			err := RetrySendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, []sdk.Msg{msg}, accSequence, accNumber, callback)
 			if err != nil {
-				log.Error("failed to retry message", zap.Int("msg_index", msgIndex), zap.Error(err))
+				if ErrorContained(err, expectedErrors) {
+					log.Error("expected err when submitting the tx, skip retrying", zap.Error(err))
+				} else {
+					log.Error("failed to retry message", zap.Int("msg_index", msgIndex), zap.Error(err))
+				}
 				// If the callback was not invoked, decrement the wait group here
 				wg.Done()
 			}
-		}(ctx, cfg, log, cometClient, rpcClient, encCfg, []sdk.Msg{msg}, accSequence, accNumber, callback, msgIndex)
+		}(ctx, cfg, log, cometClient, rpcClient, encCfg, msg, accSequence, accNumber, callback, msgIndex)
 
 		accSequence++
 	}
@@ -139,10 +143,6 @@ func RetrySendMessagesToMempool(
 				log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
 				return retry.Unrecoverable(sendMsgErr)
 			}
-			if ErrorContained(sendMsgErr, expectedErrors) {
-				log.Error("expected err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
-				return nil
-			}
 			return sendMsgErr
 		}
 		return nil

From 91a7da1594724ea6dea424be08bb9fbd6a43df58 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 12:54:46 -0300
Subject: [PATCH 21/31] chore: add option to start covenant emulator

---
 itest/e2e_test.go     |  4 ++--
 itest/test_manager.go | 12 +++++++-----
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/itest/e2e_test.go b/itest/e2e_test.go
index b2ba621..3d10155 100644
--- a/itest/e2e_test.go
+++ b/itest/e2e_test.go
@@ -17,7 +17,7 @@ var (
 )
 
 func TestCovenantEmulatorLifeCycle(t *testing.T) {
-	tm, btcPks := StartManagerWithFinalityProvider(t, 1)
+	tm, btcPks := StartManagerWithFinalityProvider(t, 1, true)
 	defer tm.Stop(t)
 
 	// send a BTC delegation that is not following pre-approval flow
@@ -51,7 +51,7 @@ func TestCovenantEmulatorLifeCycle(t *testing.T) {
 }
 
 func TestQueryPendingDelegations(t *testing.T) {
-	tm, btcPks := StartManagerWithFinalityProvider(t, 1)
+	tm, btcPks := StartManagerWithFinalityProvider(t, 1, false)
 	defer tm.Stop(t)
 
 	// manually sets the pg to a low value
diff --git a/itest/test_manager.go b/itest/test_manager.go
index 8a913aa..7ffd28b 100644
--- a/itest/test_manager.go
+++ b/itest/test_manager.go
@@ -77,7 +77,7 @@ type testFinalityProviderData struct {
 	PoP            *bstypes.ProofOfPossessionBTC
 }
 
-func StartManager(t *testing.T) *TestManager {
+func StartManager(t *testing.T, shouldStartEmulator bool) *TestManager {
 	testDir, err := baseDir("cee2etest")
 	require.NoError(t, err)
 
@@ -158,8 +158,10 @@ func StartManager(t *testing.T) *TestManager {
 
 	ce, err := covenant.NewCovenantEmulator(covenantConfig, covbc, logger, signer)
 	require.NoError(t, err)
-	err = ce.Start()
-	require.NoError(t, err)
+	if shouldStartEmulator {
+		err = ce.Start()
+		require.NoError(t, err)
+	}
 
 	tm := &TestManager{
 		BabylonHandler:   bh,
@@ -206,8 +208,8 @@ func (tm *TestManager) SendToAddr(t *testing.T, toAddr, amount string) {
 	require.NoError(t, err)
 }
 
-func StartManagerWithFinalityProvider(t *testing.T, n int) (*TestManager, []*btcec.PublicKey) {
-	tm := StartManager(t)
+func StartManagerWithFinalityProvider(t *testing.T, n int, shouldStartEmulator bool) (*TestManager, []*btcec.PublicKey) {
+	tm := StartManager(t, shouldStartEmulator)
 
 	var btcPks []*btcec.PublicKey
 	for i := 0; i < n; i++ {

From 960a88ca7833a1da8940bf05e56a862ccf406033 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 14:31:40 -0300
Subject: [PATCH 22/31] chore: refactory to return an slice of tx response

---
 Makefile                        |  2 +-
 clientcontroller/babylon.go     | 84 +++++++++++++++++++++++++--------
 clientcontroller/babylon_msg.go | 16 +++++--
 clientcontroller/interface.go   |  2 +-
 covenant/covenant.go            |  8 ++--
 covenant/covenant_test.go       |  4 +-
 testutil/mocks/babylon.go       |  4 +-
 7 files changed, 87 insertions(+), 33 deletions(-)

diff --git a/Makefile b/Makefile
index 3e1223b..35ef6ab 100644
--- a/Makefile
+++ b/Makefile
@@ -64,7 +64,7 @@ test-e2e:
 
 test-e2e-cov-emu-life:
 	cd $(TOOLS_DIR); go install -trimpath $(BABYLON_PKG)
-	go test -run TestCovenantEmulatorLifeCycle -mod=readonly -timeout=5m -v $(PACKAGES_E2E) --tags=e2e
+	go test -run TestCovenantEmulatorLifeCycle -mod=readonly -timeout=7m -v $(PACKAGES_E2E) --tags=e2e
 
 test-e2e-cov-pending-del:
 	cd $(TOOLS_DIR); go install -trimpath $(BABYLON_PKG)
diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index e1fdb6b..d62c4c7 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -2,6 +2,7 @@ package clientcontroller
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"math"
 	"time"
@@ -155,6 +156,37 @@ func (bc *BabylonController) reliablySendMsg(msg sdk.Msg) (*provider.RelayerTxRe
 	return bc.reliablySendMsgs([]sdk.Msg{msg})
 }
 
+// SendMsgs first it tries to send all the messages in a single transaction
+// if it fails, sends each message in a different transaction.
+func (bc *BabylonController) SendMsgs(msgs []sdk.Msg) ([]*types.TxResponse, error) {
+	resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
+	if errSingleTx != nil {
+		// failed to send as a batch tx
+		resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
+		if errMultipleTx != nil {
+			return nil, errors.Join(errSingleTx, errMultipleTx)
+		}
+
+		return convertTxResp(resMultipleTxs...), nil
+	}
+
+	if resSingleTx == nil { // some expected error happened
+		return []*types.TxResponse{}, nil
+	}
+	return convertTxResp(resSingleTx), nil
+}
+
+func convertTxResp(txs ...*provider.RelayerTxResponse) []*types.TxResponse {
+	resp := make([]*types.TxResponse, len(txs))
+	for i, tx := range txs {
+		resp[i] = &types.TxResponse{
+			TxHash: tx.TxHash,
+			Events: tx.Events,
+		}
+	}
+	return resp
+}
+
 func (bc *BabylonController) reliablySendMsgs(msgs []sdk.Msg) (*provider.RelayerTxResponse, error) {
 	return bc.bbnClient.ReliablySendMsgs(
 		context.Background(),
@@ -164,9 +196,15 @@ func (bc *BabylonController) reliablySendMsgs(msgs []sdk.Msg) (*provider.Relayer
 	)
 }
 
-func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) (*provider.RelayerTxResponse, error) {
+func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) ([]*provider.RelayerTxResponse, error) {
 	cfg := bc.bbnClient.GetConfig()
 	encCfg := bc.encCfg
+	log := bc.logger
+
+	var (
+		txResponses []*sdk.TxResponse
+		failedMsgs  []*failedMsg
+	)
 
 	errAccKey := AccessKeyWithLock(cfg.KeyDirectory, func() error {
 		keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
@@ -180,7 +218,7 @@ func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) (*pro
 		}
 
 		covAddrStr := covAddr.String()
-		bc.logger.Debug(
+		log.Debug(
 			"covenant_signing",
 			zap.String("address", covAddrStr),
 		)
@@ -190,20 +228,39 @@ func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) (*pro
 			return err
 		}
 
-		_, _, err = reliablySendEachMsgAsTx(cfg, msgs, bc.logger, bc.bbnClient.RPCClient, encCfg, covAcc)
+		txResponses, failedMsgs, err = reliablySendEachMsgAsTx(cfg, msgs, log, bc.bbnClient.RPCClient, encCfg, covAcc)
 		return err
 	})
-
 	if errAccKey != nil {
 		return nil, errAccKey
 	}
 
-	return nil, nil
+	for _, failedMsg := range failedMsgs {
+		log.Warn(
+			"msg failed to submit as tx",
+			zap.String("msg", failedMsg.msg.String()),
+			zap.Error(failedMsg.reason),
+		)
+	}
+
+	resp := make([]*provider.RelayerTxResponse, len(txResponses))
+	for i, res := range txResponses {
+		resp[i] = &provider.RelayerTxResponse{
+			Height:    res.Height,
+			TxHash:    res.TxHash,
+			Codespace: res.Codespace,
+			Code:      res.Code,
+			Data:      res.Data,
+			Events:    parseEventsFromTxResponse(res),
+		}
+	}
+
+	return resp, nil
 }
 
 // SubmitCovenantSigs submits the Covenant signature via a MsgAddCovenantSig to Babylon if the daemon runs in Covenant mode
 // it returns tx hash and error
-func (bc *BabylonController) SubmitCovenantSigs(covSigs []*types.CovenantSigs) (*types.TxResponse, error) {
+func (bc *BabylonController) SubmitCovenantSigs(covSigs []*types.CovenantSigs) ([]*types.TxResponse, error) {
 	msgs := make([]sdk.Msg, 0, len(covSigs))
 	for _, covSig := range covSigs {
 		bip340UnbondingSig := bbntypes.NewBIP340SignatureFromBTCSig(covSig.UnbondingSig)
@@ -216,20 +273,7 @@ func (bc *BabylonController) SubmitCovenantSigs(covSigs []*types.CovenantSigs) (
 			SlashingUnbondingTxSigs: covSig.SlashingUnbondingSigs,
 		})
 	}
-	// res, err := bc.reliablySendMsgs(msgs)
-	// if err != nil {
-	// 	return nil, err
-	// }
-	res, err := bc.reliablySendMsgsAsMultipleTxs(msgs)
-	if err != nil {
-		return nil, err
-	}
-
-	if res == nil {
-		return &types.TxResponse{}, nil
-	}
-
-	return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil
+	return bc.SendMsgs(msgs)
 }
 
 func (bc *BabylonController) QueryPendingDelegations(limit uint64, filter FilterFn) ([]*types.Delegation, error) {
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index d16454c..2baafa6 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -57,6 +57,11 @@ var (
 // callbackTx is the expected type that waits for the inclusion of a transaction on the chain to be called
 type callbackTx func(*sdk.TxResponse, error)
 
+type failedMsg struct {
+	msg    sdk.Msg
+	reason error
+}
+
 // reliablySendEachMsgAsTx creates multiple
 func reliablySendEachMsgAsTx(
 	cfg *config.BabylonConfig,
@@ -65,7 +70,7 @@ func reliablySendEachMsgAsTx(
 	cometClient client.CometRPC,
 	encCfg *appparams.EncodingConfig,
 	covAcc sdk.AccountI,
-) (txResponses []*sdk.TxResponse, failedMsgs []*sdk.Msg, err error) {
+) (txResponses []*sdk.TxResponse, failedMsgs []*failedMsg, err error) {
 	rpcClient, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
 	if err != nil {
 		return nil, nil, err
@@ -77,7 +82,7 @@ func reliablySendEachMsgAsTx(
 	// create outputs at msg len capacity to handle each msg in parallel
 	// as it is easier than pass 2 channels for each func
 	txResponses = make([]*sdk.TxResponse, msgLen)
-	failedMsgs = make([]*sdk.Msg, msgLen)
+	failedMsgs = make([]*failedMsg, msgLen)
 
 	var wg sync.WaitGroup
 
@@ -792,13 +797,16 @@ func reliablySendEachMsgAsTxCallback(
 	msg sdk.Msg,
 	msgIndex int,
 	txResponses []*sdk.TxResponse,
-	failedMsgs []*sdk.Msg,
+	failedMsgs []*failedMsg,
 ) callbackTx {
 	return func(txResp *sdk.TxResponse, err error) {
 		defer wg.Done()
 
 		if err != nil {
-			failedMsgs[msgIndex] = &msg
+			failedMsgs[msgIndex] = &failedMsg{
+				msg:    msg,
+				reason: err,
+			}
 
 			if ErrorContained(err, expectedErrors) {
 				log.Debug(
diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go
index 53e0e8d..d8b6376 100644
--- a/clientcontroller/interface.go
+++ b/clientcontroller/interface.go
@@ -20,7 +20,7 @@ type (
 		// SubmitCovenantSigs submits Covenant signatures to the consumer chain, each corresponding to
 		// a finality provider that the delegation is (re-)staked to
 		// it returns tx hash and error
-		SubmitCovenantSigs(covSigMsgs []*types.CovenantSigs) (*types.TxResponse, error)
+		SubmitCovenantSigs(covSigMsgs []*types.CovenantSigs) ([]*types.TxResponse, error)
 
 		// QueryPendingDelegations queries BTC delegations that are in status of pending
 		QueryPendingDelegations(limit uint64, filter FilterFn) ([]*types.Delegation, error)
diff --git a/covenant/covenant.go b/covenant/covenant.go
index f97ec09..b5525dd 100644
--- a/covenant/covenant.go
+++ b/covenant/covenant.go
@@ -83,7 +83,7 @@ func (ce *CovenantEmulator) PublicKeyStr() string {
 // AddCovenantSignatures adds Covenant signatures on every given Bitcoin delegations and submits them
 // in a batch to Babylon. Invalid delegations will be skipped with error log error will be returned if
 // the batch submission fails
-func (ce *CovenantEmulator) AddCovenantSignatures(btcDels []*types.Delegation) (*types.TxResponse, error) {
+func (ce *CovenantEmulator) AddCovenantSignatures(btcDels []*types.Delegation) ([]*types.TxResponse, error) {
 	if len(btcDels) == 0 {
 		return nil, fmt.Errorf("no delegations")
 	}
@@ -511,8 +511,10 @@ func (ce *CovenantEmulator) covenantSigSubmissionLoop() {
 	limit := ce.config.DelegationLimit
 	covenantSigTicker := time.NewTicker(interval)
 
-	ce.logger.Info("starting signature submission loop",
-		zap.Float64("interval seconds", interval.Seconds()))
+	ce.logger.Info(
+		"starting signature submission loop",
+		zap.Float64("interval seconds", interval.Seconds()),
+	)
 
 	for {
 		select {
diff --git a/covenant/covenant_test.go b/covenant/covenant_test.go
index fbb449c..0577a42 100644
--- a/covenant/covenant_test.go
+++ b/covenant/covenant_test.go
@@ -254,10 +254,10 @@ func FuzzAddCovenantSig(f *testing.F) {
 		// check the sigs are expected
 		expectedTxHash := testutil.GenRandomHexStr(r, 32)
 		mockClientController.EXPECT().SubmitCovenantSigs(covSigsSet).
-			Return(&types.TxResponse{TxHash: expectedTxHash}, nil).AnyTimes()
+			Return([]*types.TxResponse{&types.TxResponse{TxHash: expectedTxHash}}, nil).AnyTimes()
 		res, err := ce.AddCovenantSignatures(btcDels)
 		require.NoError(t, err)
-		require.Equal(t, expectedTxHash, res.TxHash)
+		require.Equal(t, expectedTxHash, res[0].TxHash)
 	})
 }
 
diff --git a/testutil/mocks/babylon.go b/testutil/mocks/babylon.go
index 1644332..e8cb61a 100644
--- a/testutil/mocks/babylon.go
+++ b/testutil/mocks/babylon.go
@@ -80,10 +80,10 @@ func (mr *MockClientControllerMockRecorder) QueryStakingParamsByVersion(version
 }
 
 // SubmitCovenantSigs mocks base method.
-func (m *MockClientController) SubmitCovenantSigs(covSigMsgs []*types.CovenantSigs) (*types.TxResponse, error) {
+func (m *MockClientController) SubmitCovenantSigs(covSigMsgs []*types.CovenantSigs) ([]*types.TxResponse, error) {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "SubmitCovenantSigs", covSigMsgs)
-	ret0, _ := ret[0].(*types.TxResponse)
+	ret0, _ := ret[0].([]*types.TxResponse)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }

From df8759b225237e81c4f1b0e944ac9e479a6cbbfb Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 14:55:48 -0300
Subject: [PATCH 23/31] test: modified to use multiple txs for checking

---
 clientcontroller/babylon.go | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index d62c4c7..8e01d03 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -2,7 +2,6 @@ package clientcontroller
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 	"time"
@@ -159,21 +158,22 @@ func (bc *BabylonController) reliablySendMsg(msg sdk.Msg) (*provider.RelayerTxRe
 // SendMsgs first it tries to send all the messages in a single transaction
 // if it fails, sends each message in a different transaction.
 func (bc *BabylonController) SendMsgs(msgs []sdk.Msg) ([]*types.TxResponse, error) {
-	resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
-	if errSingleTx != nil {
-		// failed to send as a batch tx
-		resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
-		if errMultipleTx != nil {
-			return nil, errors.Join(errSingleTx, errMultipleTx)
-		}
-
-		return convertTxResp(resMultipleTxs...), nil
-	}
-
-	if resSingleTx == nil { // some expected error happened
-		return []*types.TxResponse{}, nil
-	}
-	return convertTxResp(resSingleTx), nil
+	// resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
+	// if errSingleTx != nil {
+	// failed to send as a batch tx
+	resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
+	if errMultipleTx != nil {
+		// return nil, errors.Join(errSingleTx, errMultipleTx)
+		return nil, errMultipleTx
+	}
+
+	return convertTxResp(resMultipleTxs...), nil
+	// }
+
+	// if resSingleTx == nil { // some expected error happened
+	// 	return []*types.TxResponse{}, nil
+	// }
+	// return convertTxResp(resSingleTx), nil
 }
 
 func convertTxResp(txs ...*provider.RelayerTxResponse) []*types.TxResponse {

From 5994bc1f889d4583f594abbc45c96a2cc179be4f Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 15:11:15 -0300
Subject: [PATCH 24/31] chore: rollback to use batch first

---
 clientcontroller/babylon.go | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index 8e01d03..d62c4c7 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -2,6 +2,7 @@ package clientcontroller
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"math"
 	"time"
@@ -158,22 +159,21 @@ func (bc *BabylonController) reliablySendMsg(msg sdk.Msg) (*provider.RelayerTxRe
 // SendMsgs first it tries to send all the messages in a single transaction
 // if it fails, sends each message in a different transaction.
 func (bc *BabylonController) SendMsgs(msgs []sdk.Msg) ([]*types.TxResponse, error) {
-	// resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
-	// if errSingleTx != nil {
-	// failed to send as a batch tx
-	resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
-	if errMultipleTx != nil {
-		// return nil, errors.Join(errSingleTx, errMultipleTx)
-		return nil, errMultipleTx
-	}
-
-	return convertTxResp(resMultipleTxs...), nil
-	// }
-
-	// if resSingleTx == nil { // some expected error happened
-	// 	return []*types.TxResponse{}, nil
-	// }
-	// return convertTxResp(resSingleTx), nil
+	resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
+	if errSingleTx != nil {
+		// failed to send as a batch tx
+		resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
+		if errMultipleTx != nil {
+			return nil, errors.Join(errSingleTx, errMultipleTx)
+		}
+
+		return convertTxResp(resMultipleTxs...), nil
+	}
+
+	if resSingleTx == nil { // some expected error happened
+		return []*types.TxResponse{}, nil
+	}
+	return convertTxResp(resSingleTx), nil
 }
 
 func convertTxResp(txs ...*provider.RelayerTxResponse) []*types.TxResponse {

From 2114a6e62a739571431f8d5ba9a1b2dacf9a2e9b Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 21 Jan 2025 15:16:27 -0300
Subject: [PATCH 25/31] chore: increase exec time

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 35ef6ab..33e11ea 100644
--- a/Makefile
+++ b/Makefile
@@ -68,7 +68,7 @@ test-e2e-cov-emu-life:
 
 test-e2e-cov-pending-del:
 	cd $(TOOLS_DIR); go install -trimpath $(BABYLON_PKG)
-	go test -run TestQueryPendingDelegations -mod=readonly -timeout=5m -v $(PACKAGES_E2E) --tags=e2e
+	go test -run TestQueryPendingDelegations -mod=readonly -timeout=7m -v $(PACKAGES_E2E) --tags=e2e
 
 mock-gen:
 	mkdir -p $(MOCKS_DIR)

From 9a9453b55854b46974431c6ff4ed141805887101 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Wed, 29 Jan 2025 11:04:24 -0300
Subject: [PATCH 26/31] chore: small refactor, need to have more public funcs
 in babylonclient

---
 clientcontroller/babylon.go         |   2 +-
 clientcontroller/babylon_msg.go     | 178 ++++++----------------------
 clientcontroller/babylon_msg_log.go |  16 +--
 3 files changed, 42 insertions(+), 154 deletions(-)

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index 71c81cb..a6f2b68 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -228,7 +228,7 @@ func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) ([]*b
 			return err
 		}
 
-		txResponses, failedMsgs, err = reliablySendEachMsgAsTx(cfg, msgs, log, bc.bbnClient.RPCClient, encCfg, covAcc)
+		txResponses, failedMsgs, err = reliablySendEachMsgAsTx(cfg, bc.bbnClient.Provider(), msgs, log, encCfg, covAcc)
 		return err
 	})
 	if errAccKey != nil {
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 2baafa6..9bb63b3 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -16,12 +16,12 @@ import (
 	"cosmossdk.io/store/rootmulti"
 	"github.com/avast/retry-go/v4"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
+	"github.com/babylonlabs-io/babylon/client/babylonclient"
 	"github.com/babylonlabs-io/babylon/client/config"
 	abci "github.com/cometbft/cometbft/abci/types"
-	"github.com/cometbft/cometbft/crypto/merkle"
-	"github.com/cometbft/cometbft/libs/bytes"
+	rpcclient "github.com/cometbft/cometbft/rpc/client"
+	"github.com/cometbft/cometbft/rpc/client/http"
 	coretypes "github.com/cometbft/cometbft/rpc/core/types"
-	tmtypes "github.com/cometbft/cometbft/types"
 	"github.com/cosmos/cosmos-sdk/client"
 	"github.com/cosmos/cosmos-sdk/client/tx"
 	"github.com/cosmos/cosmos-sdk/codec"
@@ -31,12 +31,8 @@ import (
 	legacyerrors "github.com/cosmos/cosmos-sdk/types/errors"
 	txtypes "github.com/cosmos/cosmos-sdk/types/tx"
 	"github.com/cosmos/cosmos-sdk/types/tx/signing"
-	"github.com/cosmos/relayer/v2/relayer/chains/cosmos"
-	"github.com/cosmos/relayer/v2/relayer/provider"
 	"github.com/juju/fslock"
-	abcistrange "github.com/strangelove-ventures/cometbft-client/abci/types"
-	strangeloveclient "github.com/strangelove-ventures/cometbft-client/client"
-	rpcclient "github.com/strangelove-ventures/cometbft-client/rpc/client"
+
 	"go.uber.org/zap"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
@@ -65,16 +61,17 @@ type failedMsg struct {
 // reliablySendEachMsgAsTx creates multiple
 func reliablySendEachMsgAsTx(
 	cfg *config.BabylonConfig,
+	cp *babylonclient.CosmosProvider,
 	msgs []sdk.Msg,
 	log *zap.Logger,
-	cometClient client.CometRPC,
 	encCfg *appparams.EncodingConfig,
 	covAcc sdk.AccountI,
 ) (txResponses []*sdk.TxResponse, failedMsgs []*failedMsg, err error) {
-	rpcClient, err := strangeloveclient.NewClient(cfg.RPCAddr, cfg.Timeout)
+	c, err := http.NewWithTimeout(cfg.RPCAddr, "/websocket", uint(cfg.Timeout.Seconds()))
 	if err != nil {
 		return nil, nil, err
 	}
+	rpcClient := babylonclient.NewRPCClient(c)
 
 	ctx := context.Background()
 
@@ -97,9 +94,9 @@ func reliablySendEachMsgAsTx(
 		go func(
 			ctx context.Context,
 			cfg *config.BabylonConfig,
+			cp *babylonclient.CosmosProvider,
 			log *zap.Logger,
-			cometClient client.CometRPC,
-			rpcClient *strangeloveclient.Client,
+			rpcClient *babylonclient.RPCClient,
 			encCfg *appparams.EncodingConfig,
 			msg sdk.Msg,
 			accSequence, accNumber uint64,
@@ -107,7 +104,7 @@ func reliablySendEachMsgAsTx(
 
 			msgIndex int,
 		) {
-			err := RetrySendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, []sdk.Msg{msg}, accSequence, accNumber, callback)
+			err := RetrySendMessagesToMempool(ctx, cfg, cp, log, rpcClient, encCfg, []sdk.Msg{msg}, accSequence, accNumber, callback)
 			if err != nil {
 				if ErrorContained(err, expectedErrors) {
 					log.Error("expected err when submitting the tx, skip retrying", zap.Error(err))
@@ -117,7 +114,7 @@ func reliablySendEachMsgAsTx(
 				// If the callback was not invoked, decrement the wait group here
 				wg.Done()
 			}
-		}(ctx, cfg, log, cometClient, rpcClient, encCfg, msg, accSequence, accNumber, callback, msgIndex)
+		}(ctx, cfg, cp, log, &rpcClient, encCfg, msg, accSequence, accNumber, callback, msgIndex)
 
 		accSequence++
 	}
@@ -130,9 +127,9 @@ func reliablySendEachMsgAsTx(
 func RetrySendMessagesToMempool(
 	ctx context.Context,
 	cfg *config.BabylonConfig,
+	cp *babylonclient.CosmosProvider,
 	log *zap.Logger,
-	cometClient client.CometRPC,
-	rpcClient *strangeloveclient.Client,
+	rpcClient *babylonclient.RPCClient,
 	encCfg *appparams.EncodingConfig,
 
 	msgs []sdk.Msg,
@@ -142,7 +139,7 @@ func RetrySendMessagesToMempool(
 	asyncCallbacks ...callbackTx,
 ) error {
 	return retry.Do(func() error {
-		sendMsgErr := SendMessagesToMempool(ctx, cfg, log, cometClient, rpcClient, encCfg, msgs, accSequence, accNumber, asyncCallbacks...)
+		sendMsgErr := SendMessagesToMempool(ctx, cfg, cp, log, rpcClient, encCfg, msgs, accSequence, accNumber, asyncCallbacks...)
 		if sendMsgErr != nil {
 			if ErrorContained(sendMsgErr, unrecoverableErrors) {
 				log.Error("unrecoverable err when submitting the tx, skip retrying", zap.Error(sendMsgErr))
@@ -163,9 +160,9 @@ func RetrySendMessagesToMempool(
 func SendMessagesToMempool(
 	ctx context.Context,
 	cfg *config.BabylonConfig,
+	cp *babylonclient.CosmosProvider,
 	logger *zap.Logger,
-	cometClient client.CometRPC,
-	rpcClient *strangeloveclient.Client,
+	rpcClient *babylonclient.RPCClient,
 	encCfg *appparams.EncodingConfig,
 
 	msgs []sdk.Msg,
@@ -174,17 +171,14 @@ func SendMessagesToMempool(
 
 	asyncCallbacks ...callbackTx,
 ) error {
-	txSignerKey := cfg.Key
 	memo, gas := "", uint64(0)
 
-	txBytes, fees, err := BuildMessages(
-		ctx, cfg, cometClient, rpcClient, encCfg, msgs, memo, gas, txSignerKey, accSequence, accNumber,
-	)
+	txBytes, _, err := BuildMessages(ctx, cfg, cp, encCfg, msgs, accSequence, accNumber, memo, gas)
 	if err != nil {
 		return err
 	}
 
-	err = BroadcastTx(ctx, logger, cfg, encCfg, rpcClient, txBytes, msgs, fees, ctx, defaultBroadcastWaitTimeout, asyncCallbacks)
+	err = BroadcastTx(ctx, logger, cfg, encCfg, rpcClient, txBytes, msgs, ctx, defaultBroadcastWaitTimeout, asyncCallbacks)
 	if err != nil {
 		return err
 	}
@@ -195,19 +189,19 @@ func SendMessagesToMempool(
 func BuildMessages(
 	ctx context.Context,
 	cfg *config.BabylonConfig,
-	cometClient client.CometRPC,
-	rpcClient *strangeloveclient.Client,
+	cp *babylonclient.CosmosProvider,
 	encCfg *appparams.EncodingConfig,
 	msgs []sdk.Msg,
+	accSequence, accNumber uint64,
+	// optional
 	memo string,
 	gas uint64,
-	txSignerKey string,
-	accSequence, accNumber uint64,
 ) (
 	txBytes []byte,
 	fees sdk.Coins,
 	err error,
 ) {
+	txSignerKey := cfg.Key
 	keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
 	if err != nil {
 		return nil, sdk.Coins{}, err
@@ -223,8 +217,7 @@ func BuildMessages(
 
 	adjusted := gas
 	if gas == 0 {
-		_, adjusted, err = CalculateGas(ctx, rpcClient, keybase, txf, txSignerKey, cfg.GasAdjustment, msgs...)
-
+		_, adjusted, err = cp.CalculateGas(ctx, txf, txSignerKey, msgs...)
 		if err != nil {
 			return nil, sdk.Coins{}, err
 		}
@@ -264,10 +257,9 @@ func BroadcastTx(
 	cfg *config.BabylonConfig,
 	encCfg *appparams.EncodingConfig,
 
-	rpcClient *strangeloveclient.Client,
+	rpcClient *babylonclient.RPCClient,
 	tx []byte, // raw tx to be broadcasted
 	msgs []sdk.Msg, // used for logging only
-	fees sdk.Coins, // used for metrics
 
 	asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast
 	asyncTimeout time.Duration, // timeout for waiting for block inclusion
@@ -282,7 +274,7 @@ func BroadcastTx(
 			// ResultBroadcastTx will be nil.
 			return err
 		}
-		rlyResp := &provider.RelayerTxResponse{
+		rlyResp := &babylonclient.RelayerTxResponse{
 			TxHash:    res.Hash.String(),
 			Codespace: res.Codespace,
 			Code:      res.Code,
@@ -306,65 +298,12 @@ func BroadcastTx(
 	return nil
 }
 
-// CalculateGas simulates a tx to generate the appropriate gas settings before broadcasting a tx.
-func CalculateGas(
-	ctx context.Context,
-	rpcClient *strangeloveclient.Client,
-	keybase keyring.Keyring,
-	txf tx.Factory,
-	signingKey string,
-	gasAdjustment float64,
-	msgs ...sdk.Msg,
-) (txtypes.SimulateResponse, uint64, error) {
-	keyInfo, err := keybase.Key(signingKey)
-	if err != nil {
-		return txtypes.SimulateResponse{}, 0, err
-	}
-
-	var txBytes []byte
-	if err := retry.Do(func() error {
-		var err error
-		txBytes, err = BuildSimTx(keyInfo, txf, msgs...)
-		if err != nil {
-			return err
-		}
-		return nil
-	}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr); err != nil {
-		return txtypes.SimulateResponse{}, 0, err
-	}
-
-	simQuery := abci.RequestQuery{
-		Path: "/cosmos.tx.v1beta1.Service/Simulate",
-		Data: txBytes,
-	}
-
-	var res abcistrange.ResponseQuery
-	if err := retry.Do(func() error {
-		var err error
-		res, err = QueryABCI(ctx, rpcClient, simQuery)
-		if err != nil {
-			return err
-		}
-		return nil
-	}, retry.Context(ctx), rtyAtt, rtyDel, rtyErr); err != nil {
-		return txtypes.SimulateResponse{}, 0, err
-	}
-
-	var simRes txtypes.SimulateResponse
-	if err := simRes.Unmarshal(res.Value); err != nil {
-		return txtypes.SimulateResponse{}, 0, err
-	}
-
-	gas, err := AdjustEstimatedGas(gasAdjustment, simRes.GasInfo.GasUsed)
-	return simRes, gas, err
-}
-
 // waitForTx waits for a transaction to be included in a block, logs success/fail, then invokes callback.
 // This is intended to be called as an async goroutine.
 func waitForTx(
 	ctx context.Context,
 	log *zap.Logger,
-	rpcClient *strangeloveclient.Client,
+	rpcClient *babylonclient.RPCClient,
 	cdc *codec.ProtoCodec,
 	txConfig client.TxConfig,
 	chainId string,
@@ -385,7 +324,7 @@ func waitForTx(
 		return
 	}
 
-	rlyResp := &provider.RelayerTxResponse{
+	rlyResp := &babylonclient.RelayerTxResponse{
 		Height:    res.Height,
 		TxHash:    res.TxHash,
 		Codespace: res.Codespace,
@@ -426,7 +365,7 @@ func waitForTx(
 // waitForBlockInclusion will wait for a transaction to be included in a block, up to waitTimeout or context cancellation.
 func waitForBlockInclusion(
 	ctx context.Context,
-	rpcClient *strangeloveclient.Client,
+	rpcClient *babylonclient.RPCClient,
 	txConfig client.TxConfig,
 	txHash []byte,
 	waitTimeout time.Duration,
@@ -435,12 +374,12 @@ func waitForBlockInclusion(
 	for {
 		select {
 		case <-exitAfter:
-			return nil, fmt.Errorf("timed out after: %d; %w", waitTimeout, cosmos.ErrTimeoutAfterWaitingForTxBroadcast)
+			return nil, fmt.Errorf("timed out after: %d; %w", waitTimeout, babylonclient.ErrTimeoutAfterWaitingForTxBroadcast)
 		// This fixed poll is fine because it's only for logging and updating prometheus metrics currently.
 		case <-time.After(time.Millisecond * 100):
 			res, err := rpcClient.Tx(ctx, txHash, false)
 			if err == nil {
-				return mkTxResult(convertResultTx(res), txConfig)
+				return mkTxResult(res, txConfig)
 			}
 			if strings.Contains(err.Error(), "transaction indexing is disabled") {
 				return nil, fmt.Errorf("cannot determine success/failure of tx because transaction indexing is disabled on rpc url")
@@ -451,57 +390,6 @@ func waitForBlockInclusion(
 	}
 }
 
-func convertResultTx(res *strangeloveclient.TxResponse) *coretypes.ResultTx {
-	return &coretypes.ResultTx{
-		Hash:   bytes.HexBytes(res.Hash),
-		Height: res.Height,
-		Index:  res.Index,
-		TxResult: abci.ExecTxResult{
-			Code:      res.ExecTx.Code,
-			Data:      res.ExecTx.Data,
-			Log:       res.ExecTx.Log,
-			Info:      res.ExecTx.Info,
-			GasWanted: res.ExecTx.GasWanted,
-			GasUsed:   res.ExecTx.GasUsed,
-			Events:    converStringEvents(res.ExecTx.Events),
-			Codespace: res.ExecTx.Codespace,
-		},
-		Tx: tmtypes.Tx(res.Tx),
-		Proof: tmtypes.TxProof{
-			RootHash: bytes.HexBytes(res.Proof.RootHash),
-			Data:     tmtypes.Tx(res.Proof.Data),
-			Proof: merkle.Proof{
-				Total:    res.Proof.Proof.Total,
-				Index:    res.Proof.Proof.Index,
-				LeafHash: res.Proof.Proof.LeafHash,
-				Aunts:    res.Proof.Proof.Aunts,
-			},
-		},
-	}
-}
-
-func converStringEvents(events sdk.StringEvents) []abci.Event {
-	evts := make([]abci.Event, len(events))
-
-	for i, evt := range events {
-		attributes := make([]abci.EventAttribute, len(evt.Attributes))
-
-		for j, attr := range evt.Attributes {
-			attributes[j] = abci.EventAttribute{
-				Key:   attr.Key,
-				Value: attr.Value,
-			}
-		}
-
-		evts[i] = abci.Event{
-			Type:       evt.Type,
-			Attributes: attributes,
-		}
-	}
-
-	return evts
-}
-
 // mkTxResult decodes a comet transaction into an SDK TxResponse.
 func mkTxResult(
 	resTx *coretypes.ResultTx,
@@ -542,7 +430,7 @@ func AccessKeyWithLock(keyDir string, accessFunc func() error) error {
 }
 
 // QueryABCI performs an ABCI query and returns the appropriate response and error sdk error code.
-func QueryABCI(ctx context.Context, rpcClient *strangeloveclient.Client, req abci.RequestQuery) (abcistrange.ResponseQuery, error) {
+func QueryABCI(ctx context.Context, rpcClient *babylonclient.RPCClient, req abci.RequestQuery) (abci.ResponseQuery, error) {
 	opts := rpcclient.ABCIQueryOptions{
 		Height: req.Height,
 		Prove:  req.Prove,
@@ -550,11 +438,11 @@ func QueryABCI(ctx context.Context, rpcClient *strangeloveclient.Client, req abc
 
 	result, err := rpcClient.ABCIQueryWithOptions(ctx, req.Path, req.Data, opts)
 	if err != nil {
-		return abcistrange.ResponseQuery{}, err
+		return abci.ResponseQuery{}, err
 	}
 
 	if !result.Response.IsOK() {
-		return abcistrange.ResponseQuery{}, sdkErrorToGRPCError(result.Response.Code, result.Response.Log)
+		return abci.ResponseQuery{}, sdkErrorToGRPCError(result.Response.Code, result.Response.Log)
 	}
 
 	// data from trusted node or subspace query doesn't need verification
diff --git a/clientcontroller/babylon_msg_log.go b/clientcontroller/babylon_msg_log.go
index 1d197f9..c711050 100644
--- a/clientcontroller/babylon_msg_log.go
+++ b/clientcontroller/babylon_msg_log.go
@@ -4,6 +4,7 @@ import (
 	"errors"
 	"reflect"
 
+	"github.com/babylonlabs-io/babylon/client/babylonclient"
 	"github.com/cosmos/cosmos-sdk/codec"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	typestx "github.com/cosmos/cosmos-sdk/types/tx"
@@ -11,13 +12,12 @@ import (
 	transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
 	clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
 	chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
-	"github.com/cosmos/relayer/v2/relayer/provider"
 	"go.uber.org/zap"
 	"go.uber.org/zap/zapcore"
 )
 
 // LogFailedTx takes the transaction and the messages to create it and logs the appropriate data
-func LogFailedTx(log *zap.Logger, chainId string, res *provider.RelayerTxResponse, err error, msgs []sdk.Msg) {
+func LogFailedTx(log *zap.Logger, chainId string, res *babylonclient.RelayerTxResponse, err error, msgs []sdk.Msg) {
 	// Include the chain_id
 	fields := []zapcore.Field{zap.String("chain_id", chainId)}
 
@@ -51,7 +51,7 @@ func LogFailedTx(log *zap.Logger, chainId string, res *provider.RelayerTxRespons
 		if sdkErr := sdkError(res.Codespace, res.Code); err != nil {
 			fields = append(fields, zap.NamedError("sdk_error", sdkErr))
 		}
-		fields = append(fields, zap.Object("response", res))
+		fields = append(fields, zap.Any("response", res))
 		log.Warn(
 			"Sent transaction but received failure response",
 			fields...,
@@ -105,7 +105,7 @@ func LogSuccessTx(log *zap.Logger, chainId string, cdc *codec.ProtoCodec, res *s
 }
 
 // getChannelsIfPresent scans the events for channel tags
-func getChannelsIfPresent(events []provider.RelayerEvent) []zapcore.Field {
+func getChannelsIfPresent(events []babylonclient.RelayerEvent) []zapcore.Field {
 	channelTags := []string{srcChanTag, dstChanTag}
 	fields := []zap.Field{}
 
@@ -182,8 +182,8 @@ func getFeePayer(log *zap.Logger, cdc *codec.ProtoCodec, tx *typestx.Tx) string
 	}
 }
 
-func parseEventsFromTxResponse(resp *sdk.TxResponse) []provider.RelayerEvent {
-	var events []provider.RelayerEvent
+func parseEventsFromTxResponse(resp *sdk.TxResponse) []babylonclient.RelayerEvent {
+	var events []babylonclient.RelayerEvent
 
 	if resp == nil {
 		return events
@@ -195,7 +195,7 @@ func parseEventsFromTxResponse(resp *sdk.TxResponse) []provider.RelayerEvent {
 			for _, attribute := range event.Attributes {
 				attributes[attribute.Key] = attribute.Value
 			}
-			events = append(events, provider.RelayerEvent{
+			events = append(events, babylonclient.RelayerEvent{
 				EventType:  event.Type,
 				Attributes: attributes,
 			})
@@ -210,7 +210,7 @@ func parseEventsFromTxResponse(resp *sdk.TxResponse) []provider.RelayerEvent {
 			for _, attribute := range event.Attributes {
 				attributes[attribute.Key] = attribute.Value
 			}
-			events = append(events, provider.RelayerEvent{
+			events = append(events, babylonclient.RelayerEvent{
 				EventType:  event.Type,
 				Attributes: attributes,
 			})

From efb3b43e82a87803c05bec4f12b6e2038d8a94d5 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 18 Feb 2025 16:00:01 -0300
Subject: [PATCH 27/31] chore: bump babylon to v1.0.0-rc.6

---
 go.mod                |  57 +++++++++----------
 go.sum                | 124 +++++++++++++++++++++++++-----------------
 itest/test_manager.go |   4 +-
 3 files changed, 104 insertions(+), 81 deletions(-)

diff --git a/go.mod b/go.mod
index 17151bf..5ec36ac 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,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 v1.0.0-rc.4
+	github.com/babylonlabs-io/babylon v1.0.0-rc.6
 	github.com/btcsuite/btcd v0.24.2
 	github.com/btcsuite/btcd/btcec/v2 v2.3.4
 	github.com/btcsuite/btcd/btcutil v1.1.6
@@ -26,23 +26,28 @@ require (
 	github.com/ory/dockertest/v3 v3.10.0
 	github.com/prometheus/client_golang v1.20.5
 	github.com/spf13/viper v1.19.0
-	github.com/stretchr/testify v1.9.0
+	github.com/stretchr/testify v1.10.0
 	github.com/urfave/cli v1.22.14
 	go.uber.org/zap v1.26.0
-	golang.org/x/crypto v0.28.0 // indirect
-	golang.org/x/sync v0.8.0 // indirect
+	golang.org/x/crypto v0.32.0 // indirect
+	golang.org/x/sync v0.10.0 // indirect
 )
 
 require (
+	cosmossdk.io/store v1.1.1
+	github.com/cometbft/cometbft v0.38.17
+	github.com/cosmos/ibc-go/v8 v8.4.0
 	github.com/go-chi/chi/v5 v5.0.12
 	github.com/google/uuid v1.6.0
+	github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b
 	github.com/rs/zerolog v1.33.0
 	github.com/spf13/cobra v1.8.1
+	google.golang.org/grpc v1.70.0
 )
 
 require (
 	cloud.google.com/go v0.112.1 // indirect
-	cloud.google.com/go/compute/metadata v0.5.0 // indirect
+	cloud.google.com/go/compute/metadata v0.5.2 // indirect
 	cloud.google.com/go/iam v1.1.6 // indirect
 	cloud.google.com/go/storage v1.38.0 // indirect
 	cosmossdk.io/api v0.7.6 // indirect
@@ -51,7 +56,6 @@ require (
 	cosmossdk.io/core v0.11.1 // indirect
 	cosmossdk.io/depinject v1.1.0 // indirect
 	cosmossdk.io/log v1.4.1 // indirect
-	cosmossdk.io/store v1.1.1 // indirect
 	cosmossdk.io/x/circuit v0.1.1 // indirect
 	cosmossdk.io/x/evidence v0.1.1 // indirect
 	cosmossdk.io/x/feegrant v0.1.1 // indirect
@@ -63,8 +67,8 @@ require (
 	github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
 	github.com/99designs/keyring v1.2.1 // indirect
 	github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
-	github.com/CosmWasm/wasmd v0.53.0 // indirect
-	github.com/CosmWasm/wasmvm/v2 v2.1.3 // indirect
+	github.com/CosmWasm/wasmd v0.53.2 // indirect
+	github.com/CosmWasm/wasmvm/v2 v2.1.5 // indirect
 	github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
 	github.com/DataDog/zstd v1.5.5 // indirect
 	github.com/Microsoft/go-winio v0.6.1 // indirect
@@ -87,7 +91,6 @@ require (
 	github.com/cockroachdb/pebble v1.1.2 // indirect
 	github.com/cockroachdb/redact v1.1.5 // indirect
 	github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
-	github.com/cometbft/cometbft v0.38.15 // indirect
 	github.com/cometbft/cometbft-db v0.15.0 // indirect
 	github.com/containerd/continuity v0.3.0 // indirect
 	github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
@@ -100,7 +103,6 @@ require (
 	github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0f8bd // indirect
 	github.com/cosmos/ibc-go/modules/capability v1.0.1 // indirect
 	github.com/cosmos/ibc-go/modules/light-clients/08-wasm v0.0.0-20240429153234-e1e6da7e4ead // indirect
-	github.com/cosmos/ibc-go/v8 v8.4.0 // indirect
 	github.com/cosmos/ics23/go v0.11.0 // indirect
 	github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
@@ -125,7 +127,7 @@ require (
 	github.com/go-kit/kit v0.13.0 // indirect
 	github.com/go-kit/log v0.2.1 // indirect
 	github.com/go-logfmt/logfmt v0.6.0 // indirect
-	github.com/go-logr/logr v1.4.1 // indirect
+	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
 	github.com/gogo/googleapis v1.4.1 // indirect
@@ -166,7 +168,6 @@ require (
 	github.com/jinzhu/copier v0.3.5 // indirect
 	github.com/jmespath/go-jmespath v0.4.0 // indirect
 	github.com/jmhodges/levigo v1.0.0 // indirect
-	github.com/juju/fslock v0.0.0-20160525022230-4d5c94c67b4b // indirect
 	github.com/kkdai/bstream v1.0.0 // indirect
 	github.com/kr/pretty v0.3.1 // indirect
 	github.com/kr/text v0.2.0 // indirect
@@ -193,7 +194,7 @@ require (
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/prometheus/client_model v0.6.1 // indirect
-	github.com/prometheus/common v0.60.1 // indirect
+	github.com/prometheus/common v0.62.0 // indirect
 	github.com/prometheus/procfs v0.15.1 // indirect
 	github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
 	github.com/rogpeppe/go-internal v1.12.0 // indirect
@@ -215,6 +216,7 @@ require (
 	github.com/tendermint/go-amino v0.16.0 // indirect
 	github.com/tidwall/btree v1.7.0 // indirect
 	github.com/ulikunitz/xz v0.5.11 // indirect
+	github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3 // indirect
 	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
@@ -224,25 +226,24 @@ require (
 	go.opencensus.io v0.24.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect
-	go.opentelemetry.io/otel v1.24.0 // indirect
-	go.opentelemetry.io/otel/metric v1.24.0 // indirect
-	go.opentelemetry.io/otel/trace v1.24.0 // indirect
+	go.opentelemetry.io/otel v1.32.0 // indirect
+	go.opentelemetry.io/otel/metric v1.32.0 // indirect
+	go.opentelemetry.io/otel/trace v1.32.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
-	golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect
-	golang.org/x/mod v0.17.0 // indirect
-	golang.org/x/net v0.30.0 // indirect
-	golang.org/x/oauth2 v0.23.0 // indirect
-	golang.org/x/sys v0.26.0 // indirect
-	golang.org/x/term v0.25.0 // indirect
-	golang.org/x/text v0.19.0 // indirect
+	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
+	golang.org/x/mod v0.19.0 // indirect
+	golang.org/x/net v0.34.0 // indirect
+	golang.org/x/oauth2 v0.24.0 // indirect
+	golang.org/x/sys v0.29.0 // indirect
+	golang.org/x/term v0.28.0 // indirect
+	golang.org/x/text v0.21.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
-	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+	golang.org/x/tools v0.23.0 // indirect
 	google.golang.org/api v0.171.0 // indirect
 	google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f // indirect
-	google.golang.org/grpc v1.67.1 // indirect
-	google.golang.org/protobuf v1.35.1 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
+	google.golang.org/protobuf v1.36.4 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/go.sum b/go.sum
index 3a4cf02..724cd41 100644
--- a/go.sum
+++ b/go.sum
@@ -68,8 +68,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz
 cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
 cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
 cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU=
-cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
-cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
+cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
+cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
 cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I=
 cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4=
 cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0=
@@ -224,10 +224,10 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/CosmWasm/wasmd v0.53.0 h1:kdaoAi20bIb4VCsxw9pRaT2g5PpIp82Wqrr9DRVN9ao=
-github.com/CosmWasm/wasmd v0.53.0/go.mod h1:FJl/aWjdpGof3usAMFQpDe07Rkx77PUzp0cygFMOvtw=
-github.com/CosmWasm/wasmvm/v2 v2.1.3 h1:CSJTauZqkHyb9yic6JVYCjiGUgxI2MJV2QzfSu8m49c=
-github.com/CosmWasm/wasmvm/v2 v2.1.3/go.mod h1:bMhLQL4Yp9CzJi9A83aR7VO9wockOsSlZbT4ztOl6bg=
+github.com/CosmWasm/wasmd v0.53.2 h1:c3MQjeQq+r+Zj2rPeW+c9kJmTevuNnZOIkiiCP/3bg4=
+github.com/CosmWasm/wasmd v0.53.2/go.mod h1:gP10E56tuToU5rsZR7vZLBL5ssW2mie6KN/WrQLG7/I=
+github.com/CosmWasm/wasmvm/v2 v2.1.5 h1:cYI1Ook1IAA5DFA0IVvDQQboorNHZPAZ7emBBHFmXSQ=
+github.com/CosmWasm/wasmvm/v2 v2.1.5/go.mod h1:bMhLQL4Yp9CzJi9A83aR7VO9wockOsSlZbT4ztOl6bg=
 github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4=
 github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
 github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
@@ -267,8 +267,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 v1.0.0-rc.4 h1:fZNqUxyfGNwk7bJddglbDkEYsbNAB8jaaxaxRepb2Ow=
-github.com/babylonlabs-io/babylon v1.0.0-rc.4/go.mod h1:4nCZ40ZbUFMG7OkbYV91rhwSZUmjBBNc4c3RGLrtrUY=
+github.com/babylonlabs-io/babylon v1.0.0-rc.6 h1:qLgyVtLMIWeOR+lnLEXzE9rNTA+lpuuH3FIrObXviBU=
+github.com/babylonlabs-io/babylon v1.0.0-rc.6/go.mod h1:lAswl51aYhmOCgPnQOMLA5lbjgSY3l9LfxeawkkEZmY=
 github.com/babylonlabs-io/btcd/btcec/v2 v2.3.4-babylon.rc.0 h1:BVqjtFpXKYnaPMTfrWgt0sg03jZMywNzz142ZV9ck+g=
 github.com/babylonlabs-io/btcd/btcec/v2 v2.3.4-babylon.rc.0/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -362,8 +362,8 @@ github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ
 github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
 github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
 github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
-github.com/cometbft/cometbft v0.38.15 h1:5veFd8k1uXM27PBg9sMO3hAfRJ3vbh4OmmLf6cVrqXg=
-github.com/cometbft/cometbft v0.38.15/go.mod h1:+wh6ap6xctVG+JOHwbl8pPKZ0GeqdPYqISu7F4b43cQ=
+github.com/cometbft/cometbft v0.38.17 h1:FkrQNbAjiFqXydeAO81FUzriL4Bz0abYxN/eOHrQGOk=
+github.com/cometbft/cometbft v0.38.17/go.mod h1:5l0SkgeLRXi6bBfQuevXjKqML1jjfJJlvI1Ulp02/o4=
 github.com/cometbft/cometbft-db v0.15.0 h1:VLtsRt8udD4jHCyjvrsTBpgz83qne5hnL245AcPJVRk=
 github.com/cometbft/cometbft-db v0.15.0/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk=
 github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
@@ -474,6 +474,8 @@ github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
 github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
 github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9 h1:9VDpsWq096+oGMDTT/SgBD/VgZYf4pTF+KTPmZ+OaKM=
+github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
 github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
 github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
@@ -513,8 +515,8 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
 github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
 github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
-github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
+github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@@ -648,6 +650,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -741,6 +744,8 @@ github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE
 github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
 github.com/hdevalence/ed25519consensus v0.1.0 h1:jtBwzzcHuTmFrQN6xQZn6CQEO/V9f7HsjsjeEZ6auqU=
 github.com/hdevalence/ed25519consensus v0.1.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
+github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371 h1:LEw2KkKciJEr3eKDLzdZ/rjzSR6Y+BS6xKxdA78Bq6s=
+github.com/herumi/bls-eth-go-binary v0.0.0-20210130185500-57372fb27371/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U=
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
 github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
@@ -848,6 +853,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
 github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
+github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
+github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
 github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@@ -859,6 +866,8 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA=
@@ -973,8 +982,8 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2
 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
 github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s=
-github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
-github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
+github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
+github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@@ -1060,8 +1069,9 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
 github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
@@ -1070,6 +1080,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70
 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
 github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
 github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
+github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
+github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
 github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
 github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -1088,6 +1100,12 @@ github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk=
 github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA=
 github.com/vulpine-io/io-test v1.0.0 h1:Ot8vMh+ssm1VWDAwJ3U4C5qG9aRnr5YfQFZPNZBAUGI=
 github.com/vulpine-io/io-test v1.0.0/go.mod h1:X1I+p5GCxVX9m4nFd1HBtr2bVX9v1ZE6x8w+Obt36AU=
+github.com/wealdtech/go-eth2-types/v2 v2.5.2 h1:tiA6T88M6XQIbrV5Zz53l1G5HtRERcxQfmET225V4Ls=
+github.com/wealdtech/go-eth2-types/v2 v2.5.2/go.mod h1:8lkNUbgklSQ4LZ2oMSuxSdR7WwJW3L9ge1dcoCVyzws=
+github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3 h1:SxrDVSr+oXuT1x8kZt4uWqNCvv5xXEGV9zd7cuSrZS8=
+github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3/go.mod h1:qiIimacW5NhVRy8o+YxWo9YrecXqDAKKbL0+sOa0SJ4=
+github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2 h1:264/meVYWt1wFw6Mtn+xwkZkXjID42gNra4rycoiDXI=
+github.com/wealdtech/go-eth2-wallet-types/v2 v2.8.2/go.mod h1:k6kmiKWSWBTd4OxFifTEkPaBLhZspnO2KFD5XJY9nqg=
 github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -1125,14 +1143,16 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.4
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
-go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
-go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
-go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
-go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
-go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw=
-go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
-go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
-go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
+go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
+go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
+go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
+go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
+go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
+go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
+go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
+go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
+go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
+go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -1162,9 +1182,10 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
-golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
+golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
+golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1176,8 +1197,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
-golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 h1:985EYyeCOxTpcgOTJpflJUwOeEz0CQOdPt73OzpE9F8=
-golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1204,8 +1225,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
+golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1266,8 +1287,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
 golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
 golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
-golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
-golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
+golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
+golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1293,8 +1314,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri
 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
 golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
 golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A=
-golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
-golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
+golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1309,8 +1330,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
-golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1406,13 +1427,14 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
-golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
-golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
+golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
+golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1423,8 +1445,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
-golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1491,8 +1513,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
+golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1671,10 +1693,10 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz
 google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s=
 google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
 google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
-google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
-google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f h1:cUMEy+8oS78BWIH9OWazBkzbr090Od9tWBNtZHkOhf0=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a h1:OAiGFfOiA0v9MRYsSidp3ubZaBnteRUyn3xB2ZQ5G/E=
+google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@@ -1716,8 +1738,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu
 google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
 google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
 google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
-google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
-google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
+google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
+google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1734,8 +1756,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
-google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
+google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/itest/test_manager.go b/itest/test_manager.go
index 7ffd28b..1232e1b 100644
--- a/itest/test_manager.go
+++ b/itest/test_manager.go
@@ -247,7 +247,7 @@ func StartManagerWithFinalityProvider(t *testing.T, n int, shouldStartEmulator b
 func genTestFinalityProviderData(t *testing.T, babylonAddr sdk.AccAddress) *testFinalityProviderData {
 	finalityProviderEOTSPrivKey, err := btcec.NewPrivateKey()
 	require.NoError(t, err)
-	pop, err := bstypes.NewPoPBTC(babylonAddr, finalityProviderEOTSPrivKey)
+	pop, err := datagen.NewPoPBTC(babylonAddr, finalityProviderEOTSPrivKey)
 	require.NoError(t, err)
 
 	return &testFinalityProviderData{
@@ -360,7 +360,7 @@ func (tm *TestManager) InsertBTCDelegation(
 	)
 
 	// proof-of-possession
-	pop, err := bstypes.NewPoPBTC(tm.CovBBNClient.GetKeyAddress(), delBtcPrivKey)
+	pop, err := datagen.NewPoPBTC(tm.CovBBNClient.GetKeyAddress(), delBtcPrivKey)
 	require.NoError(t, err)
 
 	// create and insert BTC headers which include the staking tx to get staking tx info

From 4e48e7c82ba768788ed1b62f1d10f3f3886a479f Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 18 Feb 2025 21:53:14 -0300
Subject: [PATCH 28/31] chore: refactory send multiple msgs as tx

---
 clientcontroller/babylon.go     | 32 +++++++++---------
 clientcontroller/babylon_msg.go | 57 ++++++++++++++++++++-------------
 2 files changed, 51 insertions(+), 38 deletions(-)

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index a6f2b68..069641d 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -2,7 +2,6 @@ package clientcontroller
 
 import (
 	"context"
-	"errors"
 	"fmt"
 	"math"
 	"time"
@@ -159,21 +158,22 @@ func (bc *BabylonController) reliablySendMsg(msg sdk.Msg) (*babylonclient.Relaye
 // SendMsgs first it tries to send all the messages in a single transaction
 // if it fails, sends each message in a different transaction.
 func (bc *BabylonController) SendMsgs(msgs []sdk.Msg) ([]*types.TxResponse, error) {
-	resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
-	if errSingleTx != nil {
-		// failed to send as a batch tx
-		resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
-		if errMultipleTx != nil {
-			return nil, errors.Join(errSingleTx, errMultipleTx)
-		}
-
-		return convertTxResp(resMultipleTxs...), nil
-	}
-
-	if resSingleTx == nil { // some expected error happened
-		return []*types.TxResponse{}, nil
-	}
-	return convertTxResp(resSingleTx), nil
+	// resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
+	// if errSingleTx != nil {
+	// failed to send as a batch tx
+	resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
+	if errMultipleTx != nil {
+		// return nil, errors.Join(errSingleTx, errMultipleTx)
+		return nil, errMultipleTx
+	}
+
+	return convertTxResp(resMultipleTxs...), nil
+	// }
+
+	// if resSingleTx == nil { // some expected error happened
+	// 	return []*types.TxResponse{}, nil
+	// }
+	// return convertTxResp(resSingleTx), nil
 }
 
 func convertTxResp(txs ...*babylonclient.RelayerTxResponse) []*types.TxResponse {
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 9bb63b3..78e7ad1 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -17,6 +17,7 @@ import (
 	"github.com/avast/retry-go/v4"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
 	"github.com/babylonlabs-io/babylon/client/babylonclient"
+	bbnclient "github.com/babylonlabs-io/babylon/client/client"
 	"github.com/babylonlabs-io/babylon/client/config"
 	abci "github.com/cometbft/cometbft/abci/types"
 	rpcclient "github.com/cometbft/cometbft/rpc/client"
@@ -201,7 +202,6 @@ func BuildMessages(
 	fees sdk.Coins,
 	err error,
 ) {
-	txSignerKey := cfg.Key
 	keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
 	if err != nil {
 		return nil, sdk.Coins{}, err
@@ -215,35 +215,48 @@ func BuildMessages(
 	txf = txf.WithSequence(accSequence).
 		WithAccountNumber(accNumber)
 
-	adjusted := gas
-	if gas == 0 {
-		_, adjusted, err = cp.CalculateGas(ctx, txf, txSignerKey, msgs...)
-		if err != nil {
-			return nil, sdk.Coins{}, err
-		}
-	}
+	txSignerKey := cfg.Key
 
-	// Set the gas amount on the transaction factory
-	txf = txf.WithGas(adjusted)
+	ws := &babylonclient.WalletState{
+		NextAccountSequence: accSequence,
+		Mu:                  sync.Mutex{},
+	}
 
-	// Build the transaction builder
-	txb, err := txf.BuildUnsignedTx(msgs...)
+	relayerMsgs := bbnclient.ToProviderMsgs(msgs)
+	txBytes, _, fees, err = cp.BuildMessages(ctx, txf, relayerMsgs, memo, 0, txSignerKey, ws)
 	if err != nil {
 		return nil, sdk.Coins{}, err
 	}
 
-	if err = tx.Sign(ctx, txf, txSignerKey, txb, false); err != nil {
-		return nil, sdk.Coins{}, err
-	}
+	// adjusted := gas
+	// if gas == 0 {
+	// 	_, adjusted, err = cp.CalculateGas(ctx, txf, txSignerKey, msgs...)
+	// 	if err != nil {
+	// 		return nil, sdk.Coins{}, err
+	// 	}
+	// }
 
-	tx := txb.GetTx()
-	fees = tx.GetFee()
+	// // Set the gas amount on the transaction factory
+	// txf = txf.WithGas(adjusted)
 
-	// Generate the transaction bytes
-	txBytes, err = encCfg.TxConfig.TxEncoder()(tx)
-	if err != nil {
-		return nil, sdk.Coins{}, err
-	}
+	// // Build the transaction builder
+	// txb, err := txf.BuildUnsignedTx(msgs...)
+	// if err != nil {
+	// 	return nil, sdk.Coins{}, err
+	// }
+
+	// if err = tx.Sign(ctx, txf, txSignerKey, txb, false); err != nil {
+	// 	return nil, sdk.Coins{}, err
+	// }
+
+	// tx := txb.GetTx()
+	// fees = tx.GetFee()
+
+	// // Generate the transaction bytes
+	// txBytes, err = encCfg.TxConfig.TxEncoder()(tx)
+	// if err != nil {
+	// 	return nil, sdk.Coins{}, err
+	// }
 
 	return txBytes, fees, nil
 }

From f30a3e18547223afc2a74ba1defec53d41cfa70e Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 18 Feb 2025 22:52:08 -0300
Subject: [PATCH 29/31] chore: reduce code duplication

---
 clientcontroller/babylon.go         |  26 +-
 clientcontroller/babylon_msg.go     | 405 +---------------------------
 clientcontroller/babylon_msg_log.go | 221 ---------------
 3 files changed, 15 insertions(+), 637 deletions(-)
 delete mode 100644 clientcontroller/babylon_msg_log.go

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index 069641d..a48fe34 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -202,17 +202,13 @@ func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) ([]*b
 	log := bc.logger
 
 	var (
-		txResponses []*sdk.TxResponse
+		txResponses []*babylonclient.RelayerTxResponse
 		failedMsgs  []*failedMsg
 	)
 
 	errAccKey := AccessKeyWithLock(cfg.KeyDirectory, func() error {
-		keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
-		if err != nil {
-			return err
-		}
-
-		covAddr, err := GetKeyAddressForKey(keybase, cfg.Key)
+		cp := bc.bbnClient.Provider()
+		covAddr, err := cp.GetKeyAddressForKey(cfg.Key)
 		if err != nil {
 			return err
 		}
@@ -228,7 +224,7 @@ func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) ([]*b
 			return err
 		}
 
-		txResponses, failedMsgs, err = reliablySendEachMsgAsTx(cfg, bc.bbnClient.Provider(), msgs, log, encCfg, covAcc)
+		txResponses, failedMsgs, err = reliablySendEachMsgAsTx(cfg, cp, msgs, log, encCfg, covAcc)
 		return err
 	})
 	if errAccKey != nil {
@@ -243,19 +239,7 @@ func (bc *BabylonController) reliablySendMsgsAsMultipleTxs(msgs []sdk.Msg) ([]*b
 		)
 	}
 
-	resp := make([]*babylonclient.RelayerTxResponse, len(txResponses))
-	for i, res := range txResponses {
-		resp[i] = &babylonclient.RelayerTxResponse{
-			Height:    res.Height,
-			TxHash:    res.TxHash,
-			Codespace: res.Codespace,
-			Code:      res.Code,
-			Data:      res.Data,
-			Events:    parseEventsFromTxResponse(res),
-		}
-	}
-
-	return resp, nil
+	return txResponses, nil
 }
 
 // SubmitCovenantSigs submits the Covenant signature via a MsgAddCovenantSig to Babylon if the daemon runs in Covenant mode
diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 78e7ad1..8f433f6 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -3,7 +3,6 @@ package clientcontroller
 import (
 	"context"
 	"fmt"
-	"math"
 	"os"
 	"path"
 	"strings"
@@ -13,30 +12,22 @@ import (
 	"errors"
 
 	sdkerrors "cosmossdk.io/errors"
-	"cosmossdk.io/store/rootmulti"
 	"github.com/avast/retry-go/v4"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
 	"github.com/babylonlabs-io/babylon/client/babylonclient"
 	bbnclient "github.com/babylonlabs-io/babylon/client/client"
 	"github.com/babylonlabs-io/babylon/client/config"
-	abci "github.com/cometbft/cometbft/abci/types"
-	rpcclient "github.com/cometbft/cometbft/rpc/client"
 	"github.com/cometbft/cometbft/rpc/client/http"
-	coretypes "github.com/cometbft/cometbft/rpc/core/types"
 	"github.com/cosmos/cosmos-sdk/client"
 	"github.com/cosmos/cosmos-sdk/client/tx"
 	"github.com/cosmos/cosmos-sdk/codec"
 	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
 	"github.com/cosmos/cosmos-sdk/crypto/keyring"
 	sdk "github.com/cosmos/cosmos-sdk/types"
-	legacyerrors "github.com/cosmos/cosmos-sdk/types/errors"
-	txtypes "github.com/cosmos/cosmos-sdk/types/tx"
 	"github.com/cosmos/cosmos-sdk/types/tx/signing"
 	"github.com/juju/fslock"
 
 	"go.uber.org/zap"
-	"google.golang.org/grpc/codes"
-	"google.golang.org/grpc/status"
 )
 
 // Note: most of the functions were adappt from
@@ -52,7 +43,7 @@ var (
 )
 
 // callbackTx is the expected type that waits for the inclusion of a transaction on the chain to be called
-type callbackTx func(*sdk.TxResponse, error)
+type callbackTx func(*babylonclient.RelayerTxResponse, error)
 
 type failedMsg struct {
 	msg    sdk.Msg
@@ -67,7 +58,7 @@ func reliablySendEachMsgAsTx(
 	log *zap.Logger,
 	encCfg *appparams.EncodingConfig,
 	covAcc sdk.AccountI,
-) (txResponses []*sdk.TxResponse, failedMsgs []*failedMsg, err error) {
+) (txResponses []*babylonclient.RelayerTxResponse, failedMsgs []*failedMsg, err error) {
 	c, err := http.NewWithTimeout(cfg.RPCAddr, "/websocket", uint(cfg.Timeout.Seconds()))
 	if err != nil {
 		return nil, nil, err
@@ -79,7 +70,7 @@ func reliablySendEachMsgAsTx(
 	msgLen := len(msgs)
 	// create outputs at msg len capacity to handle each msg in parallel
 	// as it is easier than pass 2 channels for each func
-	txResponses = make([]*sdk.TxResponse, msgLen)
+	txResponses = make([]*babylonclient.RelayerTxResponse, msgLen)
 	failedMsgs = make([]*failedMsg, msgLen)
 
 	var wg sync.WaitGroup
@@ -137,7 +128,7 @@ func RetrySendMessagesToMempool(
 
 	accSequence, accNumber uint64,
 
-	asyncCallbacks ...callbackTx,
+	asyncCallbacks ...func(*babylonclient.RelayerTxResponse, error),
 ) error {
 	return retry.Do(func() error {
 		sendMsgErr := SendMessagesToMempool(ctx, cfg, cp, log, rpcClient, encCfg, msgs, accSequence, accNumber, asyncCallbacks...)
@@ -170,7 +161,7 @@ func SendMessagesToMempool(
 
 	accSequence, accNumber uint64,
 
-	asyncCallbacks ...callbackTx,
+	asyncCallbacks ...func(*babylonclient.RelayerTxResponse, error),
 ) error {
 	memo, gas := "", uint64(0)
 
@@ -179,7 +170,7 @@ func SendMessagesToMempool(
 		return err
 	}
 
-	err = BroadcastTx(ctx, logger, cfg, encCfg, rpcClient, txBytes, msgs, ctx, defaultBroadcastWaitTimeout, asyncCallbacks)
+	err = cp.BroadcastTx(ctx, txBytes, ctx, defaultBroadcastWaitTimeout, asyncCallbacks)
 	if err != nil {
 		return err
 	}
@@ -202,17 +193,8 @@ func BuildMessages(
 	fees sdk.Coins,
 	err error,
 ) {
-	keybase, err := KeybaseFromCfg(cfg, encCfg.Codec)
-	if err != nil {
-		return nil, sdk.Coins{}, err
-	}
-
-	txf := TxFactory(cfg, encCfg.TxConfig, keybase)
-	if memo != "" {
-		txf = txf.WithMemo(memo)
-	}
-
-	txf = txf.WithSequence(accSequence).
+	txf := TxFactory(cfg, encCfg.TxConfig).
+		WithSequence(accSequence).
 		WithAccountNumber(accNumber)
 
 	txSignerKey := cfg.Key
@@ -228,200 +210,9 @@ func BuildMessages(
 		return nil, sdk.Coins{}, err
 	}
 
-	// adjusted := gas
-	// if gas == 0 {
-	// 	_, adjusted, err = cp.CalculateGas(ctx, txf, txSignerKey, msgs...)
-	// 	if err != nil {
-	// 		return nil, sdk.Coins{}, err
-	// 	}
-	// }
-
-	// // Set the gas amount on the transaction factory
-	// txf = txf.WithGas(adjusted)
-
-	// // Build the transaction builder
-	// txb, err := txf.BuildUnsignedTx(msgs...)
-	// if err != nil {
-	// 	return nil, sdk.Coins{}, err
-	// }
-
-	// if err = tx.Sign(ctx, txf, txSignerKey, txb, false); err != nil {
-	// 	return nil, sdk.Coins{}, err
-	// }
-
-	// tx := txb.GetTx()
-	// fees = tx.GetFee()
-
-	// // Generate the transaction bytes
-	// txBytes, err = encCfg.TxConfig.TxEncoder()(tx)
-	// if err != nil {
-	// 	return nil, sdk.Coins{}, err
-	// }
-
 	return txBytes, fees, nil
 }
 
-// BroadcastTx broadcasts a transaction with the given raw bytes and then, in an async goroutine, waits for the tx to be included in the block.
-// The wait will end after either the asyncTimeout has run out or the asyncCtx exits.
-// If there is no error broadcasting, the asyncCallback will be called with success/failure of the wait for block inclusion.
-func BroadcastTx(
-	ctx context.Context, // context for tx broadcast
-	logger *zap.Logger,
-	cfg *config.BabylonConfig,
-	encCfg *appparams.EncodingConfig,
-
-	rpcClient *babylonclient.RPCClient,
-	tx []byte, // raw tx to be broadcasted
-	msgs []sdk.Msg, // used for logging only
-
-	asyncCtx context.Context, // context for async wait for block inclusion after successful tx broadcast
-	asyncTimeout time.Duration, // timeout for waiting for block inclusion
-	asyncCallbacks []callbackTx, // callback for success/fail of the wait for block inclusion
-) error {
-	res, err := rpcClient.BroadcastTxSync(ctx, tx)
-	isErr := err != nil
-	isFailed := res != nil && res.Code != 0
-	if isErr || isFailed {
-		if isErr && res == nil {
-			// There are some cases where BroadcastTxSync will return an error but the associated
-			// ResultBroadcastTx will be nil.
-			return err
-		}
-		rlyResp := &babylonclient.RelayerTxResponse{
-			TxHash:    res.Hash.String(),
-			Codespace: res.Codespace,
-			Code:      res.Code,
-			Data:      res.Data.String(),
-		}
-		if isFailed {
-			err = sdkError(res.Codespace, res.Code)
-			if err == nil {
-				err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.Log)
-			}
-		}
-		LogFailedTx(logger, cfg.ChainID, rlyResp, err, msgs)
-		return err
-	}
-
-	// TODO: maybe we need to check if the node has tx indexing enabled?
-	// if not, we need to find a new way to block until inclusion in a block
-	protoCdc := codec.NewProtoCodec(encCfg.InterfaceRegistry)
-	go waitForTx(asyncCtx, logger, rpcClient, protoCdc, encCfg.TxConfig, cfg.ChainID, res.Hash, msgs, asyncTimeout, asyncCallbacks)
-
-	return nil
-}
-
-// waitForTx waits for a transaction to be included in a block, logs success/fail, then invokes callback.
-// This is intended to be called as an async goroutine.
-func waitForTx(
-	ctx context.Context,
-	log *zap.Logger,
-	rpcClient *babylonclient.RPCClient,
-	cdc *codec.ProtoCodec,
-	txConfig client.TxConfig,
-	chainId string,
-	txHash []byte,
-	msgs []sdk.Msg, // used for logging only
-	waitTimeout time.Duration,
-	callbacks []callbackTx,
-) {
-	res, err := waitForBlockInclusion(ctx, rpcClient, txConfig, txHash, waitTimeout)
-	if err != nil {
-		log.Error("Failed to wait for block inclusion", zap.Error(err))
-		if len(callbacks) > 0 {
-			for _, cb := range callbacks {
-				//Call each callback in order since waitForTx is already invoked asyncronously
-				cb(nil, err)
-			}
-		}
-		return
-	}
-
-	rlyResp := &babylonclient.RelayerTxResponse{
-		Height:    res.Height,
-		TxHash:    res.TxHash,
-		Codespace: res.Codespace,
-		Code:      res.Code,
-		Data:      res.Data,
-		Events:    parseEventsFromTxResponse(res),
-	}
-
-	// transaction was executed, log the success or failure using the tx response code
-	// NOTE: error is nil, logic should use the returned error to determine if the
-	// transaction was successfully executed.
-
-	if res.Code != 0 {
-		// Check for any registered SDK errors
-		err := sdkError(res.Codespace, res.Code)
-		if err == nil {
-			err = fmt.Errorf("transaction failed to execute: codespace: %s, code: %d, log: %s", res.Codespace, res.Code, res.RawLog)
-		}
-		if len(callbacks) > 0 {
-			for _, cb := range callbacks {
-				//Call each callback in order since waitForTx is already invoked asyncronously
-				cb(nil, err)
-			}
-		}
-		LogFailedTx(log, chainId, rlyResp, nil, msgs)
-		return
-	}
-
-	if len(callbacks) > 0 {
-		for _, cb := range callbacks {
-			//Call each callback in order since waitForTx is already invoked asyncronously
-			cb(res, nil)
-		}
-	}
-	LogSuccessTx(log, chainId, cdc, res, msgs)
-}
-
-// waitForBlockInclusion will wait for a transaction to be included in a block, up to waitTimeout or context cancellation.
-func waitForBlockInclusion(
-	ctx context.Context,
-	rpcClient *babylonclient.RPCClient,
-	txConfig client.TxConfig,
-	txHash []byte,
-	waitTimeout time.Duration,
-) (*sdk.TxResponse, error) {
-	exitAfter := time.After(waitTimeout)
-	for {
-		select {
-		case <-exitAfter:
-			return nil, fmt.Errorf("timed out after: %d; %w", waitTimeout, babylonclient.ErrTimeoutAfterWaitingForTxBroadcast)
-		// This fixed poll is fine because it's only for logging and updating prometheus metrics currently.
-		case <-time.After(time.Millisecond * 100):
-			res, err := rpcClient.Tx(ctx, txHash, false)
-			if err == nil {
-				return mkTxResult(res, txConfig)
-			}
-			if strings.Contains(err.Error(), "transaction indexing is disabled") {
-				return nil, fmt.Errorf("cannot determine success/failure of tx because transaction indexing is disabled on rpc url")
-			}
-		case <-ctx.Done():
-			return nil, ctx.Err()
-		}
-	}
-}
-
-// mkTxResult decodes a comet transaction into an SDK TxResponse.
-func mkTxResult(
-	resTx *coretypes.ResultTx,
-	txConfig client.TxConfig,
-) (*sdk.TxResponse, error) {
-	txbz, err := txConfig.TxDecoder()(resTx.Tx)
-	if err != nil {
-		return nil, err
-	}
-
-	p, ok := txbz.(intoAny)
-	if !ok {
-		return nil, fmt.Errorf("expecting a type implementing intoAny, got: %T", txbz)
-	}
-
-	any := p.AsAny()
-	return sdk.NewResponseResultTx(resTx, any, ""), nil
-}
-
 func AccessKeyWithLock(keyDir string, accessFunc func() error) error {
 	// use lock file to guard concurrent access to the keyring
 	lockFilePath := path.Join(keyDir, "keys.lock")
@@ -442,51 +233,6 @@ func AccessKeyWithLock(keyDir string, accessFunc func() error) error {
 	return err
 }
 
-// QueryABCI performs an ABCI query and returns the appropriate response and error sdk error code.
-func QueryABCI(ctx context.Context, rpcClient *babylonclient.RPCClient, req abci.RequestQuery) (abci.ResponseQuery, error) {
-	opts := rpcclient.ABCIQueryOptions{
-		Height: req.Height,
-		Prove:  req.Prove,
-	}
-
-	result, err := rpcClient.ABCIQueryWithOptions(ctx, req.Path, req.Data, opts)
-	if err != nil {
-		return abci.ResponseQuery{}, err
-	}
-
-	if !result.Response.IsOK() {
-		return abci.ResponseQuery{}, sdkErrorToGRPCError(result.Response.Code, result.Response.Log)
-	}
-
-	// data from trusted node or subspace query doesn't need verification
-	if !opts.Prove || !isQueryStoreWithProof(req.Path) {
-		return result.Response, nil
-	}
-
-	return result.Response, nil
-}
-
-// isQueryStoreWithProof expects a format like /<queryType>/<storeName>/<subpath>
-// queryType must be "store" and subpath must be "key" to require a proof.
-func isQueryStoreWithProof(path string) bool {
-	if !strings.HasPrefix(path, "/") {
-		return false
-	}
-
-	paths := strings.SplitN(path[1:], "/", 3)
-
-	switch {
-	case len(paths) != 3:
-		return false
-	case paths[0] != "store":
-		return false
-	case rootmulti.RequireProof("/" + paths[2]):
-		return true
-	}
-
-	return false
-}
-
 func ErrorContained(err error, errList []*sdkerrors.Error) bool {
 	for _, e := range errList {
 		if strings.Contains(err.Error(), e.Error()) {
@@ -510,77 +256,16 @@ func KeybaseFromCfg(
 	)
 }
 
-// PrepareFactory mutates the tx factory with the appropriate account number, sequence number, and min gas settings.
-func PrepareFactory(
-	cliCtx client.Context,
-	txf tx.Factory,
-	keybase keyring.Keyring,
-	signingKey string,
-) (tx.Factory, error) {
-	var (
-		err      error
-		from     sdk.AccAddress
-		num, seq uint64
-	)
-
-	// Get key address and retry if fail
-	if err = retry.Do(func() error {
-		from, err = GetKeyAddressForKey(keybase, signingKey)
-		if err != nil {
-			return err
-		}
-		return err
-	}, rtyAtt, rtyDel, rtyErr); err != nil {
-		return tx.Factory{}, err
-	}
-
-	cliCtx = cliCtx.WithFromAddress(from)
-
-	// TODO: why this code? this may potentially require another query when we don't want one
-	initNum, initSeq := txf.AccountNumber(), txf.Sequence()
-	if initNum == 0 || initSeq == 0 {
-		if err = retry.Do(func() error {
-			num, seq, err = txf.AccountRetriever().GetAccountNumberSequence(cliCtx, from)
-			if err != nil {
-				return err
-			}
-			return err
-		}, rtyAtt, rtyDel, rtyErr); err != nil {
-			return txf, err
-		}
-
-		if initNum == 0 {
-			txf = txf.WithAccountNumber(num)
-		}
-
-		if initSeq == 0 {
-			txf = txf.WithSequence(seq)
-		}
-	}
-
-	return txf, nil
-}
-
-func GetKeyAddressForKey(keybase keyring.Keyring, key string) (sdk.AccAddress, error) {
-	info, err := keybase.Key(key)
-	if err != nil {
-		return nil, err
-	}
-	return info.GetAddress()
-}
-
 // TxFactory instantiates a new tx factory with the appropriate configuration settings for this chain.
 func TxFactory(
 	cfg *config.BabylonConfig,
 	txConf client.TxConfig,
-	keybase keyring.Keyring,
 ) tx.Factory {
 	return tx.Factory{}.
 		WithChainID(cfg.ChainID).
 		WithTxConfig(txConf).
 		WithGasAdjustment(cfg.GasAdjustment).
 		WithGasPrices(cfg.GasPrices).
-		WithKeybase(keybase).
 		WithSignMode(SignMode(cfg.SignModeStr))
 }
 
@@ -595,75 +280,6 @@ func SignMode(signModeStr string) signing.SignMode {
 	}
 }
 
-// BuildSimTx creates an unsigned tx with an empty single signature and returns
-// the encoded transaction or an error if the unsigned transaction cannot be built.
-func BuildSimTx(info *keyring.Record, txf tx.Factory, msgs ...sdk.Msg) ([]byte, error) {
-	txb, err := txf.BuildUnsignedTx(msgs...)
-	if err != nil {
-		return nil, err
-	}
-
-	pk, err := info.GetPubKey()
-	if err != nil {
-		return nil, err
-	}
-
-	// Create an empty signature literal as the ante handler will populate with a
-	// sentinel pubkey.
-	sig := signing.SignatureV2{
-		PubKey: pk,
-		Data: &signing.SingleSignatureData{
-			SignMode: txf.SignMode(),
-		},
-		Sequence: txf.Sequence(),
-	}
-	if err := txb.SetSignatures(sig); err != nil {
-		return nil, err
-	}
-
-	protoProvider, ok := txb.(protoTxProvider)
-	if !ok {
-		return nil, fmt.Errorf("cannot simulate amino tx")
-	}
-
-	simReq := txtypes.SimulateRequest{Tx: protoProvider.GetProtoTx()}
-	return simReq.Marshal()
-}
-
-// protoTxProvider is a type which can provide a proto transaction. It is a
-// workaround to get access to the wrapper TxBuilder's method GetProtoTx().
-type protoTxProvider interface {
-	GetProtoTx() *txtypes.Tx
-}
-
-func sdkErrorToGRPCError(code uint32, log string) error {
-	switch code {
-	case legacyerrors.ErrInvalidRequest.ABCICode():
-		return status.Error(codes.InvalidArgument, log)
-	case legacyerrors.ErrUnauthorized.ABCICode():
-		return status.Error(codes.Unauthenticated, log)
-	case legacyerrors.ErrKeyNotFound.ABCICode():
-		return status.Error(codes.NotFound, log)
-	default:
-		return status.Error(codes.Unknown, log)
-	}
-}
-
-// AdjustEstimatedGas adjusts the estimated gas usage by multiplying it by the gas adjustment factor
-// and return estimated gas is higher than max gas error. If the gas usage is zero, the adjusted gas
-// is also zero.
-func AdjustEstimatedGas(gasAdjustment float64, gasUsed uint64) (uint64, error) {
-	if gasUsed == 0 {
-		return gasUsed, nil
-	}
-
-	gas := gasAdjustment * float64(gasUsed)
-	if math.IsInf(gas, 1) {
-		return 0, fmt.Errorf("infinite gas used")
-	}
-	return uint64(gas), nil
-}
-
 // sdkError will return the Cosmos SDK registered error for a given codespace/code combo if registered, otherwise nil.
 func sdkError(codespace string, code uint32) error {
 	// ABCIError will return an error other than "unknown" if syncRes.Code is a registered error in syncRes.Codespace
@@ -697,10 +313,10 @@ func reliablySendEachMsgAsTxCallback(
 	wg *sync.WaitGroup,
 	msg sdk.Msg,
 	msgIndex int,
-	txResponses []*sdk.TxResponse,
+	txResponses []*babylonclient.RelayerTxResponse,
 	failedMsgs []*failedMsg,
 ) callbackTx {
-	return func(txResp *sdk.TxResponse, err error) {
+	return func(txResp *babylonclient.RelayerTxResponse, err error) {
 		defer wg.Done()
 
 		if err != nil {
@@ -733,5 +349,4 @@ func reliablySendEachMsgAsTxCallback(
 		)
 		txResponses[msgIndex] = txResp
 	}
-
 }
diff --git a/clientcontroller/babylon_msg_log.go b/clientcontroller/babylon_msg_log.go
deleted file mode 100644
index c711050..0000000
--- a/clientcontroller/babylon_msg_log.go
+++ /dev/null
@@ -1,221 +0,0 @@
-package clientcontroller
-
-import (
-	"errors"
-	"reflect"
-
-	"github.com/babylonlabs-io/babylon/client/babylonclient"
-	"github.com/cosmos/cosmos-sdk/codec"
-	sdk "github.com/cosmos/cosmos-sdk/types"
-	typestx "github.com/cosmos/cosmos-sdk/types/tx"
-	feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"
-	transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
-	clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
-	chantypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
-	"go.uber.org/zap"
-	"go.uber.org/zap/zapcore"
-)
-
-// LogFailedTx takes the transaction and the messages to create it and logs the appropriate data
-func LogFailedTx(log *zap.Logger, chainId string, res *babylonclient.RelayerTxResponse, err error, msgs []sdk.Msg) {
-	// Include the chain_id
-	fields := []zapcore.Field{zap.String("chain_id", chainId)}
-
-	// Extract the channels from the events, if present
-	if res != nil {
-		channels := getChannelsIfPresent(res.Events)
-		fields = append(fields, channels...)
-	}
-	fields = append(fields, msgTypesField(msgs))
-
-	if err != nil {
-
-		if errors.Is(err, chantypes.ErrRedundantTx) {
-			log.Debug("Redundant message(s)", fields...)
-			return
-		}
-
-		// Make a copy since we may continue to the warning
-		errorFields := append(fields, zap.Error(err))
-		log.Error(
-			"Failed sending cosmos transaction",
-			errorFields...,
-		)
-
-		if res == nil {
-			return
-		}
-	}
-
-	if res.Code != 0 {
-		if sdkErr := sdkError(res.Codespace, res.Code); err != nil {
-			fields = append(fields, zap.NamedError("sdk_error", sdkErr))
-		}
-		fields = append(fields, zap.Any("response", res))
-		log.Warn(
-			"Sent transaction but received failure response",
-			fields...,
-		)
-	}
-}
-
-// LogSuccessTx take the transaction and the messages to create it and logs the appropriate data
-func LogSuccessTx(log *zap.Logger, chainId string, cdc *codec.ProtoCodec, res *sdk.TxResponse, msgs []sdk.Msg) {
-	// Include the chain_id
-	fields := []zapcore.Field{zap.String("chain_id", chainId)}
-
-	// Extract the channels from the events, if present
-	if res != nil {
-		events := parseEventsFromTxResponse(res)
-		fields = append(fields, getChannelsIfPresent(events)...)
-	}
-
-	// Include the gas used
-	fields = append(fields, zap.Int64("gas_used", res.GasUsed))
-
-	var m sdk.Msg
-	if err := cdc.InterfaceRegistry().UnpackAny(res.Tx, &m); err == nil {
-		if tx, ok := m.(*typestx.Tx); ok {
-			fields = append(fields, zap.Stringer("fees", tx.GetFee()))
-			if feePayer := getFeePayer(log, cdc, tx); feePayer != "" {
-				fields = append(fields, zap.String("fee_payer", feePayer))
-			}
-		} else {
-			log.Debug(
-				"Failed to convert message to Tx type",
-				zap.Stringer("type", reflect.TypeOf(m)),
-			)
-		}
-	} else {
-		log.Debug("Failed to unpack response Tx into sdk.Msg", zap.Error(err))
-	}
-
-	// Include the height, msgType, and tx_hash
-	fields = append(fields,
-		zap.Int64("height", res.Height),
-		msgTypesField(msgs),
-		zap.String("tx_hash", res.TxHash),
-	)
-
-	// Log the successful transaction with fields
-	log.Info(
-		"Successful transaction",
-		fields...,
-	)
-}
-
-// getChannelsIfPresent scans the events for channel tags
-func getChannelsIfPresent(events []babylonclient.RelayerEvent) []zapcore.Field {
-	channelTags := []string{srcChanTag, dstChanTag}
-	fields := []zap.Field{}
-
-	// While a transaction may have multiple messages, we just need to first
-	// pair of channels
-	foundTag := map[string]struct{}{}
-
-	for _, event := range events {
-		for _, tag := range channelTags {
-			for attributeKey, attributeValue := range event.Attributes {
-				if attributeKey == tag {
-					// Only append the tag once
-					// TODO: what if they are different?
-					if _, ok := foundTag[tag]; !ok {
-						fields = append(fields, zap.String(tag, attributeValue))
-						foundTag[tag] = struct{}{}
-					}
-				}
-			}
-		}
-	}
-	return fields
-}
-
-func msgTypesField(msgs []sdk.Msg) zap.Field {
-	msgTypes := make([]string, len(msgs))
-	for i, m := range msgs {
-		msgTypes[i] = sdk.MsgTypeURL(m)
-	}
-	return zap.Strings("msg_types", msgTypes)
-}
-
-// getFeePayer returns the bech32 address of the fee payer of a transaction.
-// This uses the fee payer field if set,
-// otherwise falls back to the address of whoever signed the first message.
-func getFeePayer(log *zap.Logger, cdc *codec.ProtoCodec, tx *typestx.Tx) string {
-	payer := tx.AuthInfo.Fee.Payer
-	if payer != "" {
-		return payer
-	}
-
-	switch firstMsg := tx.GetMsgs()[0].(type) {
-	case *transfertypes.MsgTransfer:
-		// There is a possible data race around concurrent map access
-		// in the cosmos sdk when it converts the address from bech32.
-		// We don't need the address conversion; just the sender is all that
-		// GetSigners is doing under the hood anyway.
-		return firstMsg.Sender
-	case *clienttypes.MsgCreateClient:
-		// Without this particular special case, there is a panic in ibc-go
-		// due to the sdk config singleton expecting one bech32 prefix but seeing another.
-		return firstMsg.Signer
-	case *clienttypes.MsgUpdateClient:
-		// Same failure mode as MsgCreateClient.
-		return firstMsg.Signer
-	case *clienttypes.MsgUpgradeClient:
-		return firstMsg.Signer
-	case *feetypes.MsgRegisterPayee:
-		return firstMsg.Relayer
-	case *feetypes.MsgRegisterCounterpartyPayee:
-		return firstMsg.Relayer
-	case *feetypes.MsgPayPacketFee:
-		return firstMsg.Signer
-	case *feetypes.MsgPayPacketFeeAsync:
-		return firstMsg.PacketFee.RefundAddress
-	default:
-		signers, _, err := cdc.GetMsgV1Signers(firstMsg)
-		if err != nil {
-			log.Info("Could not get signers for msg when attempting to get the fee payer", zap.Error(err))
-			return ""
-		}
-
-		return string(signers[0])
-	}
-}
-
-func parseEventsFromTxResponse(resp *sdk.TxResponse) []babylonclient.RelayerEvent {
-	var events []babylonclient.RelayerEvent
-
-	if resp == nil {
-		return events
-	}
-
-	for _, logs := range resp.Logs {
-		for _, event := range logs.Events {
-			attributes := make(map[string]string)
-			for _, attribute := range event.Attributes {
-				attributes[attribute.Key] = attribute.Value
-			}
-			events = append(events, babylonclient.RelayerEvent{
-				EventType:  event.Type,
-				Attributes: attributes,
-			})
-		}
-	}
-
-	// After SDK v0.50, indexed events are no longer provided in the logs on
-	// transaction execution, the response events can be directly used
-	if len(events) == 0 {
-		for _, event := range resp.Events {
-			attributes := make(map[string]string)
-			for _, attribute := range event.Attributes {
-				attributes[attribute.Key] = attribute.Value
-			}
-			events = append(events, babylonclient.RelayerEvent{
-				EventType:  event.Type,
-				Attributes: attributes,
-			})
-		}
-	}
-
-	return events
-}

From b2bc2ad68edcd3c50b284f9ed4d52008b8586395 Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Tue, 18 Feb 2025 22:56:22 -0300
Subject: [PATCH 30/31] fix: lint removed unused

---
 clientcontroller/babylon_msg.go | 22 ----------------------
 1 file changed, 22 deletions(-)

diff --git a/clientcontroller/babylon_msg.go b/clientcontroller/babylon_msg.go
index 8f433f6..020e0b6 100644
--- a/clientcontroller/babylon_msg.go
+++ b/clientcontroller/babylon_msg.go
@@ -9,8 +9,6 @@ import (
 	"sync"
 	"time"
 
-	"errors"
-
 	sdkerrors "cosmossdk.io/errors"
 	"github.com/avast/retry-go/v4"
 	appparams "github.com/babylonlabs-io/babylon/app/params"
@@ -21,7 +19,6 @@ import (
 	"github.com/cosmos/cosmos-sdk/client"
 	"github.com/cosmos/cosmos-sdk/client/tx"
 	"github.com/cosmos/cosmos-sdk/codec"
-	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
 	"github.com/cosmos/cosmos-sdk/crypto/keyring"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	"github.com/cosmos/cosmos-sdk/types/tx/signing"
@@ -38,8 +35,6 @@ var (
 	rtyDel                      = retry.Delay(time.Millisecond * 400)
 	rtyErr                      = retry.LastErrorOnly(true)
 	defaultBroadcastWaitTimeout = 10 * time.Minute
-	srcChanTag                  = "packet_src_channel"
-	dstChanTag                  = "packet_dst_channel"
 )
 
 // callbackTx is the expected type that waits for the inclusion of a transaction on the chain to be called
@@ -280,23 +275,6 @@ func SignMode(signModeStr string) signing.SignMode {
 	}
 }
 
-// sdkError will return the Cosmos SDK registered error for a given codespace/code combo if registered, otherwise nil.
-func sdkError(codespace string, code uint32) error {
-	// ABCIError will return an error other than "unknown" if syncRes.Code is a registered error in syncRes.Codespace
-	// This catches all of the sdk errors https://github.com/cosmos/cosmos-sdk/blob/f10f5e5974d2ecbf9efc05bc0bfe1c99fdeed4b6/types/errors/errors.go
-	err := errors.Unwrap(sdkerrors.ABCIError(codespace, code, "error broadcasting transaction"))
-	if err.Error() != "unknown" {
-		return err
-	}
-	return nil
-}
-
-// Deprecated: this interface is used only internally for scenario we are
-// deprecating (StdTxConfig support)
-type intoAny interface {
-	AsAny() *codectypes.Any
-}
-
 // CleanSlice removes nil values from a slice of pointers.
 func CleanSlice[T any](slice []*T) []*T {
 	result := make([]*T, 0, len(slice))

From 082eb53fc1780a16fd4acb28a8724c46533cb92d Mon Sep 17 00:00:00 2001
From: RafilxTenfen <rafaeltenfen.rt@gmail.com>
Date: Wed, 19 Feb 2025 09:20:28 -0300
Subject: [PATCH 31/31] chore: set to send one msg per tx if the batch fails

---
 clientcontroller/babylon.go | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go
index a48fe34..e373981 100644
--- a/clientcontroller/babylon.go
+++ b/clientcontroller/babylon.go
@@ -2,6 +2,7 @@ package clientcontroller
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"math"
 	"time"
@@ -158,22 +159,21 @@ func (bc *BabylonController) reliablySendMsg(msg sdk.Msg) (*babylonclient.Relaye
 // SendMsgs first it tries to send all the messages in a single transaction
 // if it fails, sends each message in a different transaction.
 func (bc *BabylonController) SendMsgs(msgs []sdk.Msg) ([]*types.TxResponse, error) {
-	// resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
-	// if errSingleTx != nil {
-	// failed to send as a batch tx
-	resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
-	if errMultipleTx != nil {
-		// return nil, errors.Join(errSingleTx, errMultipleTx)
-		return nil, errMultipleTx
-	}
-
-	return convertTxResp(resMultipleTxs...), nil
-	// }
-
-	// if resSingleTx == nil { // some expected error happened
-	// 	return []*types.TxResponse{}, nil
-	// }
-	// return convertTxResp(resSingleTx), nil
+	resSingleTx, errSingleTx := bc.reliablySendMsgs(msgs)
+	if errSingleTx != nil {
+		// failed to send as a batch tx
+		resMultipleTxs, errMultipleTx := bc.reliablySendMsgsAsMultipleTxs(msgs)
+		if errMultipleTx != nil {
+			return nil, errors.Join(errSingleTx, errMultipleTx)
+		}
+
+		return convertTxResp(resMultipleTxs...), nil
+	}
+
+	if resSingleTx == nil { // some expected error happened
+		return []*types.TxResponse{}, nil
+	}
+	return convertTxResp(resSingleTx), nil
 }
 
 func convertTxResp(txs ...*babylonclient.RelayerTxResponse) []*types.TxResponse {