go get -v github.com/Concordium/concordium-go-sdkThe core structure of the SDK is the Client which maintains a connection to the node and supports querying the node and sending messages to it.
See examples in v2/examples/ for example usage.
There are two helping packets with high-level wrappers for making transactions with minimal user input. These wrappers handle encoding, setting energy costs when those are fixed for the transaction.
Functions from github.com/Concordium/concordium-go-sdk/v2/transactions/construct packet build PreAccountTransaction.
PreAccountTransaction is an AccountTransaction without signatures. To get a signed transaction you can use PreAccountTransaction.Sign(TransactionSigner)
with the transmitted implementation of the TransactionSigner interface.
// TransactionSigner is an interface for signing transactions.
type TransactionSigner interface {
// SignTransactionHash signs transaction hash and returns signatures in TransactionSignature type.
SignTransactionHash(hashToSign *TransactionHash) (*AccountTransactionSignature, error)
}Functions from github.com/Concordium/concordium-go-sdk/v2/transactions/send packet build AccountTransaction.
AccountTransaction already has signatures, but the first parameter in constructing functions from send packet must implement the
ExactSizeTransactionSigner interface.
// ExactSizeTransactionSigner describes TransactionSigner with ability to return number of signers.
type ExactSizeTransactionSigner interface {
TransactionSigner
// NumberOfKeys returns number of signers.
NumberOfKeys() uint32
}For signature with only one private key, you can use the WalletAccount struct.
To create WalletAccount with one private key just call NewWalletAccount
with the account address and key pair. To create WalletAccount with one or more
keys, you can add a key pair to the existing WalletAccount using the method AddKeyPair
of call NewWalletAccountFromFile to read credentials from the <account_address>.export file.
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/Concordium/concordium-go-sdk/v2"
"github.com/Concordium/concordium-go-sdk/v2/transactions/construct"
)
func main() {
pathToExportFile := "PATH_TO_YOUR_EXPORT_FILE"
walletAccount, err := v2.NewWalletAccountFromFile(pathToExportFile)
if err != nil {
log.Fatalf("couldn't create wallet account, err: %v", err)
}
receiver, err := v2.AccountAddressFromString("RECEIVER_ADDRESS_IN_BASE58_CHECK")
if err != nil {
log.Fatalf("couldn't decode receiver address, err: %v", err)
}
ctx := context.Background()
client, err := v2.NewClient(v2.Config{NodeAddress: "node.testnet.concordium.com:20000"})
if err != nil {
log.Fatalf("couldn't create node client, err: %v", err)
}
sequenceNumber, err := client.GetNextAccountSequenceNumber(ctx, walletAccount.Address)
if err != nil {
log.Fatalf("failed to get next sender sequnce number, err: %v", err)
}
nonce := v2.SequenceNumber{Value: sequenceNumber.SequenceNumber.Value}
expiry := v2.TransactionTime{Value: uint64(time.Now().Add(time.Hour).UTC().Unix())}
amount := v2.Amount{Value: 100} // 100 micro CCD.
preAccountTransaction := construct.Transfer(
walletAccount.NumberOfKeys(),
*walletAccount.Address,
nonce,
expiry,
receiver,
amount,
)
accountTransaction, err := preAccountTransaction.Sign(walletAccount)
if err != nil {
log.Fatalf("couldn't sign transction, err: %v", err)
}
txHash, err := accountTransaction.Send(ctx, client)
if err != nil {
log.Fatalf("couldn't send block item, err: %v", err)
}
fmt.Printf("Success! Transaction hash: %s", txHash.Hex())
}package main
import (
"context"
"fmt"
"log"
"time"
"github.com/Concordium/concordium-go-sdk/v2"
"github.com/Concordium/concordium-go-sdk/v2/transactions/send"
)
func main() {
pathToExportFile := "PATH_TO_YOUR_EXPORT_FILE"
walletAccount, err := v2.NewWalletAccountFromFile(pathToExportFile)
if err != nil {
log.Fatalf("couldn't create wallet account, err: %v", err)
}
receiver, err := v2.AccountAddressFromString("RECEIVER_ADDRESS_IN_BASE58_CHECK")
if err != nil {
log.Fatalf("couldn't decode receiver address, err: %v", err)
}
ctx := context.Background()
client, err := v2.NewClient(v2.Config{NodeAddress: "node.testnet.concordium.com:20000"})
if err != nil {
log.Fatalf("couldn't create node client, err: %v", err)
}
sequenceNumber, err := client.GetNextAccountSequenceNumber(ctx, walletAccount.Address)
if err != nil {
log.Fatalf("failed to get next sender sequnce number, err: %v", err)
}
nonce := v2.SequenceNumber{Value: sequenceNumber.SequenceNumber.Value}
expiry := v2.TransactionTime{Value: uint64(time.Now().Add(time.Hour).UTC().Unix())}
amount := v2.Amount{Value: 100} // 100 micro CCD.
accountTransaction, err := send.Transfer(
walletAccount,
*walletAccount.Address,
nonce,
expiry,
receiver,
amount,
)
if err != nil {
log.Fatalf("couldn't build account transction, err: %v", err)
}
txHash, err := accountTransaction.Send(ctx, client)
if err != nil {
log.Fatalf("couldn't send block item, err: %v", err)
}
fmt.Printf("Success! Transaction hash: %s", txHash.Hex())
}All RPC interfaces follow the concordium protocol docs.
For more examples, see the v2/examples/ or v2/tests/ folders.
To update the generated protobuf files, ensure that you have the GRPC API repository pulled down:
git submodule update --init --recursiveThen ensure that you have the prerequisite tooling installed for protobuf. First install the Protobuf compiler, then install the Go and Go GRPC protobuf plugins:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latestBe sure to add ~/go/bin to your path, where these executables are installed.
Then, to generate the protobuf files, run the following command:
protoc --go_out=./v2 --go-grpc_out=./v2 --proto_path=concordium-grpc-api concordium-grpc-api/v2/concordium/*.proto
Now, you should be able to easily build the project:
go build ./v2