Saltar al contenido principal

Registrar la Billetera y Crear Transacciones con el SDK de TypeScript

En la sección anterior se creó y se guardó una billetera en disco (.ukey).

En esta sección se explica cómo:

  1. Cargar esa billetera desde un archivo .ukey.
  2. Abrir una sesión de transacción contra un node de ULedger.
  3. Usar esa sesión para:
    • registrar la billetera en la cadena (CREATE_WALLET),
    • y luego enviar transacciones DATA usando la misma billetera.

Conceptualmente:

  • Registrar billetera = crear la identidad en la cadena (CREATE_WALLET).
  • Transacciones de datos = escribir datos en la cadena (DATA).

1. Requisitos previos​

Antes de comenzar, es necesario disponer de:

  • Un node de ULedger en ejecución (o acceso a nodes de desarrollo).
  • Un archivo de billetera creado en la guía anterior (p. ej. ./wallets/my_wallet.ukey).
  • Un archivo de configuración con los endpoints de los nodes.

Ejemplo de config.json:

{
"nodeEndpoints": [
"https://your-node-url",
"https://your-node-2-url",
"https://your-node-3-url"
],
"verbose": true
}

2. Cargar configuración y billetera​

import fs from "node:fs";
import { getULedgerSDK } from "@uledgerinc/typescript-sdk";

type Config = {
nodeEndpoints: string[];
verbose?: boolean;
};

function loadConfig(path: string): Config {
const raw = fs.readFileSync(path, "utf8");
const cfg = JSON.parse(raw) as Config;

if (!cfg.nodeEndpoints?.length) {
throw new Error("config must contain at least one node endpoint");
}

return cfg;
}

async function loadWalletFromFile(walletPath: string, password = "") {
const sdk = await getULedgerSDK();
const raw = fs.readFileSync(walletPath, "utf8");
const wallet = sdk.walletFromJson(raw, password);
return { sdk, wallet };
}

3. Crear una sesión de transacción​

Un TransactionSession se conecta a un endpoint de node, obtiene información de salud/cadena y almacena el ID del node como el suggestor.

Se usa el helper del SDK:

  • sdk.createSession(nodeEndpoint, wallet)
function pickRandom<T>(items: T[]): T {
return items[Math.floor(Math.random() * items.length)];
}

async function newRandomSession(params: {
sdk: any;
nodeEndpoints: string[];
wallet: any;
}) {
const { sdk, nodeEndpoints, wallet } = params;

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

console.log("Using node:", session.getNodeEndpoint());
console.log("Suggestor (nodeId):", session.getSuggestor());

return session;
}

4. Registrar la billetera (registerWallet)​

Antes de que una billetera pueda participar en las reglas de la cadena, generalmente debe ser creado en ella.

La sesión expone un helper de alto nivel:

  • session.registerWallet(blockchainId, walletToRegister?, customAuthGroups?)

Si se omite walletToRegister, registra la billetera de la sesión (auto-registro).

import { DEFAULT_ADMIN_AUTH_GROUP } from "@uledgerinc/typescript-sdk";

async function registerWallet(params: {
session: any;
blockchainId: string;
}) {
const { session, blockchainId } = params;

const tx = await session.registerWallet(
blockchainId,
undefined, // omit to self-register the session wallet
DEFAULT_ADMIN_AUTH_GROUP, // optional: defaults to admin full permissions
);

console.log("CREATE_WALLET txId:", tx.transactionId);
console.log("status:", tx.status);
console.log("output:", tx.output);

return tx;
}

5. Enviar transacciones DATA (submitData)​

:::info Enviar enteros grandes como cadenas de texto

Los enteros mayores que 2^53 − 1 (Number.MAX_SAFE_INTEGER) se almacenan redondeados y la transaction aun así se procesa con éxito, por lo que un ID de 19 dígitos se devuelve como un número distinto.

// redondeado en la cadena, pasa a ser 1234567890123456800
{ orderId: 1234567890123456789 }

// seguro, se almacena exactamente como se envió
{ orderId: "1234567890123456789" }

Se deben enviar los enteros grandes como cadenas de texto. JSON.stringify tiene el mismo límite al serializar, por lo que el valor ya se ha perdido en parte antes de salir del proceso. :::

Una vez que la billetera está registrada, se pueden enviar transacciones de datos.

Se usa:

  • session.submitData({ blockchainId, to, data })

data puede ser una cadena de texto o un objeto.

async function sendDataTransaction(params: {
session: any;
blockchainId: string;
to: string;
data: string | object;
}) {
const { session, blockchainId, to, data } = params;

const tx = await session.submitData({
blockchainId,
to,
data,
});

console.log("DATA txId:", tx.transactionId);
console.log("status:", tx.status);
console.log("output:", tx.output);
console.log("payloadRoot:", tx.payloadRoot);

return tx;
}

:::warning Una transaction enviada no es una transaction aceptada El status y el output de la respuesta de envío describen la transaction tal como se entregó al node. No la confirman. Para confirmarla, se debe leer la transaction desde el node hasta que tenga un blockHeight y output sea SUCCESS, o consultar GET {node}/blockchains/{blockchainId}/transactions/{transactionId}/status y verificar que devuelva state: "committed". Una transaction que la red rechaza se descarta y nunca aparece, por lo que, si no ha sido confirmada dentro de la ventana de espera, se debe tratar como fallida y no como pendiente. :::


6. Todo junto​

Este programa:

  1. Carga la configuración y la billetera.
  2. Crea una sesión.
  3. Registra la billetera (CREATE_WALLET).
  4. Envía algunas transacciones DATA.
import fs from "node:fs";
import { getULedgerSDK } from "@uledgerinc/typescript-sdk";

function pickRandom<T>(items: T[]): T {
return items[Math.floor(Math.random() * items.length)];
}

async function main() {
const configPath = "config.json";
const walletPath = "./wallets/my_wallet.ukey";
const password = "";
const blockchainId = "your-blockchain-id-here";
const txCount = 3;

const cfg = JSON.parse(fs.readFileSync(configPath, "utf8")) as {
nodeEndpoints: string[];
};
if (!cfg.nodeEndpoints?.length) throw new Error("Missing nodeEndpoints in config.json");

const sdk = await getULedgerSDK();

const walletJson = fs.readFileSync(walletPath, "utf8");
const wallet = sdk.walletFromJson(walletJson, password);

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

console.log("Using node:", session.getNodeEndpoint());
console.log("Suggestor (nodeId):", session.getSuggestor());

// 1) Register wallet (one-time per wallet/chain)
const regTx = await session.registerWallet(blockchainId);
console.log("Registered wallet tx:", regTx.transactionId, regTx.status, regTx.output);

// 2) Send DATA transactions
for (let i = 0; i < txCount; i++) {
const tx = await session.submitData({
blockchainId,
to: wallet.address,
data: { message: `hello from ${wallet.address}`, index: i + 1 },
});

console.log("DATA tx:", tx.transactionId, tx.status, tx.output, tx.payloadRoot);
}
}

main().catch(console.error);

Notas​

  • registerWallet(...) crea una transacción CREATE_WALLET internamente.
  • submitData(...) envía una transacción DATA y serializa los objetos automáticamente.