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) Requisitos antes de invocar
Se necesita:
- Una billetera que pueda enviar transacciones en la chain.
- Una dirección de contrato desplegado (el mismo
contractAddressque se usó durante el despliegue). - Endpoint del node y blockchainId.
En muchas chains, la billetera debe estar registrada en la chain antes de poder enviar llamadas a contratos.
Si aparece REJECTED_BY_UNAUTHORIZED, se debe registrar la billetera primero:
await session.registerWallet(blockchainId);
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 restaurar desde un JSON guardado previamente.)
import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";
const sdk = await getULedgerSDK();
// Genera una billetera (en producción, probablemente se persiste o se restaura en su lugar)
const wallet = sdk.generateWallet({ keyType: KeyType.Secp256k1 });
console.log("Wallet address:", wallet.address);
3) Crear una sesión de transacción
Se usa el helper del SDK para crear una sesión inicializada.
const nodeEndpoint = "https://your-node-url";
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 el contrato espera un i32 sin procesar, se puede 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);
El SDK de TypeScript no expone un helper
Encode(...)equivalente altransaction.Encode(...)de Go. Esta guía usa en su lugar una codificación directa de bytes. Si el runtime de ULVM requiere un serializador específico, se debe aplicar antes de pasar los bytes del argumento.
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://your-node-url";
const blockchainId = "08c28f29a62819120958984b761ddf8ccb45951612731409873994958fd150a2";
const session = await sdk.createSession(nodeEndpoint, wallet);
// Si se obtiene REJECTED_BY_UNAUTHORIZED, se debe descomentar:
// 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 solución de problemas
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.
Se debe usar la misma dirección del contrato al que se desplegó (el valor pasado como contractAddress durante el despliegue).
Gas limit
Se recomienda comenzar con 100000 para contratos simples y aumentarlo en contratos que realizan muchas llamadas de almacenamiento. El rango válido es 100000–10000000.
Próximos pasos
- Continuar con: **Tokens ERC-20 con el SDK de Go (TS)