Invocar un Smart Contract (Go)
Este tutorial muestra la lógica central para invocar una función de smart contract de ULVM usando el SDK de Go.
Usaremos el mismo contrato de ejemplo de ULVM Smart Contract Basics:
testStoreAndRetrieve(value: i32) -> i32testStoreAndRetrieveArray() -> i32
✅ Objetivo: construir una transaction
INVOKE_SMART_CONTRACTdonde:
To= la dirección del contrato- payload = JSON
{ functionName, args, gasLimit }- los args se codifican usando
transaction.Encode(...)
1) Lo que necesitas antes de invocar
Necesitas:
- Un wallet con fondos (o cualquier wallet que pueda enviar txs en tu chain).
- Una dirección de contrato desplegado (el ID de transaction devuelto al desplegar).
- Endpoint del node y blockchainId.
La dirección del contrato es el
TransactionIddevuelto por la transaction de despliegue. Guárdalo en algún lugar — lo usarás comoTo.
2) Crear un wallet (ejemplo)
Este tutorial se centra en la lógica de invocación, por lo que mantendremos la creación del wallet al mínimo.
(También puedes cargarlo desde un archivo .ukey — cualquier enfoque funciona.)
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) Construir el payload de invocación (functionName + args)
El payload de una transaction de invocación de ULVM es un JSON que coincide con:
type InvokeContractPayload struct {
FunctionName string `json:"functionName"`
Args []ContractArgs `json:"args"`
GasLimit uint64 `json:"gasLimit"`
}
type ContractArgs struct {
Value []byte `json:"value"`
}
Ejemplo A — llamar a testStoreAndRetrieve(value: i32)
Esta función del contrato espera un argumento i32.
Idea central:
- Codificar el argumento:
transaction.Encode(int32Value) - Colocarlo dentro de
[]transaction.ContractArgs - Serializar
InvokeContractPayloada bytes JSON
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)
}
Ejemplo B — llamar a testStoreAndRetrieveArray()
Esta función no recibe argumentos, por lo que Args es un slice vacío.
func buildTestStoreAndRetrieveArrayPayload() ([]byte, error) {
payload := transaction.InvokeContractPayload{
FunctionName: "testStoreAndRetrieveArray",
Args: []transaction.ContractArgs{},
GasLimit: 100000,
}
return json.Marshal(payload)
}
4) Crear y enviar la transaction INVOKE
Para invocar un contrato, creas un transaction.ULTransactionInput:
✅ Campos importantes
BlockchainId: el id de tu chainTo: dirección del contratoPayloadType:INVOKE_SMART_CONTRACTPayload: string JSON de tuInvokeContractPayload
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) Ejemplo mínimo completo (lógica central)
Este ejemplo invoca 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>"
// ✅ dirección del contrato devuelta del 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)
}
// Construir invoke payload para 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)
}
Notas y errores comunes
El nombre de la función del contrato debe coincidir exactamente
FunctionName debe coincidir con el nombre de la función AssemblyScript exportada:
export function testStoreAndRetrieve(value: i32): i32 { ... }
Por lo tanto, en Go, usa:
FunctionName: "testStoreAndRetrieve"
To debe ser la dirección del contrato
Para llamadas a contratos:
To= contractAddressFrom= la dirección de tu wallet
Gas limit
Si no estás seguro, comienza con algo como 100000 para ejemplos básicos y ajústalo más adelante.
Próximos pasos
- Continúa con: **Tokens ERC-20 con el SDK de Go (Go)