Transfer funds with Golang
This document gives instructions and examples on how to use our pkg/client
package to broadcast
transactions and query the Coreum blockchain using Go programming language.
Complete code
Complete code with go.mod
file you can find
here
P.S. If you have issues with go mod tidy
command, just copy go.mod
file from the example above.
Go code skeleton
Imports and main function
Create standard main.go
file containing this skeleton importing pkg/client
:
package main
import (
"github.com/CoreumFoundation/coreum/v3/pkg/client"
coreumconfig "github.com/CoreumFoundation/coreum/v3/pkg/config"
"github.com/CoreumFoundation/coreum/v3/pkg/config/constant"
)
const (
senderMnemonic = "" // put mnemonic here
chainID = constant.ChainIDTest
addressPrefix = constant.AddressPrefixTest
denom = constant.DenomTest
recipientAddress = "testcore1534s8rz2e36lwycr6gkm9vpfe5yf67wkuca7zs"
nodeAddress = "full-node.testnet-1.coreum.dev:9090"
)
func main() {
}
Preparing test account
Before you may broadcast transactions, you need to have access to a funded account. Normally you would create a private key stored securely in local keystore. Here, for simplicity, we will use private key generated by our faucet. Never ever use mnemonic directly in code and never ever use key generated by faucet in production. It might cause complete funds loss! Please reference keyring documentation to learn on using keyring: run node keyring and crypto keyring.
To get funded account, go to our faucet website and click on "Generate Funded Wallet" button in "Testnet" section.
In response, you get your wallet address on our testnet chain and mnemonic used to generate the
private key. Assign mnemonic to the constant senderMnemonic
in the code snippet above.
Setting Cosmos SDK configuration
First we need to configure Cosmos SDK:
config := sdk.GetConfig()
config.SetBech32PrefixForAccount(addressPrefix, addressPrefix+"pub")
config.SetCoinType(constant.CoinType)
config.Seal()
Preparing client context and tx factory
Before we are able to broadcast transaction, we must create and configure client context and tx factory:
modules := module.NewBasicManager(
auth.AppModuleBasic{},
)
// If you don't use TLS then replace `grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12}))` with `grpc.WithInsecure()`
grpcClient, err := grpc.Dial(nodeAddress, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})))
if err != nil {
panic(err)
}
encodingConfig := coreumconfig.NewEncodingConfig(modules)
clientCtx := client.NewContext(client.DefaultContextConfig(), modules).
WithChainID(string(chainID)).
WithGRPCClient(grpcClient).
WithKeyring(keyring.NewInMemory(encodingConfig.Codec)).
WithBroadcastMode(flags.BroadcastSync)
txFactory := client.Factory{}.
WithKeybase(clientCtx.Keyring()).
WithChainID(clientCtx.ChainID()).
WithTxConfig(clientCtx.TxConfig()).
WithSimulateAndExecute(true)
Generate private key
To sign a transaction, private key generated from mnemonic stored in senderMnemonic
is required.
We store that key in the temporary keystore. In production you should use any keyring other than
memory
or test
. Good choice might be os
or file
. For more details, refer keyring
documentation: run node keyring and crypto keyring.
senderInfo, err := clientCtx.Keyring().NewAccount(
"key-name",
senderMnemonic,
"",
sdk.GetConfig().GetFullBIP44Path(),
hd.Secp256k1,
)
if err != nil {
panic(err)
}
Getting the account address
Account address is the part of senderInfo
structure. It might be accessed using this code:
senderAddress, err := senderInfo.GetAddress()
if err != nil {
panic(err)
}
fmt.Println(senderAddress.String())
Output:
testcore1zuelfk5fz02v9x7gnsy2t7ps83m8vljx5wqdfq
Validating the address
Address may be validated using this code:
_, err = sdk.AccAddressFromBech32(senderInfo.GetAddress().String())
if err != nil {
panic(err)
}
Broadcasting transaction
Now we are ready to broadcast transaction. As an example we send 9000000utestcore
tokens from your
wallet to recipientAddress
:
msg := &banktypes.MsgSend{
FromAddress: senderInfo.GetAddress().String(),
ToAddress: recipientAddress,
Amount: sdk.NewCoins(sdk.NewInt64Coin(denom, 9_000_000)),
}
ctx := context.Background()
result, err := client.BroadcastTx(
ctx,
clientCtx.WithFromAddress(senderInfo.GetAddress()),
txFactory,
msg,
)
if err != nil {
panic(err)
}
fmt.Printf("Tx hash: %s\n", result.TxHash)
After executing this code, you will see output like this:
Tx hash: 8C694A92A2208DB8CE733D54C22A3C7F945D54867B9078D08686DC7DBF0F44DC
You may copy transaction hash and paste it in the search box of our block explorer to confirm the transaction execution and check its properties.
Querying the balance
Now you may query the balance of your account:
bankClient := banktypes.NewQueryClient(clientCtx)
balances, err := bankClient.AllBalances(ctx, &banktypes.QueryAllBalancesRequest{
Address: recipientAddress,
})
if err != nil {
panic(err)
}
fmt.Printf("Balances: %s\n", balances.Balances)
After executing it should produce output like:
Balances: 9000000utestcore