Saltar al contenido principal

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) -> i32
  • testStoreAndRetrieveArray() -> i32

✅ Objetivo: construir una transaction INVOKE_SMART_CONTRACT donde:

  • To = la dirección del contrato
  • payload = JSON { functionName, args, gasLimit }
  • los args se codifican usando transaction.Encode(...)

1) Lo que se necesita antes de invocar​

Se necesita:

  1. Una billetera con fondos (o cualquier billetera que pueda enviar txs en la chain).
  2. Una dirección de contrato desplegado (el ID de transaction devuelto al desplegar).
  3. Endpoint del node y blockchainId.

La dirección del contrato es el TransactionId devuelto por la transaction de despliegue. Se debe guardar porque se usará como To.


2) Crear una billetera (ejemplo)​

Este tutorial se centra en la lógica de invocación, por lo que mantendremos la creación de la billetera al mínimo. (También se puede cargar desde un archivo .ukey, y cualquiera de los dos enfoques 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:

  1. Codificar el argumento: transaction.Encode(int32Value)
  2. Colocarlo dentro de []transaction.ContractArgs
  3. Serializar InvokeContractPayload a 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, se crea un transaction.ULTransactionInput:

✅ Campos importantes

  • BlockchainId: el id de la chain
  • To: dirección del contrato
  • PayloadType: INVOKE_SMART_CONTRACT
  • Payload: string JSON del InvokeContractPayload
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 solución de problemas​

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 se usa:

FunctionName: "testStoreAndRetrieve"

To debe ser la dirección del contrato​

Para llamadas a contratos:

  • To = contractAddress
  • From = la dirección de la billetera

Gas limit​

Se recomienda comenzar con 100000 para contratos simples y aumentarlo en contratos que realicen muchas llamadas de almacenamiento. El rango válido es 100000–10000000.


Próximos pasos​

  • Continuar con: **Tokens ERC-20 con el SDK de Go (Go)