github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/docs/how-to-guides/connecting-from-go.md (about)

     1  ---
     2  id: connect-from-go
     3  ---
     4  
     5  # How to connect a Go app to Gno.land 
     6  
     7  This guide will show you how to connect to a Gno.land network from your Go application,
     8  using the [gnoclient](../reference/gnoclient/gnoclient.md) package.
     9  
    10  For this guide, we will build a small Go app that will:
    11  
    12  - Get account information from the chain
    13  - Broadcast a state-changing transaction
    14  - Read on-chain state
    15  
    16  ## Prerequisites
    17  - A local Gno.land keypair generated using
    18  [gnokey](../getting-started/local-setup/working-with-key-pairs.md)
    19  
    20  ## Setup
    21  
    22  To get started, create a new Go project. In a clean directory, run the following:
    23  ```bash
    24  go mod init example
    25  ```
    26  
    27  After this, create a new `main.go` file:
    28  
    29  ```bash
    30  touch main.go
    31  ```
    32  
    33  Set up your main file with the code below:
    34  
    35  ```go
    36  package main
    37  
    38  func main() {}
    39  ```
    40  
    41  Finally, add the `gnoclient` package by running the following command:
    42  
    43  ```bash
    44  go get github.com/gnolang/gno/gno.land/pkg/gnoclient
    45  ```
    46  
    47  ## Main components
    48  
    49  The `gnoclient` package exposes a `Client` struct containing a `Signer` and 
    50  `RPCClient` connector. `Client` exposes all available functionality for talking
    51  to a Gno.land chain.
    52  
    53  ```go 
    54  type Client struct {
    55      Signer    Signer           // Signer for transaction authentication
    56      RPCClient rpcclient.Client // gnolang/gno/tm2/pkg/bft/rpc/client
    57  }
    58  ```
    59  
    60  ### Signer
    61  
    62  The `Signer` provides functionality to sign transactions with a Gno.land keypair.
    63  The keypair can be accessed from a local keybase, or it can be generated 
    64  in-memory from a BIP39 mnemonic.
    65  
    66  :::info
    67  The keybase directory path is set with the `gnokey --home` flag. 
    68  :::
    69  
    70  ### RPCClient
    71  
    72  The `RPCCLient` provides connectivity to a Gno.land network via HTTP or WebSockets.
    73  
    74  
    75  ## Initialize the Signer
    76  
    77  For this example, we will initialize the `Signer` from a local keybase: 
    78  
    79  ```go
    80  package main
    81  
    82  import (
    83  	"github.com/gnolang/gno/gno.land/pkg/gnoclient"
    84  	"github.com/gnolang/gno/tm2/pkg/crypto/keys"
    85  )
    86  
    87  func main() {
    88  	// Initialize keybase from a directory
    89  	keybase, _ := keys.NewKeyBaseFromDir("path/to/keybase/dir")
    90  
    91  	// Create signer
    92  	signer := gnoclient.SignerFromKeybase{
    93  		Keybase:  keybase,
    94  		Account:  "<keypair_name>",     // Name of your keypair in keybase
    95  		Password: "<keypair_password>", // Password to decrypt your keypair 
    96  		ChainID:  "<gno_chainID>",      // id of Gno.land chain
    97  	}
    98  }
    99  ```
   100  
   101  A few things to note:
   102  - You can view keys in your local keybase by running `gnokey list`.  
   103  - You can get the password from a user input using the IO package.
   104  - `Signer` can also be initialized in-memory from a BIP39 mnemonic, using the 
   105  [`SignerFromBip39`](../reference/gnoclient/signer.md#func-signerfrombip39) function.
   106  
   107  ## Initialize the RPC connection & Client
   108  
   109  You can initialize the RPC Client used to connect to the Gno.land network with
   110  the following line:
   111  ```go
   112  rpc := rpcclient.NewHTTPClient("<gno_chain_endpoint>")
   113  ```
   114  
   115  A list of Gno.land network endpoints & chain IDs can be found in the [Gno RPC 
   116  endpoints](../reference/rpc-endpoints.md#network-configurations) page. 
   117  
   118  With this, we can initialize the `gnoclient.Client` struct: 
   119  
   120  ```go
   121  package main
   122  
   123  import (
   124  	"github.com/gnolang/gno/gno.land/pkg/gnoclient"
   125  	"github.com/gnolang/gno/tm2/pkg/crypto/keys"
   126  	rpcclient "github.com/gnolang/gno/tm2/pkg/bft/rpc/client"
   127  )
   128  
   129  func main() {
   130  	// Initialize keybase from a directory
   131  	keybase, _ := keys.NewKeyBaseFromDir("path/to/keybase/dir")
   132  
   133  	// Create signer
   134  	signer := gnoclient.SignerFromKeybase{
   135  		Keybase:  keybase,
   136  		Account:  "<keypair_name>",     // Name of your keypair in keybase
   137  		Password: "<keypair_password>", // Password to decrypt your keypair 
   138  		ChainID:  "<gno_chainID>",      // id of Gno.land chain
   139  	}
   140  
   141  	// Initialize the RPC client
   142  	rpc := rpcclient.NewHTTPClient("<gno.land_remote_endpoint>")
   143  	
   144  	// Initialize the gnoclient
   145  	client := gnoclient.Client{
   146  		Signer:    signer,
   147  		RPCClient: rpc,
   148  	}
   149  }
   150  ```
   151  
   152  We can now communicate with the Gno.land chain. Let's explore some of the functionality
   153  `gnoclient` provides.
   154  
   155  ## Query account info from a chain
   156  
   157  To send transactions to the chain, we need to know the account number (ID) and 
   158  sequence (nonce). We can get this information by querying the chain with the
   159  `QueryAccount` function:
   160  
   161  ```go
   162  // Convert Gno address string to `crypto.Address`
   163  addr, err := crypto.AddressFromBech32("g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5") // your Gno address
   164  if err != nil {
   165  	panic(err)
   166  }
   167  
   168  accountRes, _, err := client.QueryAccount(addr)
   169  if err != nil {
   170      panic(err)
   171  }
   172  ```
   173  
   174  An example result would be as follows:
   175  
   176  ```go
   177  fmt.Println(accountRes)
   178  // Output:
   179  // Account:
   180  //  Address:       g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5
   181  //  Pubkey:
   182  //  Coins:         9999862000000ugnot
   183  //  AccountNumber: 0
   184  //  Sequence:      0
   185  ```
   186  
   187  We are now ready to send a transaction to the chain.
   188  
   189  ## Sending a transaction
   190  
   191  A Gno.land transaction consists of two main parts:
   192  - A set of base transaction fields, such as a gas price, gas limit, account &
   193  sequence number,
   194  - An array of messages to be executed on the chain.
   195  
   196  To construct the base set of transaction fields, we can use the `BaseTxCfg` type:
   197  ```go
   198  txCfg := gnoclient.BaseTxCfg{
   199      GasFee:         "1000000ugnot",                 // gas price
   200      GasWanted:      1000000,                        // gas limit
   201      AccountNumber:  accountRes.GetAccountNumber(),  // account ID
   202      SequenceNumber: accountRes.GetSequence(),       // account nonce
   203      Memo:           "This is a cool how-to guide!", // transaction memo
   204  }
   205  ```
   206  
   207  For calling an exported (public) function in a Gno realm, we can use the `MsgCall`
   208  message type. We will use the wrapped ugnot realm for this example, wrapping 
   209  `1000000ugnot` (1 $GNOT) for demonstration purposes.
   210  
   211  ```go
   212  msg := gnoclient.MsgCall{
   213      PkgPath:  "gno.land/r/demo/wugnot", // wrapped ugnot realm path
   214      FuncName: "Deposit",                // function to call
   215      Args:     nil,                      // arguments in string format
   216      Send:     "1000000ugnot",           // coins to send along with transaction
   217  }
   218  ```
   219  
   220  Finally, to actually call the function, we can use `Call`:
   221  
   222  ```go
   223  res, err := client.Call(txCfg, msg)
   224  if err != nil {
   225  	panic(err)
   226  }
   227  ```
   228  
   229  Before running your code, make sure your keypair has enough funds to send the 
   230  transaction. 
   231  
   232  If everything went well, you've just sent a state-changing transaction to a 
   233  Gno.land chain!
   234  
   235  
   236  ## Reading on-chain state
   237  
   238  To read on-chain state, you can use the `QEval()` function. This functionality
   239  allows you to evaluate a query expression on a realm, without having to spend gas.
   240  
   241  Let's fetch the balance of wrapped ugnot for our address:
   242  ```go
   243  // Evaluate expression
   244  qevalRes, _, err := client.QEval("gno.land/r/demo/wugnot", "BalanceOf(\"g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5\")")
   245  if err != nil {
   246  	panic(err)
   247  }
   248  ```
   249  
   250  Printing out the result should output:
   251  ```go
   252  fmt.Println(qevalRes)
   253  // Output:
   254  // (1000000 uint64)
   255  ```
   256  
   257  To see all functionality the `gnoclient` package provides, see the gnoclient
   258  [reference page](../reference/gnoclient/gnoclient.md).
   259  
   260  ## Conclusion
   261  
   262  Congratulations 🎉
   263  
   264  You've just built a small demo app in Go that connects to a Gno.land chain
   265  to query account info, send a transaction, and read on-chain state.
   266  
   267  Check out the full example app code [here](https://github.com/leohhhn/connect-gno/blob/master/main.go). 
   268  
   269  To see a real-world example CLI tool use `gnoclient`,
   270  check out [gnoblog-cli](https://github.com/gnolang/blog/tree/main/cmd/gnoblog-cli).
   271  
   272