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