Invoke a Smart Contract (Go)
This tutorial shows the core logic to invoke a ULVM smart contract function using the Go SDK.
We’ll use the same example contract from ULVM Smart Contract Basics:
testStoreAndRetrieve(value: i32) -> i32testStoreAndRetrieveArray() -> i32
✅ Goal: build an
INVOKE_SMART_CONTRACTtransaction where:
To= the contract address- payload = JSON
{ functionName, args, gasLimit }- args are encoded using
transaction.Encode(...)
1) What you need before invoking
You need:
- A funded wallet (or any wallet that can submit txs on your chain).
- A deployed contract address (the transaction ID returned from deploy).
- Node endpoint and blockchainId.
The contract address is the
TransactionIdreturned by the deploy transaction. Save it somewhere — you’ll use it asTo.
2) Create a wallet (example)
This tutorial focuses on invocation logic, so we’ll keep wallet creation minimal.
(You can also load from a .ukey file — either approach works.)
import (
"fmt"
"github.com/ULedgerInc/go-sdk/pkg/crypto"
"github.com/ULedgerInc/go-sdk/pkg/wallet"
)
privateKeyHex := "<YOUR_PRIVATE_KEY_HEX>"
publicKeyHex := "<YOUR_PUBLIC_KEY_HEX>"
w, err := wallet.GetWalletFromHex(publicKeyHex, privateKeyHex, crypto.KeyTypeSecp256k1)
if err != nil {
return fmt.Errorf("GetWalletFromHex() error: %w", err)
}
3) Build the invoke payload (functionName + args)
A ULVM invoke transaction payload is JSON that matches:
type InvokeContractPayload struct {
FunctionName string `json:"functionName"`
Args []ContractArgs `json:"args"`
GasLimit uint64 `json:"gasLimit"`
}
type ContractArgs struct {
Value []byte `json:"value"`
}
Example A — call testStoreAndRetrieve(value: i32)
This contract function expects one i32 argument.
Core idea:
- Encode the argument:
transaction.Encode(int32Value) - Put it inside
[]transaction.ContractArgs - Marshal
InvokeContractPayloadto JSON bytes
import (
"encoding/json"
"github.com/ULedgerInc/go-sdk/pkg/transaction"
)
func buildTestStoreAndRetrievePayload(value int32) ([]byte, error) {
encoded, err := transaction.Encode(value)
if err != nil {
return nil, err
}
payload := transaction.InvokeContractPayload{
FunctionName: "testStoreAndRetrieve",
Args: []transaction.ContractArgs{
{Value: encoded},
},
GasLimit: 100000,
}
return json.Marshal(payload)
}
Example B — call testStoreAndRetrieveArray()
This function takes no arguments, so Args is an empty slice.
func buildTestStoreAndRetrieveArrayPayload() ([]byte, error) {
payload := transaction.InvokeContractPayload{
FunctionName: "testStoreAndRetrieveArray",
Args: []transaction.ContractArgs{},
GasLimit: 100000,
}
return json.Marshal(payload)
}
4) Create and submit the INVOKE transaction
To invoke a contract, you create a transaction.ULTransactionInput:
✅ Important fields
BlockchainId: your chain idTo: contract addressPayloadType:INVOKE_SMART_CONTRACTPayload: JSON string of yourInvokeContractPayload
import (
"github.com/ULedgerInc/go-sdk/pkg/transaction"
)
func invokeContract(
nodeEndpoint string,
blockchainId string,
contractAddress string,
w wallet.UL_Wallet,
payloadBytes []byte,
) (transaction.ULTransaction, error) {
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: w.Address,
To: contractAddress,
PayloadType: transaction.INVOKE_SMART_CONTRACT.String(),
Payload: string(payloadBytes),
}
session, err := transaction.NewUL_TransactionSession(nodeEndpoint, w)
if err != nil {
return transaction.ULTransaction{}, err
}
return session.GenerateTransaction(input)
}
5) Full minimal example (core logic)
This example invokes testStoreAndRetrieve(123).
package main
import (
"encoding/json"
"fmt"
"github.com/ULedgerInc/go-sdk/pkg/crypto"
"github.com/ULedgerInc/go-sdk/pkg/transaction"
"github.com/ULedgerInc/go-sdk/pkg/wallet"
)
func main() {
nodeEndpoint := "http://localhost:8080"
blockchainId := "<YOUR_BLOCKCHAIN_ID>"
// ✅ contract address returned from deploy tx.TransactionId
contractAddress := "<YOUR_CONTRACT_ADDRESS>"
privateKeyHex := "<YOUR_PRIVATE_KEY_HEX>"
publicKeyHex := "<YOUR_PUBLIC_KEY_HEX>"
w, err := wallet.GetWalletFromHex(publicKeyHex, privateKeyHex, crypto.KeyTypeSecp256k1)
if err != nil {
panic(err)
}
// Build invoke payload for testStoreAndRetrieve(123)
payloadBytes, err := buildTestStoreAndRetrievePayload(123)
if err != nil {
panic(err)
}
input := transaction.ULTransactionInput{
BlockchainId: blockchainId,
From: w.Address,
To: contractAddress,
PayloadType: transaction.INVOKE_SMART_CONTRACT.String(),
Payload: string(payloadBytes),
}
session, err := transaction.NewUL_TransactionSession(nodeEndpoint, w)
if err != nil {
panic(err)
}
tx, err := session.GenerateTransaction(input)
if err != nil {
panic(err)
}
fmt.Printf("Invoke tx id: %s\n", tx.TransactionId)
fmt.Printf("Status: %s | Output: %s\n", tx.Status, tx.Output)
}
func buildTestStoreAndRetrievePayload(value int32) ([]byte, error) {
encoded, err := transaction.Encode(value)
if err != nil {
return nil, err
}
payload := transaction.InvokeContractPayload{
FunctionName: "testStoreAndRetrieve",
Args: []transaction.ContractArgs{
{Value: encoded},
},
GasLimit: 100000,
}
return json.Marshal(payload)
}
Notes and common gotchas
Contract function name must match exactly
FunctionName must match the exported AssemblyScript function name:
export function testStoreAndRetrieve(value: i32): i32 { ... }
So in Go, use:
FunctionName: "testStoreAndRetrieve"
To must be the contract address
For contract calls:
To= contractAddressFrom= your wallet address
Gas limit
If you’re unsure, start with something like 100000 for basic examples and adjust later.
Next steps
- Move on to: **ERC-20 Tokens with the Go SDK (Go)