Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Update transaction building using v2 #23257

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 190 additions & 0 deletions docs/learn/advanced/01-transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,193 @@ An example can be seen [here](https://docs.cosmos.network/main/user/run-node/txs
#### CometBFT RPC

The three methods presented above are actually higher abstractions over the CometBFT RPC `/broadcast_tx_{async,sync,commit}` endpoints, documented [here](https://docs.cometbft.com/v1.0/explanation/core/rpc). This means that you can use the CometBFT RPC endpoints directly to broadcast the transaction, if you wish so.


#### Complete Example Building and Broadcasting a Transaction using clientv2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, this should be moved under https://docs.cosmos.network/v0.52/tutorials and not here.
This page is about the general concepts of transactions

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what other think, but adding it here: https://github.com/cosmos/cosmos-sdk-docs/tree/main/docs/tutorials and maybe linking it in this page, makes more sense to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok , need write access here: https://github.com/cosmos/cosmos-sdk-docs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can just fork it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks!


1. Correctly set up imports

```go
import (
"context"
"fmt"
"log"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"

apisigning "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
"cosmossdk.io/client/v2/broadcast/comet"
"cosmossdk.io/client/v2/tx"
"cosmossdk.io/core/transaction"
"cosmossdk.io/math"
banktypes "cosmossdk.io/x/bank/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

"github.com/cosmos/cosmos-sdk/codec"
addrcodec "github.com/cosmos/cosmos-sdk/codec/address"
sdk "github.com/cosmos/cosmos-sdk/types"
)

```

2. Create a gRPC connection

```go
clientConn, err := grpc.NewClient("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
```
Comment on lines +246 to +250
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve security and configuration handling

  1. Using insecure credentials is not recommended for production environments.
  2. The gRPC endpoint should be configurable rather than hardcoded.
+// Define configuration variables
+const (
+    defaultGRPCEndpoint = "127.0.0.1:9090"
+)

-clientConn, err := grpc.NewClient("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
+// TODO: In production, use secure credentials
+endpoint := os.Getenv("GRPC_ENDPOINT")
+if endpoint == "" {
+    endpoint = defaultGRPCEndpoint
+}
+clientConn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
clientConn, err := grpc.NewClient("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
```
// Define configuration variables
const (
defaultGRPCEndpoint = "127.0.0.1:9090"
)
// TODO: In production, use secure credentials
endpoint := os.Getenv("GRPC_ENDPOINT")
if endpoint == "" {
endpoint = defaultGRPCEndpoint
}
clientConn, err := grpc.NewClient(endpoint, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}


3. Setup codec and interface registry

```go
// Setup interface registry and register necessary interfaces
interfaceRegistry := codectypes.NewInterfaceRegistry()
banktypes.RegisterInterfaces(interfaceRegistry)
authtypes.RegisterInterfaces(interfaceRegistry)
cryptocodec.RegisterInterfaces(interfaceRegistry)

// Create a ProtoCodec for encoding/decoding
protoCodec := codec.NewProtoCodec(interfaceRegistry)

```

4. Initialize keyring

```go

ckr, err := keyring.New("autoclikeyring", "test", home, nil, protoCodec)
if err != nil {
log.Fatal("error creating keyring", err)
}
kr, err := keyring.NewAutoCLIKeyring(ckr, addrcodec.NewBech32Codec("cosmos"))
if err != nil {
log.Fatal("error creating auto cli keyring", err)
}


```

5. Setup transaction parameters

```go

// Setup transaction parameters
txParams := tx.TxParameters{
ChainID: "simapp-v2-chain",
SignMode: apisigning.SignMode_SIGN_MODE_DIRECT,
AccountConfig: tx.AccountConfig{
FromAddress: "cosmos1t0fmn0lyp2v99ga55mm37mpnqrlnc4xcs2hhhy",
FromName: "alice",
},
}

// Configure gas settings
gasConfig, err := tx.NewGasConfig(100, 100, "0stake")
if err != nil {
log.Fatal("error creating gas config: ", err)
}
txParams.GasConfig = gasConfig

// Create auth query client
authClient := authtypes.NewQueryClient(clientConn)

// Retrieve account information for the sender
fromAccount, err := getAccount("cosmos1t0fmn0lyp2v99ga55mm37mpnqrlnc4xcs2hhhy", authClient, protoCodec)
if err != nil {
log.Fatal("error getting from account: ", err)
}

// Update txParams with the correct account number and sequence
txParams.AccountConfig.AccountNumber = fromAccount.GetAccountNumber()
txParams.AccountConfig.Sequence = fromAccount.GetSequence()

// Retrieve account information for the recipient
toAccount, err := getAccount("cosmos1e2wanzh89mlwct7cs7eumxf7mrh5m3ykpsh66m", authClient, protoCodec)
if err != nil {
log.Fatal("error getting to account: ", err)
}

// Configure transaction settings
txConf, _ := tx.NewTxConfig(tx.ConfigOptions{
AddressCodec: addrcodec.NewBech32Codec("cosmos"),
Cdc: protoCodec,
ValidatorAddressCodec: addrcodec.NewBech32Codec("cosmosval"),
EnabledSignModes: []apisigning.SignMode{apisigning.SignMode_SIGN_MODE_DIRECT},
})
```

6. Build the transaction

```go
// Create a transaction factory
f, err := tx.NewFactory(kr, codec.NewProtoCodec(codectypes.NewInterfaceRegistry()), nil, txConf, addrcodec.NewBech32Codec("cosmos"), clientConn, txParams)
if err != nil {
log.Fatal("error creating factory", err)
}

// Define the transaction message
msgs := []transaction.Msg{
&banktypes.MsgSend{
FromAddress: fromAccount.GetAddress().String(),
ToAddress: toAccount.GetAddress().String(),
Amount: sdk.Coins{
sdk.NewCoin("stake", math.NewInt(1000000)),
},
},
}

// Build and sign the transaction
tx, err := f.BuildsSignedTx(context.Background(), msgs...)
if err != nil {
log.Fatal("error building signed tx", err)
}


```

7. Broadcast the transaction

```go
// Create a broadcaster for the transaction
c, err := comet.NewCometBFTBroadcaster("http://127.0.0.1:26675", comet.BroadcastSync, protoCodec)
if err != nil {
log.Fatal("error creating comet broadcaster", err)
}

// Broadcast the transaction
res, err := c.Broadcast(context.Background(), tx.Bytes())
if err != nil {
log.Fatal("error broadcasting tx", err)
}

```

8. Helpers

```go
// getAccount retrieves account information using the provided address
func getAccount(address string, authClient authtypes.QueryClient, codec codec.Codec) (sdk.AccountI, error) {
// Query account info
accountQuery, err := authClient.Account(context.Background(), &authtypes.QueryAccountRequest{
Address: string(address),
})
if err != nil {
return nil, fmt.Errorf("error getting account: %w", err)
}

// Unpack the account information
var account sdk.AccountI
err = codec.InterfaceRegistry().UnpackAny(accountQuery.Account, &account)
if err != nil {
return nil, fmt.Errorf("error unpacking account: %w", err)
}

return account, nil
}
```
Loading