ZYCORD documentación
Español

Monedero

Claves, direcciones y envíos — más el contrato de comportamiento que todo monedero de este protocolo tiene que cumplir. Cada regla describe una forma de perder dinero que el protocolo permite, y que por tanto un monedero debe impedir.

Los comandos#

zcd wallet new     --out KEYFILE                        # create an encrypted key file
zcd wallet address --key KEYFILE                        # show an address
zcd wallet balance --key KEYFILE                        # ask a node for a balance
zcd wallet send    --key KEYFILE --to ADDR --amount N
zcd wallet sweep   --key KEYFILE --to ADDR --one-shot
zcd wallet retire  --key KEYFILE [--addr ADDR]
zcd ui             --key KEYFILE                        # the same wallet in a browser

El monedero gráfico no es una segunda implementación. zcd wallet, zcd ui y la aplicación de escritorio son tres interfaces sobre un solo wallet/session: cada una construye ahí su certificado, y las comprobaciones de las reglas corren dentro de esa llamada. Un monedero gráfico es por tanto estructuralmente incapaz de ser más permisivo que la línea de comandos — no porque quien lo escribió tuviera cuidado, sino porque no hay una segunda ruta de código en la que pudiera serlo.

Dos tipos de dirección#

VersiónTipoÚsala para¿Reutilizable?
0x01De un solo usoUn único pago esperado. Deriva una nueva por cada pago que recibas.No. Un débito la quema permanentemente.
0x02PersistenteComercios, direcciones de donación, monederos calientes, pagos de minería.Sí, para siempre. Nunca puede entrar en el registro de gastadas.

Un solo uso frente a persistente es una política del monedero expuesta como un bit de la dirección, no dos libros mayores. Los monederos usan 0x01 por defecto para cada pago recibido, porque es lo que hace que un pago no sea vinculable con el siguiente; quien quiera una cuenta usa 0x02.

Las ocho reglas#

Toda regla de abajo describe una forma de perder dinero o comisiones que el protocolo permite — deliberadamente, porque la alternativa era peor — y que por tanto un monedero debe impedir. El monedero de referencia las implementa. No se limita a documentarlas.

Regla 1 — barre celdas enteras#

Al gastar desde una dirección 0x01, mueve el saldo entero — al beneficiario y a una dirección de cambio que controles. El certificado lleva un MARK_SPENT de esa dirección, y después de que se aplique, toda lectura y escritura bajo la dirección falla de forma permanente. No hay segunda transacción.

La cadena ahora suaviza esto: lo que una dirección quemada siga conteniendo se mueve a la propia celda RefundTo del certificado al confirmarse — tanto para el saldo nativo de la dirección como para cada celda que el propio certificado nombre. Así que barrer de menos ya no destruye los restos; se los entrega a tu dirección de cambio.

La obligación que viene con ello

Un certificado tiene un solo RefundTo y puede quemar direcciones de un solo uso pertenecientes a varios firmantes, así que un residuo bajo tu celda puede entregarse a la de ellos. Nunca cofirmes un certificado que queme una dirección de un solo uso tuya y reembolse a una dirección que no controlas.

Lo que esta regla no puede salvar: un saldo en un activo que el certificado nunca menciona. Los activos bajo una dirección no son derivables de un slot, así que alcanzar un activo no nombrado significaría recorrer toda la tabla de celdas en la única etapa que no se paraleliza. Nombra todos los activos en el certificado que quema la dirección.

Regla 2 — RefundTo debe ser una dirección que aún puedas usar#

Debe nombrar o bien una dirección persistente que controles o bien una dirección de un solo uso nueva que este certificado no queme. Depositarlo en una celda quemada deja varado el resto: el fold lo quema en lugar de escribirlo en una celda que nadie puede leer, y lo informa como refund_burned en lugar de refunded, de modo que un monedero que concilie un saldo pueda darse cuenta.

Regla 3 — una dirección, un pago esperado#

Dos obligaciones, una en cada lado:

  • Al recibir. Deriva una dirección 0x01 nueva por cada pago que esperes. Nunca publiques una dos veces. No barras ni retires una dirección que hayas divulgado en los últimos ttl_max bloques salvo que aceptes que un pago en vuelo hacia ella sufrirá una omisión y se le cobrará a quien lo envió.
  • Al enviar. Niégate a pagar a una dirección de un solo uso que puedas ver que ya se ha abonado o gastado. Si un beneficiario te da una dirección por segunda vez, trátalo como un error, no como una comodidad.

Para cualquier cosa que se pague más de una vez — un comercio, una dirección de donaciones, un pago de minería — usa una dirección persistente (0x02). Esta es la única regla que elimina la exposición en lugar de acotarla.

Regla 4 — cadenas dependientes: confirma, o acepta el riesgo#

Incrementa Seq por cada certificado que dependa de uno anterior. Dentro de un mismo bloque el fold confirma los certificados de un firmante en orden de Seq, así que una cadena dependiente en el mismo bloque es segura. Entre bloques no lo es: difunde Seq = n+1 solo después de que Seq = n haya confirmado, o acepta que el dependiente puede confirmarse solo y sufrir una omisión. Esto no es un defecto del protocolo — el firmante aceptó el riesgo de obsolescencia al firmar.

Regla 5 — fija el máximo con generosidad y la prioridad con honestidad#

Cada mercado toma dos precios. El máximo es una cota de solvencia: en cuanto la comisión base lo supera, el certificado es inincluible y hay que volver a firmarlo. La prioridad es lo que se le paga de verdad a un minero.

  • Subir el máximo no cuesta nada en comisiones — el colchón de seguridad es gratis.
  • Pero el depósito reserva gas × max, así que el máximo acota cuánto saldo queda bloqueado por un paso del fold. Dimensiónalo contra el saldo realmente disponible.
  • Un certificado con un TTL largo necesita más holgura que uno con un TTL corto, porque la comisión base tiene más bloques en los que moverse.

La vía de escape para saldos pequeños es reducir la ventana, no la seguridad: firma con un TTL corto y vuelve a firmar al caducar, cambiando inmovilización por latencia. La respuesta equivocada es mantener el TTL largo y reducir el máximo, lo que hace que el certificado quede varado justo cuando el mercado se mueve — el caso para el que existía el margen.

Regla 6 — ordena los movimientos de forma canónica#

El protocolo no impone ningún orden a los movimientos de una transferencia, así que sin un orden canónico un reintento del mismo pago lógico produce un id distinto y el monedero no puede distinguir "ya enviado" de "enviado dos veces". wallet.Transfer ordena por activo, origen, destino y luego importe, de modo que un reintento reproduce el id.

Un reintento no tiene que reproducir la firma: la preimagen del id excluye la lista de firmas, así que un reintento vuelto a firmar con un nonce nuevo es el mismo id y la red lo rechaza como el duplicado que es. La idempotencia es una propiedad que provee el protocolo, para todo monedero y no solo para los cuidadosos.

Regla 7 — nunca entregues una semilla#

La semilla es la clave. Cualquiera que la lea es dueño de todo lo que contienen sus dos direcciones — la de un solo uso y la persistente, que no guardan relación en la cadena pero se derivan de la misma clave.

Los archivos de clave están siempre cifrados: Argon2id sobre la frase de paso, AES-256-GCM sobre la semilla, ambos con sus parámetros guardados en el archivo para que un usuario que se quede fuera de este binario pueda recuperarla con la biblioteca estándar de cualquier lenguaje. No hay ningún flag para escribir uno sin cifrar. Las frases de paso se leen de la terminal sin eco, nunca de un flag — una frase de paso en una línea de comandos está en el historial del intérprete y en la tabla de procesos.

La escritura sostiene dos propiedades a la vez, y ambas tratan de la misma frase — perder una es perder dinero:

  • Nunca sobrescribir en silencio. Un archivo de clave que ya esté en el destino se deja intacto y la escritura falla.
  • Nunca dejar uno a medias. La semilla va a un archivo temporal en el mismo directorio, allí se hace fsync, y solo entonces se publica con su nombre definitivo en una única operación del sistema de archivos.

Ambas se cumplen en todos los sistemas de archivos contra los que se midió la CLI, FAT32 y exFAT incluidos — los formatos que es más probable que use una copia de seguridad USB en frío.

Un archivo de clave cifrado en una memoria con formato FAT está protegido por su contraseña y por nada más

FAT32 y exFAT no tienen bits de permisos de Unix, así que el 0600 con el que se crea un archivo de clave no sobrevive en ellos — deciden las opciones de montaje. En Linux, el fmask por defecto suele dejarlo legible para todo el mundo; macOS monta esos volúmenes como noowners, que informa de 0700 y no impone nada. Elige la frase de paso en consecuencia. Tampoco tienen diario, así que si una publicación se interrumpe en FAT e informa de un fallo, comprueba el destino antes de volver a ejecutarla.

Regla 8 — rechaza lo que la red va a rechazar#

Un monedero que informa de éxito para algo que la red solo puede descartar ha movido el fallo a un sitio donde el usuario nunca mirará. Dos formas de esto, ambas encontradas sobre el terreno:

  • Bytes que ningún par puede decodificar. El códec es una autoridad por derecho propio, con reglas que el validador no repite. El constructor ahora afirma la propiedad directamente: lo que emita, el decodificador lo acepta.
  • Una transferencia que el fold solo puede omitir. Una transferencia por encima del saldo del origen no rompe ninguna regla, así que todos los nodos la admiten — y nada rechaza a un productor que la incluya de todos modos, momento en que el fold la liquida a skip_fee, quemada del depósito y pagada a nadie. El mal caso no es "sin efecto", es "la comisión se quemó y el valor nunca se movió".

zcd wallet send --force salta esa única negativa y ninguna otra, porque un depósito que se espera que aterrice dentro de la ventana del TTL hace que el mismo certificado se aplique y el monedero no puede ver el futuro. No puede hacer válido un certificado inválido; solo puede enviar uno válido que puede sufrir una omisión — y una omisión no es gratis.

Confiar en un nodo que no ejecutas tú#

zcd y el monedero no son nodos completos. Creen lo que un nodo les dice, y una CLI que habla RPC con un nodo que ella misma no valida tiene que confiar en algo sobre las respuestas de ese nodo — eso no es un fallo que corregir, es lo que un monedero es. Tres mitigaciones, cada una para una mentira concreta:

MitigaciónQué detecta
--devnet / --testnet / --paramsEl operador afirma para qué red pretende firmar, y cada nodo consultado se contrasta con esa afirmación. La identidad de la red nunca se toma de un nodo por sí solo. Esto se aplica también a balance, no solo a los comandos que firman.
--confirm-rpc NODENombra un segundo nodo independiente. El saldo de cada dirección y su marca de gastada deben ser informados de forma idéntica por ambos antes de que nada continúe. Un nodo cuyo chain_id discrepe se rechaza, y un --confirm-rpc que nombre el mismo punto de acceso que --rpc se rechaza sin más — un nodo que se contrasta consigo mismo coincide consigo mismo.
La confirmación escrita a manoAntes de enviar, zcd wallet sweep imprime los números exactos y exige que escribas sweep. --yes se salta solo esa pregunta, nunca las comprobaciones anteriores.

Lista de comprobación para una implementación de monedero#

Si estás escribiendo un monedero contra este protocolo, este es el contrato:

  • Gastar desde 0x01 mueve el saldo entero, contando la reserva del depósito como parte de él — incluso en programas sin ningún movimiento.
  • RETIRE rechaza un objetivo que todavía tenga saldo.
  • El saldo que informa el nodo no se trata como incuestionable: identidad de red afirmada por el operador, una segunda fuente contrastable, y los números exactos confirmados antes de un barrido irreversible.
  • RefundTo se valida como persistente o nueva antes de firmar.
  • Al recibir se deriva una dirección nueva por pago esperado; al enviar se rechaza una dirección de un solo uso ya abonada o gastada.
  • Las direcciones de comercio y de pago usan 0x02 por defecto.
  • Seq se incrementa por cada certificado dependiente, y el monedero espera la confirmación antes de difundir el siguiente — o dice en voz alta que no lo hace.
  • Los máximos de comisión se dimensionan a partir del saldo disponible y del TTL, no se fijan en el código.
  • Los movimientos se ordenan canónicamente, de modo que un reintento reproduce el id del certificado.
  • Los archivos de clave están cifrados, se escriben de forma duradera y sin sobrescritura silenciosa, y las contraseñas nunca llegan a un flag.
  • No se firma nada de cuya propia codificación no se pueda volver a decodificar, y no se envía nada que el saldo de origen no pueda cubrir — con cualquier excepción nombrada, estrecha y reflejada en la vista previa.