The tx package provides a robust set of tools for building, signing, and managing transactions in a Cosmos SDK-based blockchain application. ## Overview This package includes several key components: 1. Transaction Factory 2. Transaction Config 3. Transaction Encoder/Decoder 4. Signature Handling ## Architecture ```mermaid graph TD A[Client] --> B[Factory] B --> D[TxConfig] D --> E[TxEncodingConfig] D --> F[TxSigningConfig] B --> G[Tx] G --> H[Encoder] G --> I[Decoder] F --> J[SignModeHandler] F --> K[SigningContext] B --> L[AuxTxBuilder] ``` ## Key Components ### TxConfig `TxConfig` provides configuration for transaction handling, including: - Encoding and decoding - Sign mode handling - Signature JSON marshaling/unmarshaling ```mermaid classDiagram class TxConfig { <> TxEncodingConfig TxSigningConfig } class TxEncodingConfig { <> TxEncoder() txEncoder TxDecoder() txDecoder TxJSONEncoder() txEncoder TxJSONDecoder() txDecoder Decoder() Decoder } class TxSigningConfig { <> SignModeHandler() *signing.HandlerMap SigningContext() *signing.Context MarshalSignatureJSON([]Signature) ([]byte, error) UnmarshalSignatureJSON([]byte) ([]Signature, error) } class txConfig { TxEncodingConfig TxSigningConfig } class defaultEncodingConfig { cdc codec.BinaryCodec decoder Decoder TxEncoder() txEncoder TxDecoder() txDecoder TxJSONEncoder() txEncoder TxJSONDecoder() txDecoder } class defaultTxSigningConfig { signingCtx *signing.Context handlerMap *signing.HandlerMap cdc codec.BinaryCodec SignModeHandler() *signing.HandlerMap SigningContext() *signing.Context MarshalSignatureJSON([]Signature) ([]byte, error) UnmarshalSignatureJSON([]byte) ([]Signature, error) } TxConfig <|-- txConfig TxEncodingConfig <|.. defaultEncodingConfig TxSigningConfig <|.. defaultTxSigningConfig txConfig *-- defaultEncodingConfig txConfig *-- defaultTxSigningConfig ``` ### Factory The `Factory` is the main entry point for creating and managing transactions. It handles: - Account preparation - Gas calculation - Unsigned transaction building - Transaction signing - Transaction simulation - Transaction broadcasting ```mermaid classDiagram class Factory { keybase keyring.Keyring cdc codec.BinaryCodec accountRetriever account.AccountRetriever ac address.Codec conn gogogrpc.ClientConn txConfig TxConfig txParams TxParameters tx txState NewFactory(keybase, cdc, accRetriever, txConfig, ac, conn, parameters) Factory Prepare() error BuildUnsignedTx(msgs ...transaction.Msg) error BuildsSignedTx(ctx context.Context, msgs ...transaction.Msg) (Tx, error) calculateGas(msgs ...transaction.Msg) error Simulate(msgs ...transaction.Msg) (*apitx.SimulateResponse, uint64, error) UnsignedTxString(msgs ...transaction.Msg) (string, error) BuildSimTx(msgs ...transaction.Msg) ([]byte, error) sign(ctx context.Context, overwriteSig bool) (Tx, error) WithGas(gas uint64) WithSequence(sequence uint64) WithAccountNumber(accnum uint64) getTx() (Tx, error) getFee() (*apitx.Fee, error) getSigningTxData() (signing.TxData, error) setSignatures(...Signature) error } class TxParameters { <> chainID string AccountConfig GasConfig FeeConfig SignModeConfig TimeoutConfig MemoConfig } class TxConfig { <> } class Tx { <> } class txState { <> msgs []transaction.Msg memo string fees []*base.Coin gasLimit uint64 feeGranter []byte feePayer []byte timeoutHeight uint64 unordered bool timeoutTimestamp uint64 signatures []Signature signerInfos []*apitx.SignerInfo } Factory *-- TxParameters Factory *-- TxConfig Factory *-- txState Factory ..> Tx : creates ``` ### Encoder/Decoder The package includes functions for encoding and decoding transactions in both binary and JSON formats. ```mermaid classDiagram class Decoder { <> Decode(txBytes []byte) (*txdecode.DecodedTx, error) } class txDecoder { <> decode(txBytes []byte) (Tx, error) } class txEncoder { <> encode(tx Tx) ([]byte, error) } class EncoderUtils { <> decodeTx(cdc codec.BinaryCodec, decoder Decoder) txDecoder encodeTx(tx Tx) ([]byte, error) decodeJsonTx(cdc codec.BinaryCodec, decoder Decoder) txDecoder encodeJsonTx(tx Tx) ([]byte, error) protoTxBytes(tx *txv1beta1.Tx) ([]byte, error) } class MarshalOptions { <> Deterministic bool } class JSONMarshalOptions { <> Indent string UseProtoNames bool UseEnumNumbers bool } Decoder <.. EncoderUtils : uses txDecoder <.. EncoderUtils : creates txEncoder <.. EncoderUtils : implements EncoderUtils ..> MarshalOptions : uses EncoderUtils ..> JSONMarshalOptions : uses ``` ### Sequence Diagrams #### Generate Aux Signer Data ```mermaid sequenceDiagram participant User participant GenerateOrBroadcastTxCLI participant generateAuxSignerData participant makeAuxSignerData participant AuxTxBuilder participant ctx.PrintProto User->>GenerateOrBroadcastTxCLI: Call with isAux flag GenerateOrBroadcastTxCLI->>generateAuxSignerData: Call generateAuxSignerData->>makeAuxSignerData: Call makeAuxSignerData->>AuxTxBuilder: NewAuxTxBuilder() makeAuxSignerData->>AuxTxBuilder: SetAddress(f.txParams.fromAddress) alt f.txParams.offline makeAuxSignerData->>AuxTxBuilder: SetAccountNumber(f.AccountNumber()) makeAuxSignerData->>AuxTxBuilder: SetSequence(f.Sequence()) else makeAuxSignerData->>f.accountRetriever: GetAccountNumberSequence() makeAuxSignerData->>AuxTxBuilder: SetAccountNumber(accNum) makeAuxSignerData->>AuxTxBuilder: SetSequence(seq) end makeAuxSignerData->>AuxTxBuilder: SetMsgs(msgs...) makeAuxSignerData->>AuxTxBuilder: SetSignMode(f.SignMode()) makeAuxSignerData->>f.keybase: GetPubKey(f.txParams.fromName) makeAuxSignerData->>AuxTxBuilder: SetPubKey(pubKey) makeAuxSignerData->>AuxTxBuilder: SetChainID(f.txParams.chainID) makeAuxSignerData->>AuxTxBuilder: GetSignBytes() makeAuxSignerData->>f.keybase: Sign(f.txParams.fromName, signBz, f.SignMode()) makeAuxSignerData->>AuxTxBuilder: SetSignature(sig) makeAuxSignerData->>AuxTxBuilder: GetAuxSignerData() AuxTxBuilder-->>makeAuxSignerData: Return AuxSignerData makeAuxSignerData-->>generateAuxSignerData: Return AuxSignerData generateAuxSignerData->>ctx.PrintProto: Print AuxSignerData ctx.PrintProto-->>GenerateOrBroadcastTxCLI: Return result GenerateOrBroadcastTxCLI-->>User: Return result ``` #### Generate Only ```mermaid sequenceDiagram participant User participant GenerateOrBroadcastTxCLI participant generateOnly participant Factory participant ctx.PrintString User->>GenerateOrBroadcastTxCLI: Call with generateOnly flag GenerateOrBroadcastTxCLI->>generateOnly: Call generateOnly->>Factory: Prepare() alt Error in Prepare Factory-->>generateOnly: Return error generateOnly-->>GenerateOrBroadcastTxCLI: Return error GenerateOrBroadcastTxCLI-->>User: Return error end generateOnly->>Factory: UnsignedTxString(msgs...) Factory->>Factory: BuildUnsignedTx(msgs...) Factory->>Factory: setMsgs(msgs...) Factory->>Factory: setMemo(f.txParams.memo) Factory->>Factory: setFees(f.txParams.gasPrices) Factory->>Factory: setGasLimit(f.txParams.gas) Factory->>Factory: setFeeGranter(f.txParams.feeGranter) Factory->>Factory: setFeePayer(f.txParams.feePayer) Factory->>Factory: setTimeoutHeight(f.txParams.timeoutHeight) Factory->>Factory: getTx() Factory->>Factory: txConfig.TxJSONEncoder() Factory->>Factory: encoder(tx) Factory-->>generateOnly: Return unsigned tx string generateOnly->>ctx.PrintString: Print unsigned tx string ctx.PrintString-->>generateOnly: Return result generateOnly-->>GenerateOrBroadcastTxCLI: Return result GenerateOrBroadcastTxCLI-->>User: Return result ``` #### DryRun ```mermaid sequenceDiagram participant User participant GenerateOrBroadcastTxCLI participant dryRun participant Factory participant os.Stderr User->>GenerateOrBroadcastTxCLI: Call with dryRun flag GenerateOrBroadcastTxCLI->>dryRun: Call dryRun->>Factory: Prepare() alt Error in Prepare Factory-->>dryRun: Return error dryRun-->>GenerateOrBroadcastTxCLI: Return error GenerateOrBroadcastTxCLI-->>User: Return error end dryRun->>Factory: Simulate(msgs...) Factory->>Factory: BuildSimTx(msgs...) Factory->>Factory: BuildUnsignedTx(msgs...) Factory->>Factory: getSimPK() Factory->>Factory: getSimSignatureData(pk) Factory->>Factory: setSignatures(sig) Factory->>Factory: getTx() Factory->>Factory: txConfig.TxEncoder()(tx) Factory->>ServiceClient: Simulate(context.Background(), &apitx.SimulateRequest{}) ServiceClient->>Factory: Return result Factory-->>dryRun: Return (simulation, gas, error) alt Error in Simulate dryRun-->>GenerateOrBroadcastTxCLI: Return error GenerateOrBroadcastTxCLI-->>User: Return error end dryRun->>os.Stderr: Fprintf(GasEstimateResponse{GasEstimate: gas}) os.Stderr-->>dryRun: Return result dryRun-->>GenerateOrBroadcastTxCLI: Return result GenerateOrBroadcastTxCLI-->>User: Return result ``` #### Generate and Broadcast Tx ```mermaid sequenceDiagram participant User participant GenerateOrBroadcastTxCLI participant BroadcastTx participant Factory participant clientCtx User->>GenerateOrBroadcastTxCLI: Call GenerateOrBroadcastTxCLI->>BroadcastTx: Call BroadcastTx->>Factory: Prepare() alt Error in Prepare Factory-->>BroadcastTx: Return error BroadcastTx-->>GenerateOrBroadcastTxCLI: Return error GenerateOrBroadcastTxCLI-->>User: Return error end alt SimulateAndExecute is true BroadcastTx->>Factory: calculateGas(msgs...) Factory->>Factory: Simulate(msgs...) Factory->>Factory: WithGas(adjusted) end BroadcastTx->>Factory: BuildUnsignedTx(msgs...) Factory->>Factory: setMsgs(msgs...) Factory->>Factory: setMemo(f.txParams.memo) Factory->>Factory: setFees(f.txParams.gasPrices) Factory->>Factory: setGasLimit(f.txParams.gas) Factory->>Factory: setFeeGranter(f.txParams.feeGranter) Factory->>Factory: setFeePayer(f.txParams.feePayer) Factory->>Factory: setTimeoutHeight(f.txParams.timeoutHeight) alt !clientCtx.SkipConfirm BroadcastTx->>Factory: getTx() BroadcastTx->>Factory: txConfig.TxJSONEncoder() BroadcastTx->>clientCtx: PrintRaw(txBytes) BroadcastTx->>clientCtx: Input.GetConfirmation() alt Not confirmed BroadcastTx-->>GenerateOrBroadcastTxCLI: Return error GenerateOrBroadcastTxCLI-->>User: Return error end end BroadcastTx->>Factory: BuildsSignedTx(ctx, msgs...) Factory->>Factory: sign(ctx, true) Factory->>Factory: keybase.GetPubKey(fromName) Factory->>Factory: getSignBytesAdapter() Factory->>Factory: keybase.Sign(fromName, bytesToSign, signMode) Factory->>Factory: setSignatures(sig) Factory->>Factory: getTx() BroadcastTx->>Factory: txConfig.TxEncoder() BroadcastTx->>clientCtx: BroadcastTx(txBytes) alt Error in BroadcastTx clientCtx-->>BroadcastTx: Return error BroadcastTx-->>GenerateOrBroadcastTxCLI: Return error GenerateOrBroadcastTxCLI-->>User: Return error end BroadcastTx->>clientCtx: OutputTx(res) clientCtx-->>BroadcastTx: Return result BroadcastTx-->>GenerateOrBroadcastTxCLI: Return result GenerateOrBroadcastTxCLI-->>User: Return result ``` ## Usage To use the `tx` package, typically you would: 1. Create a `Factory` 2. Simulate the transaction (optional) 3. Build a signed transaction 4. Encode the transaction 5. Broadcast the transaction Here's a simplified example: ```go // Create a Factory factory, err := NewFactory(keybase, cdc, accountRetriever, txConfig, addressCodec, conn, txParameters) if err != nil { return err } // Simulate the transaction (optional) simRes, gas, err := factory.Simulate(msgs...) if err != nil { return err } factory.WithGas(gas) // Build a signed transaction signedTx, err := factory.BuildsSignedTx(context.Background(), msgs...) if err != nil { return err } // Encode the transaction txBytes, err := factory.txConfig.TxEncoder()(signedTx) if err != nil { return err } // Broadcast the transaction // (This step depends on your specific client implementation) ```