Saltar al contenido principal

Invocar un Smart Contract (TypeScript)

Este tutorial muestra la lógica principal para invocar una función de smart contract de ULVM usando el SDK de TypeScript de ULedger (respaldado por WASM).

Usaremos el mismo contrato de ejemplo de ULVM Smart Contract Basics:

  • testStoreAndRetrieve(value: i32) -> i32
  • testStoreAndRetrieveArray() -> i32

✅ Objetivo: enviar una transacción INVOKE_SMART_CONTRACT donde:

  • contractAddress = la dirección del contrato desplegado
  • functionName = nombre de la función exportada
  • args = Array<string | Uint8Array>
  • gasLimit = número opcional

En el SDK de TypeScript, generalmente se invoca mediante:

  • session.invokeContract({ blockchainId, contractAddress, functionName, args, gasLimit })

en lugar de construir ULTransactionInput manualmente.


1) Lo que necesitas antes de invocar

Necesitas:

  1. Un wallet que pueda enviar transacciones en tu chain.
  2. Una dirección de contrato desplegado (el mismo contractAddress que usaste durante el despliegue).
  3. Endpoint del node y blockchainId.
info

En muchas chains, tu wallet debe estar registrado en la chain antes de poder enviar llamadas a contratos.

Si ves REJECTED_BY_UNAUTHORIZED, regístrate primero:

await session.registerWallet(blockchainId);

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 restaurarlo desde un JSON que guardaste previamente.)

import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";

const sdk = await getULedgerSDK();

// Genera un wallet (en producción, probablemente lo persistirás/restaurarás en su lugar)
const wallet = sdk.generateWallet({ keyType: KeyType.Secp256k1 });

console.log("Wallet address:", wallet.address);

3) Crear una sesión de transacción

Usa el helper del SDK para crear una sesión inicializada.

const nodeEndpoint = "https://tn-w-1.uledger.net/";
const blockchainId = "08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2";

const session = await sdk.createSession(nodeEndpoint, wallet);

4) Invocar el contrato

Ejemplo A — llamar a testStoreAndRetrieveArray() (sin args)

const contractAddress = "<YOUR_CONTRACT_ADDRESS>";

const tx = await session.invokeContract({
blockchainId,
contractAddress,
functionName: "testStoreAndRetrieveArray",
args: [], // opcional; vacío está bien
gasLimit: 100000, // opcional
});

console.log("Invoke tx id:", tx.transactionId);
console.log("Status:", tx.status, "| Output:", tx.output);

Ejemplo B — llamar a testStoreAndRetrieve(value: i32) (un arg)

El SDK de TypeScript acepta args como string o Uint8Array.

Si tu contrato espera un i32 sin procesar, puedes codificar un entero de 32 bits en 4 bytes (little-endian es una convención común):

function i32LE(n: number): Uint8Array {
const buf = new ArrayBuffer(4);
new DataView(buf).setInt32(0, n, true);
return new Uint8Array(buf);
}

const tx = await session.invokeContract({
blockchainId,
contractAddress,
functionName: "testStoreAndRetrieve",
args: [i32LE(123)],
gasLimit: 100000,
});

console.log("Invoke tx id:", tx.transactionId);
console.log("Status:", tx.status, "| Output:", tx.output);

Si tu runtime de ULVM requiere un serializador específico (como el transaction.Encode(...) de Go), usa el equivalente del SDK de TypeScript si existe en tu build. Según el transaction.d.ts que compartiste, un helper Encode(...) no está actualmente expuesto en la superficie de TS, por lo que esta guía usa un ejemplo simple de codificación de bytes.


5) Ejemplo mínimo completo (lógica principal)

Este ejemplo invoca testStoreAndRetrieve(123).

import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";

function i32LE(n: number): Uint8Array {
const buf = new ArrayBuffer(4);
new DataView(buf).setInt32(0, n, true);
return new Uint8Array(buf);
}

async function main() {
const sdk = await getULedgerSDK();

const wallet = sdk.generateWallet({ keyType: KeyType.Secp256k1 });

const nodeEndpoint = "https://tn-w-1.uledger.net/";
const blockchainId = "08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2";

const session = await sdk.createSession(nodeEndpoint, wallet);

// Si obtienes REJECTED_BY_UNAUTHORIZED, descomenta:
// await session.registerWallet(blockchainId);

const contractAddress = "<YOUR_CONTRACT_ADDRESS>";

const tx = await session.invokeContract({
blockchainId,
contractAddress,
functionName: "testStoreAndRetrieve",
args: [i32LE(123)],
gasLimit: 100000,
});

console.log("Invoke tx id:", tx.transactionId);
console.log("Status:", tx.status, "| Output:", tx.output);
}

main().catch((e) => {
console.error("Invoke failed:", e);
process.exit(1);
});

Notas y errores comunes

El nombre de la función debe coincidir exactamente

functionName debe coincidir con el nombre de la función ULVM exportada:

export function testStoreAndRetrieve(value: i32): i32 { ... }

Por lo tanto, en TypeScript:

functionName: "testStoreAndRetrieve"

Dirección del contrato

En el SDK de TypeScript, invokeContract() recibe contractAddress directamente.

Usa la misma dirección del contrato a la que desplegaste (el valor que pasaste como contractAddress durante el despliegue).

Gas limit

Si no estás seguro, comienza con aproximadamente 100000 para ejemplos básicos y ajústalo después.


Próximos pasos

  • Continúa con: **Tokens ERC-20 con el SDK de Go (TS)