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) -> i32testStoreAndRetrieveArray() -> i32
✅ Objetivo: enviar una transacción
INVOKE_SMART_CONTRACTdonde:
contractAddress= la dirección del contrato desplegadofunctionName= nombre de la función exportadaargs=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
ULTransactionInputmanualmente.
1) Lo que necesitas antes de invocar
Necesitas:
- Un wallet que pueda enviar transacciones en tu chain.
- Una dirección de contrato desplegado (el mismo
contractAddressque usaste durante el despliegue). - Endpoint del node y blockchainId.
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 eltransaction.d.tsque compartiste, un helperEncode(...)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)