Desplegar Smart Contracts (TypeScript)
Esta guía muestra los pasos principales para desplegar un smart contract ULVM usando el SDK de TypeScript de ULedger.
Vas a:
- Inicializar el SDK
- Cargar o generar un wallet (el firmante)
- Leer tu contrato compilado (
.wato.wasm) - Crear una sesión de transaction hacia un node
- Enviar una transaction
DEPLOY_SMART_CONTRACT
En muchas chains, tu wallet debe estar registrado on-chain antes de poder desplegar contratos.
Si obtienes REJECTED_BY_UNAUTHORIZED, registra el wallet primero (consulta la nota en el Paso 5).
1. Requisitos previos
Necesitas:
nodeEndpoint(ejemplo:http://localhost:8080)blockchainId- Un wallet que pueda firmar transactions
- El archivo fuente de tu contrato:
auction.wat(texto), oauction.wasm(binario — la codificación depende de las reglas del node)
2. Inicializar el SDK y cargar un wallet
import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";
const sdk = await getULedgerSDK();
// Opción A: generar un nuevo wallet
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
Opción A: Desplegar un archivo .wat (texto)
import { readFile } from "node:fs/promises";
const wat = await readFile("./auction.wat", "utf8");
const contractSource = wat;
Opción B: Desplegar un archivo .wasm (binario)
Tu node puede esperar bytes sin procesar, hex o base64. Un enfoque común es base64:
import { readFile } from "node:fs/promises";
const wasmBytes = await readFile("./auction.wasm");
const contractSource = Buffer.from(wasmBytes).toString("base64");
Usa el formato que tu node espera para
DEPLOY_SMART_CONTRACT.
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.
Aquí hay 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 wallet)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, envía una transaction INVOKE_SMART_CONTRACT.
Continúa en: Invocar Smart Contracts (TS) (siguiente guía).
---
## Invocar Smart Contracts (TypeScript)
```mdx
---
id: invoke-smart-contract-ts
title: Invoca 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) Lo que necesitas antes de invocar
Necesitas:
1. Un wallet que pueda enviar txs en tu chain.
2. Una **dirección de contrato** desplegada (el mismo `contractAddress` que pasaste durante el despliegue).
3. `nodeEndpoint` y `blockchainId`.
:::info
La **dirección del contrato no es el transactionId del despliegue** en este SDK.
Usa el `contractAddress` que elegiste en el momento del despliegue (el `to` de la transaction).
:::
---
## 2) Inicializar el SDK y el wallet (ejemplo)
```ts
import { getULedgerSDK, KeyType } from "@uledgerinc/typescript-sdk";
const sdk = await getULedgerSDK();
// Ejemplo mínimo: generar un wallet
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 tu contrato acepta args de tipo string (o parsea strings), puedes 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 errores comunes
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 = tu wallet en la sesión
Los args deben coincidir con lo que el contrato espera
En el SDK de TS:
argspuede serstringoUint8Array- Usa
Uint8Arraycuando tu contrato espera argumentos binarios codificados por la VM
Si tu contrato espera codificación binaria con tipos fuertes (por ejemplo, i32 codificado para la VM),
proporciona un Uint8Array producido por tus utilidades de serialización de contratos (documentadas por separado).
Valores predeterminados del gas limit
Si omites gasLimit, la sesión establece un valor predeterminado (la implementación usa actualmente un valor predeterminado grande).
Si no estás seguro, comienza con 100000 para ejemplos básicos y ajusta según sea necesario.
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
Continúa en: **Invocar Smart Contracts (TS)