wormhole/node/pkg/wormconn/send_tx.go

97 lines
2.6 KiB
Go

package wormconn
import (
"context"
"fmt"
txclient "github.com/cosmos/cosmos-sdk/client/tx"
sdktypes "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
auth "github.com/cosmos/cosmos-sdk/x/auth/types"
)
func (c *ClientConn) SignAndBroadcastTx(ctx context.Context, msg sdktypes.Msg) (*sdktx.BroadcastTxResponse, error) {
// Lock to protect the wallet sequence number.
c.mutex.Lock()
defer c.mutex.Unlock()
authClient := auth.NewQueryClient(c.c)
accountQuery := &auth.QueryAccountRequest{
Address: c.senderAddress,
}
resp, err := authClient.Account(ctx, accountQuery)
if err != nil {
return nil, fmt.Errorf("failed to fetch account: %w", err)
}
var account auth.AccountI
if err := c.encCfg.InterfaceRegistry.UnpackAny(resp.Account, &account); err != nil {
return nil, fmt.Errorf("failed to unmarshal account info: %w", err)
}
builder := c.encCfg.TxConfig.NewTxBuilder()
if err := builder.SetMsgs(msg); err != nil {
return nil, fmt.Errorf("failed to add message to builder: %w", err)
}
builder.SetGasLimit(2000000) // TODO: Maybe simulate and use the result
// The tx needs to be signed in 2 passes: first we populate the SignerInfo
// inside the TxBuilder and then sign the payload.
sequence := account.GetSequence()
sig := signing.SignatureV2{
PubKey: c.privateKey.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: c.encCfg.TxConfig.SignModeHandler().DefaultMode(),
Signature: nil,
},
Sequence: sequence,
}
if err := builder.SetSignatures(sig); err != nil {
return nil, fmt.Errorf("failed to set SignerInfo: %w", err)
}
signerData := authsigning.SignerData{
ChainID: "wormchain",
AccountNumber: account.GetAccountNumber(),
Sequence: sequence,
}
sig, err = txclient.SignWithPrivKey(
c.encCfg.TxConfig.SignModeHandler().DefaultMode(),
signerData,
builder,
c.privateKey,
c.encCfg.TxConfig,
sequence,
)
if err != nil {
return nil, fmt.Errorf("failed to sign tx: %w", err)
}
if err := builder.SetSignatures(sig); err != nil {
return nil, fmt.Errorf("failed to update tx signature: %w", err)
}
txBytes, err := c.encCfg.TxConfig.TxEncoder()(builder.GetTx())
if err != nil {
return nil, fmt.Errorf("failed to marshal tx: %w", err)
}
client := sdktx.NewServiceClient(c.c)
// Returns *BroadcastTxResponse
txResp, err := client.BroadcastTx(
ctx,
&sdktx.BroadcastTxRequest{
Mode: sdktx.BroadcastMode_BROADCAST_MODE_BLOCK,
TxBytes: txBytes,
},
)
if err != nil {
return nil, fmt.Errorf("failed to broadcast tx: %w", err)
}
return txResp, nil
}