Desplegar Smart Contracts (TypeScript)
Esta guía muestra los pasos principales para desplegar un smart contract ULVM usando el SDK de TypeScript de ULedger.
Pasos:
- Inicializar el SDK
- Cargar o generar una billetera (el firmante)
- Leer el archivo
.watdel contrato - Crear una sesión de transaction hacia un node
- Enviar una transaction
DEPLOY_SMART_CONTRACT
En muchas chains, la billetera debe estar registrada on-chain antes de poder desplegar contratos.
Si se obtiene REJECTED_BY_UNAUTHORIZED, se debe registrar la billetera primero (ver la nota en el Paso 5).
1. Requisitos previos
Se necesita:
nodeEndpoint(ejemplo:http://localhost:8080)blockchainId- Una billetera que pueda firmar transactions
- El contrato como archivo
.wat(texto de WebAssembly), por ejemploauction.wat
2. Inicializar el SDK y cargar una billetera
import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";
const sdk = await getULedgerSDK();
// Opción A: generar una nueva billetera
const wallet = sdk.generateWallet({ keyType: KeyType.Secp256k1 });
// Opción B: restaurar desde mnemonic / JSON (ejemplos)
// const wallet = sdk.walletFromMnemonic(mnemonic, { keyType: KeyType.Secp256k1 });
// const wallet = sdk.walletFromJson(walletJsonString);
3. Leer el código fuente del contrato
Se recomienda desplegar el contrato como un archivo .wat (texto de WebAssembly).
import { readFile } from "node:fs/promises";
const wat = await readFile("./auction.wat", "utf8");
const contractSource = wat;
4. Elegir una dirección de contrato (esto va en to)
En el SDK de TS, deployContract requiere un contractAddress, que se convierte en el to de la transaction.
A continuación se muestra un helper simple que genera una cadena hex aleatoria de 32 bytes:
import { randomBytes } from "node:crypto";
function randomHex32(): string {
return randomBytes(32).toString("hex"); // 64 caracteres hex
}
const contractAddress = randomHex32();
5. Crear una sesión de transaction (se conecta al node)
Esta llamada inicializa la sesión (obtiene /health para conseguir el nodeId y verifica /blockchains):
const nodeEndpoint = "http://localhost:8080";
const session = await sdk.createSession(nodeEndpoint, wallet);
6. Desplegar el contrato
import { TransactionType } from "@uledgerinc/typescript-sdk";
const tx = await session.deployContract({
blockchainId,
sourceCode: contractSource,
contractAddress,
});
console.log("Deploy TX ID:", tx.transactionId);
console.log("Status:", tx.status);
console.log("Output:", tx.output);
console.log("Contract Address (to):", contractAddress);
Qué ocurre internamente (caso de despliegue)
TransactionSession.deployContract(...) delega en submitTransaction(...), que:
-
Construye un input de transaction con:
to = contractAddressfrom = wallet.address(el despliegue no es una tx de creación de billetera)payload = sourceCodepayloadType = TransactionType.DeploySmartContractsuggestor = nodeId(desde/health)
-
Firma el input de la transaction mediante el backend WASM
-
Hace POST a:
POST {nodeEndpoint}/blockchains/{blockchainId}/transactions
7. Siguiente paso: Invocar el contrato
Para llamar al contrato desplegado, se envía una transaction INVOKE_SMART_CONTRACT.
Continuar en: Invocar Smart Contracts (TS) (siguiente guía).
---
## Invocar Smart Contracts (TypeScript)
```mdx
---
id: invoke-smart-contract-ts
title: Invocar un Smart Contract con el SDK de TypeScript
sidebar_label: Invocar Smart Contract (TS)
sidebar_position: 5
---
# Invocar un Smart Contract (TypeScript)
Esta guía muestra la **lógica principal** para invocar una función de un smart contract ULVM usando el SDK de TypeScript.
✅ Objetivo: crear una transaction `INVOKE_SMART_CONTRACT` donde:
- `to` = la **dirección del contrato**
- payload = JSON `{ functionName, args, gasLimit }`
- los args se proporcionan como `string` o `Uint8Array`
---
## 1) Requisitos antes de invocar
Se necesita:
1. Una billetera que pueda enviar txs en la chain.
2. Una **dirección de contrato** desplegada (el mismo `contractAddress` que se pasó durante el despliegue).
3. `nodeEndpoint` y `blockchainId`.
:::info
La **dirección del contrato no es el transactionId del despliegue** en este SDK.
Se debe usar el `contractAddress` elegido en el momento del despliegue (el `to` de la transaction).
:::
---
## 2) Inicializar el SDK y la billetera (ejemplo)
```ts
import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";
const sdk = await getULedgerSDK();
// Ejemplo mínimo: generar una billetera
const wallet = sdk.generateWallet({ keyType: KeyType.Secp256k1 });
// O restaurar:
// const wallet = sdk.walletFromMnemonic(mnemonic, { keyType: KeyType.Secp256k1 });
// const wallet = sdk.walletFromJson(walletJsonString);
3) Crear una sesión
const nodeEndpoint = "http://localhost:8080";
const session = await sdk.createSession(nodeEndpoint, wallet);
4) Invocar una función del contrato
La sesión de TS expone:
invokeContract(options: {
blockchainId: string;
contractAddress: string;
functionName: string;
args?: Array<string | Uint8Array>;
gasLimit?: number;
}): Promise<ULTransaction>
Ejemplo A — llamar a testStoreAndRetrieve(...)
Si el contrato acepta args de tipo string (o parsea strings), se puede pasar "123":
const tx = await session.invokeContract({
blockchainId,
contractAddress,
functionName: "testStoreAndRetrieve",
args: ["123"],
gasLimit: 100000,
});
console.log("Invoke TX ID:", tx.transactionId);
console.log("Status:", tx.status, "| Output:", tx.output);
Ejemplo B — llamar a testStoreAndRetrieveArray() (sin args)
const tx = await session.invokeContract({
blockchainId,
contractAddress,
functionName: "testStoreAndRetrieveArray",
args: [],
gasLimit: 100000,
});
console.log("Invoke TX ID:", tx.transactionId);
console.log("Status:", tx.status, "| Output:", tx.output);
5) Notas y solución de problemas
El nombre de función debe coincidir exactamente
functionName debe coincidir exactamente con el nombre de la función ULVM exportada.
contractAddress debe ser correcto
Para llamadas a contratos:
contractAddress= la misma dirección usada en el momento del despliegue- firmante = la billetera de la sesión
Los args deben coincidir con lo que el contrato espera
En el SDK de TS:
argspuede serstringoUint8Array- Se debe usar
Uint8Arraycuando el contrato espera argumentos binarios codificados por la VM
Si el contrato espera codificación binaria con tipos fuertes (por ejemplo, i32 codificado para la VM),
se debe proporcionar un Uint8Array producido por las utilidades de serialización de contratos (documentadas por separado).
Valores predeterminados del gas limit
Se debe establecer gasLimit de forma explícita. Si se omite, se aplica un valor predeterminado, y 0 se eleva al mínimo de 100000
en lugar de significar ilimitado. El rango válido es 100000–10000000, por lo que conviene comenzar con 100000 para
contratos simples y aumentarlo en contratos que realizan muchas llamadas de almacenamiento.
Opcional: Consultar resultados después de invocar
Obtener una transaction por id
const loaded = await session.getTransaction(blockchainId, tx.transactionId);
console.log("Loaded status:", loaded.status, "| output:", loaded.output);
Obtener un block por altura
const block = await session.getBlock(blockchainId, tx.blockHeight);
console.log("Block height:", block.height);
Próximos pasos
Continuar en: **Invocar Smart Contracts (TS)