Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
705 changes: 331 additions & 374 deletions app/package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
"@fontsource/space-mono": "^5.3.0",
"@huggingface/transformers": "4.3.0",
"@noble/hashes": "^1.8.0",
"@parity/product-sdk-host": "0.19.1",
"@parity/product-sdk-signer": "0.14.4",
"@parity/product-sdk-host": "0.28.0",
"@parity/product-sdk-signer": "0.17.3",
"@phosphor-icons/core": "^2.1.1",
"@polkadot/util": "^13.5.4",
"@polkadot/util-crypto": "^13.5.4",
"multiformats": "^13.3.7",
"polkadot-api": "~2.2.1",
"polkadot-api": "3.2.1",
"qrcode": "^1.5.4",
"viem": "^2.56.8"
},
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/people.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ async function ownerViaPublic(username: string): Promise<string | null> {
}

async function ownerVia(client: PolkadotClient, username: string): Promise<string | null> {
// polkadot-api 2.2: la clave `Vec<u8>` va como Uint8Array y el AccountId vuelve en SS58.
// polkadot-api 3: la clave `Vec<u8>` va como Uint8Array y el AccountId vuelve en SS58.
const q = client.getUnsafeApi().query.Resources.UsernameOwnerOf.getValue(new TextEncoder().encode(username)) as Promise<string | undefined>;
const r = await withTimeout(q, PEOPLE_QUERY_MS);
if (r === TIMED_OUT) throw new Error('People chain no respondió');
Expand Down
15 changes: 8 additions & 7 deletions app/src/lib/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
* `get(huella)` con la runtime API ReviveApi.call. Funciona igual con el
* provider del host o con un WebSocket público.
*/
import { Binary, type PolkadotClient, type PolkadotSigner } from 'polkadot-api';
import { Binary, type PolkadotClient } from 'polkadot-api';
import type { SignerTxCreator as PolkadotSigner } from 'polkadot-api/tx-creator';
import { decodeErrorResult, decodeFunctionResult, encodeFunctionData, type Abi } from 'viem';
import abiJson from './TalkRegistry.abi.json' with { type: 'json' };
import { REGISTRY_ADDRESS } from './network.ts';
Expand All @@ -28,7 +29,7 @@ export interface OnChainSeal {
export async function readSeal(client: PolkadotClient, receiptHash: string): Promise<OnChainSeal | null> {
const api = client.getUnsafeApi();
const data = encodeFunctionData({ abi, functionName: 'get', args: [receiptHash as `0x${string}`] });
// `dest` es [u8; 20]: en polkadot-api 2.2 va como texto hex; los Vec<u8> son Uint8Array.
// `dest` es [u8; 20]: en polkadot-api 3 va como texto hex; los Vec<u8> son Uint8Array.
// La api sin descriptors no tipa el resultado.
const r = (await api.apis.ReviveApi.call(READ_ORIGIN, REGISTRY_ADDRESS, 0n, undefined, undefined, Binary.fromHex(data))) as {
result?: { success: boolean; value: { flags: number; data: Uint8Array | string } };
Expand Down Expand Up @@ -118,21 +119,21 @@ const WEIGHT_CAP = { ref_time: 900_000_000_000n, proof_size: 3_000_000n };

interface TxEvent {
type: string;
found?: boolean;
ok?: boolean;
txHash?: string;
block?: { number: number };
dispatchError?: unknown;
}

/** Firma, envía y espera a que el bloque quede finalizado; avisa cuando ya se firmó. */
function submit(tx: { signSubmitAndWatch(s: PolkadotSigner): { subscribe(o: object): { unsubscribe(): void } } }, signer: PolkadotSigner, onSigned: () => void): Promise<{ block: number; txHash: string }> {
function submit(tx: { createSubmitAndWatch(s: PolkadotSigner): { subscribe(o: object): { unsubscribe(): void } } }, signer: PolkadotSigner, onSigned: () => void): Promise<{ block: number; txHash: string }> {
return new Promise((resolve, reject) => {
const sub = tx.signSubmitAndWatch(signer).subscribe({
// polkadot-api 3: el firmante es un TxCreator; eventos created → broadcasted → inBestBlock → finalized
const sub = tx.createSubmitAndWatch(signer).subscribe({
next: (e: TxEvent) => {
if (e.type === 'signed') onSigned();
if (e.type === 'created') onSigned();
// Falló ya en el primer bloque: no hace falta esperar la finalización.
if (e.type === 'txBestBlocksState' && e.found && e.ok === false) {
if (e.type === 'inBestBlock' && e.ok === false) {
sub.unsubscribe();
reject(new Error(describeDispatch(e.dispatchError)));
}
Expand Down
11 changes: 7 additions & 4 deletions app/src/lib/signer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { getAccountsProvider, isInsideContainerSync } from '@parity/product-sdk-
// Import estático a propósito: en el gateway dev-dot.li un chunk que se baja al pulsar
// "Conectar" falló con "Failed to fetch dynamically imported module".
import { SignerManager, type SignerManager as SM } from '@parity/product-sdk-signer';
import type { PolkadotSigner } from 'polkadot-api';
import type { SignerTxCreator as PolkadotSigner } from 'polkadot-api/tx-creator';
import { hexToU8a, u8aToHex } from '@polkadot/util';
import { encodeAddress } from '@polkadot/util-crypto';
import { waitForHost, withTimeout, describeError, TIMED_OUT, HOST_QUERY_MS, HOST_SUBMIT_MS } from './host';
Expand Down Expand Up @@ -88,12 +88,15 @@ export async function connectSpeaker(): Promise<Speaker> {
return speaker;
}

const u = await withTimeout(manager.getUserId(), HOST_QUERY_MS).catch(() => null);
username = u && u !== TIMED_OUT && u.ok ? u.value.primaryUsername || null : null;
// El host puede mostrar un cuadro para compartir la identidad (SDK 0.39): tiempo de diálogo, no de consulta
const u = await withTimeout(manager.getUserId(), HOST_SUBMIT_MS).catch((e: unknown) => ({ ok: false as const, error: e }));
username = u !== TIMED_OUT && u.ok ? u.value.primaryUsername || null : null;
identity = null;
identityNote = null;
if (!username) {
identityNote = 'tu cuenta no tiene username';
identityNote = u === TIMED_OUT ? 'el host no entregó tu username a tiempo (¿aprobaste compartir tu identidad?)'
: !u.ok ? `el host no entregó tu username: ${describeError(u.error)}`
: 'tu cuenta no tiene username';
} else {
try {
const owner = await usernameOwner(username);
Expand Down
2 changes: 1 addition & 1 deletion app/src/views/diagnostics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ export function renderDiagnostics(root: HTMLElement): Cleanup {
const signer = txSignerFor(payer);
if (!signer) return ['no', 'sin firmante de transacciones para esta cuenta'];
const tx = (await getClient()).getUnsafeApi().tx.System.remark({ remark: Binary.fromText('testalk diagnóstico') });
const signed = await withTimeout(tx.sign(signer), HOST_SUBMIT_MS);
const signed = await withTimeout(tx.create(signer), HOST_SUBMIT_MS);
if (signed === TIMED_OUT) return ['no', 'la firma no llegó a tiempo: revisa el celular'];
// Según la versión de polkadot-api llega como hex o como bytes.
const out = signed as unknown as string | Uint8Array;
Expand Down
6 changes: 3 additions & 3 deletions app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const version = (pkg: string) => JSON.parse(read(`${pkg}/package.json`)).version

/**
* Versiones del SDK y del protocolo host ↔ app, visibles en #/diagnostico.
* El host y la app deben hablar el mismo códec de truapi: Polkadot Desktop 0.1.3
* (host-api 0.9.4) habla el 1; truapi 0.16 en adelante habla el 2 y el host
* descarta sus peticiones sin responder.
* El host y la app deben hablar el mismo códec de truapi: desde el 22–23 oct 2026
* la Polkadot App, Desktop 0.1.4 y dev-dot.li hablan TrUAPI 0.25 (códec 3); con
* otro códec el host descarta las peticiones sin responder.
*/
const sdk = {
host: version('@parity/product-sdk-host'),
Expand Down
2 changes: 1 addition & 1 deletion docs/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ con apps reales en el contenedor. testalk ya está escrito para convivir con est
| `lookup` reporta `null` hasta encontrar el preimage | El verificador ignora los `null` y espera hasta 20 s |
| La red dentro del contenedor necesita el permiso `Remote` por dominio | Se piden al arrancar: `localhost`, el gateway IPFS y los RPC públicos |
| `localStorage` se vacía con cada release | El borrador de la charla dura la sesión; no publiques una versión nueva durante una charla |
| Polkadot Desktop 0.1.3 habla el códec 1 del protocolo; `truapi` 0.16+ habla el 2 | SDK fijado en `product-sdk-host` 0.19.1 + `signer` 0.14.4. **No subirlo** sin comprobar el códec del host ([guía](products-devnet-guide.md#9-la-app-y-el-host-deben-hablar-el-mismo-protocolo)) |
| Desde el 22–23 oct 2026 los hosts (App Android/iOS `devnet/2026-10-22.1`, Desktop 0.1.4, dev-dot.li) hablan TrUAPI 0.25, códec 3 | SDK fijado en `product-sdk-host` 0.28.0 + `signer` 0.17.3 + `polkadot-api` 3.2.1 (= `@parity/product-sdk` 0.39.0). **No subirlo** sin comprobar el códec del host ([guía](products-devnet-guide.md#9-la-app-y-el-host-deben-hablar-el-mismo-protocolo)) |
| `SignerManager` entrega una cuenta de producto de la app, nunca la identidad del usuario | Se firma con la cuenta dueña del username en People chain; la de producto queda de respaldo y el recibo lo refleja |
| En `*.dev-dot.li` el web shell no deriva cuentas de producto (TWR #18) | Presentar solo desde Polkadot Desktop; verificar sí funciona ahí |

Expand Down
36 changes: 23 additions & 13 deletions docs/products-devnet-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -382,25 +382,35 @@ esperando.

| Paquete de tu app | Códec |
|---|---|
| `@parity/truapi` 0.5.1 a 0.13.1 (`product-sdk-host` 0.14.1 a 0.19.1, `product-sdk-signer` 0.11.1 a 0.14.4) | **1** |
| `@parity/truapi` 0.16.0 en adelante (`product-sdk-host` 0.20.0+, `product-sdk-signer` 0.14.5+) | 2 |
| `@parity/truapi` 0.5.1 a 0.13.1 (`product-sdk-host` 0.14.1 a 0.19.1, `product-sdk-signer` 0.11.1 a 0.14.4) | 1 |
| `@parity/truapi` 0.16.0 a 0.24 (`product-sdk-host` 0.20.0 a 0.27) | 2 |
| `@parity/truapi` **0.25** (`product-sdk-host` **0.28.0**, `product-sdk-signer` **0.17.3** = `@parity/product-sdk` **0.39.0**) | **3** |

Polkadot Desktop 0.1.3 (septiembre de 2026) habla el **códec 1**. Con él
funcionan `product-sdk-host` **0.19.1** + `product-sdk-signer` **0.14.4**
(o el paquete `@parity/product-sdk` **0.27.0**, que trae esa pareja):
Desde el update del devnet del **22–23 de octubre de 2026**, todos los hosts
(Polkadot App Android e iOS `devnet/2026-10-22.1`, Polkadot Desktop **0.1.4** y
`dev-dot.li`) hablan TrUAPI 0.25, el **códec 3**. Las apps con el códec 1 o 2
ya no conectan. Usa exactamente el SDK 0.39.0 (el 0.40 en adelante habla
TrUAPI 0.26, que estos hosts todavía no entienden) y `polkadot-api` 3:

```bash
npm install --save-exact @parity/product-sdk-host@0.19.1 @parity/product-sdk-signer@0.14.4
npm ls @parity/product-sdk-host @parity/truapi # debe haber UNA sola copia de cada uno
npm install --save-exact @parity/product-sdk@0.39.0 polkadot-api@3.2.1
# o, si usas los paquetes sueltos, las versiones que fija el 0.39.0:
npm install --save-exact @parity/product-sdk-host@0.28.0 @parity/product-sdk-signer@0.17.3 polkadot-api@3.2.1
npm ls @parity/truapi polkadot-api # debe haber UNA sola copia de cada uno
```

Lo que cambia con `polkadot-api` 3: los firmantes son `TxCreator`
(`getTxCreator` de `polkadot-api/tx-creator` en vez de `getPolkadotSigner`),
`tx.signSubmitAndWatch(signer)` pasa a `tx.createSubmitAndWatch(signer)`,
`signAndSubmit` a `createAndSubmit`, `sign` a `create`, y los eventos son
`created` → `broadcasted` → `inBestBlock` → `finalized`.

Cómo saber qué habla tu host, sin adivinar:

```bash
# Versión del protocolo que trae Polkadot Desktop (Mac)
npx @electron/asar extract-file "/Applications/Polkadot Desktop Dev.app/Contents/Resources/app.asar" \
node_modules/@novasamatech/host-api/dist/constants.js && cat constants.js
# → export const SCALE_CODEC_PROTOCOL_ID = 1;
# Versión de TrUAPI de un host: viene en las notas de su release
gh release view devnet/2026-10-22.1 -R Polkadot-Community-Foundation/polkadot-desktop-community
# → "pin truapi-host 0.25.0-pcf.1"

# Versión que habla tu app
grep -h "TRUAPI_CODEC_VERSION = " node_modules/@parity/truapi/dist/generated/client.js
Expand Down Expand Up @@ -474,7 +484,7 @@ por detrás. Esto es lo que medimos el 25 y 26 de septiembre de 2026:

| La documentación dice | Lo que pasó de verdad |
|---|---|
| *"Install the latest release of every package"* | Vale para `pad` y `dotns`. Para el SDK de tu app, **no**: el más nuevo habla el códec 2 y Polkadot Desktop 0.1.3 el 1 ([sección 9](#9-la-app-y-el-host-deben-hablar-el-mismo-protocolo)) |
| *"Install the latest release of every package"* | Vale para `pad` y `dotns`. Para el SDK de tu app, **no**: en octubre de 2026 los hosts hablan TrUAPI 0.25 (SDK 0.39.0) y el SDK más nuevo ya habla la 0.26 ([sección 9](#9-la-app-y-el-host-deben-hablar-el-mismo-protocolo)) |
| *"Use labels nine characters or longer"* | Se cuenta la base **sin** los dígitos finales: `testalk26` tiene 9 caracteres y pidió personhood ([paso 3](#3-elegir-el-nombre-antes-que-nada)) |
| *"Reads are container-only; there is no public IPFS-gateway fallback"* | El gateway IPFS del devnet sirvió lo que subió el host con `submit()` en 274 ms, byte por byte |
| El archivo de configuración publica nombre, descripción e ícono | Con `pad login`, en `pad` 0.16.7 el manifest falla siempre ([paso 6](#el-manifest-puede-fallar-y-la-app-funciona-igual)) |
Expand All @@ -494,7 +504,7 @@ así el siguiente estudiante no pierde el mismo día.

| Síntoma | Causa | Qué hacer |
|---|---|---|
| El SDK dice `connected` pero **nada** responde: permisos, cuentas, firmas | Tu app y el host hablan distinta versión de códec | [Sección 9](#9-la-app-y-el-host-deben-hablar-el-mismo-protocolo): usa `product-sdk-host` 0.19.1 + `signer` 0.14.4 con Desktop 0.1.3 |
| El SDK dice `connected` pero **nada** responde: permisos, cuentas, firmas | Tu app y el host hablan distinta versión de códec | [Sección 9](#9-la-app-y-el-host-deben-hablar-el-mismo-protocolo): usa `@parity/product-sdk` 0.39.0 (TrUAPI 0.25) con los hosts de octubre de 2026 |
| `testalk26.dot requires ProofOfPersonhoodLite, but this signer is NoStatus` | La base del nombre tiene menos de 9 caracteres | Elige un nombre con base de 9 o más ([paso 3](#3-elegir-el-nombre-antes-que-nada)). No se gastó nada: falló en la verificación previa |
| La app aparece en otra red o el nombre "no existe" | Faltó `--env devnet` o `PAD_ENV=devnet` | Agrégalo en todos los comandos de `pad` y `dotns` |
| `pad` se queda esperando y la `Y` no hace nada | La terminal manda el proceso a segundo plano | Usa Terminal.app u otra terminal normal |
Expand Down
Loading