You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: types.go
    path of file: ./repos/cosmos-sdk/types/tx
    
    the code of the file until where you have to start completion: package tx

import (
	"fmt"

	protov2 "google.golang.org/protobuf/proto"

	errorsmod "cosmossdk.io/errors"

	"github.com/cosmos/cosmos-sdk/codec"
	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
	sdk "github.com/cosmos/cosmos-sdk/types"
	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

// MaxGasWanted defines the max gas allowed.
const MaxGasWanted = uint64((1 << 63) - 1)

// Interface implementation checks.
var (
	_, _, _, _ codectypes.UnpackInterfacesMessage = &Tx{}, &TxBody{}, &AuthInfo{}, &SignerInfo{}
)

// GetMsgs implements the GetMsgs method on sdk
    
func (t *Tx) GetSigners(cdc codec.Codec) ([][]byte, []protov2.Message, error) {
	var signers [][]byte
	seen := map[string]bool{}

	var msgsv2 []protov2.Message
	for _, msg := range t.Body.Messages {
		xs, msgv2, err := cdc.GetMsgAnySigners(msg)
		if err != nil {
			return nil, nil, err
		}

		msgsv2 = append(msgsv2, msgv2)

		for _, signer := range xs {
			if !seen[string(signer)] {
				signers = append(signers, signer)
				seen[string(signer)] = true
			}
		}
	}

	// ensure any specified fee payer is included in the required signers (at the end)
	feePayer := t.AuthInfo.Fee.Payer
	var feePayerAddr []byte
	if feePayer != "" {
		var err error
		feePayerAddr, err = cdc.InterfaceRegistry().SigningContext().AddressCodec().StringToBytes(feePayer)
		if err != nil {
			return nil, nil, err
		}
	}
	if feePayerAddr != nil && !seen[string(feePayerAddr)] {
		signers = append(signers, feePayerAddr)
		seen[string(feePayerAddr)] = true
	}

	return signers, msgsv2, nil
}