Cómo escribir smart contracts en Midnight
Source: Dev.to
El modelo mental: privacidad por defecto
Antes de escribir una sola línea de código, hay que cambiar el enfoque.
En Midnight:
- Todo lo que viene del usuario es privado por defecto.
- Nada se puede hacer público “por accidente”.
- La privacidad se controla explícitamente, no implícitamente.
Esto se logra gracias a Compact, el lenguaje de smart contracts de Midnight, y al uso de Zero‑Knowledge Proofs (zkSNARKs) para validar transacciones sin revelar datos.
¿Qué es Compact?
Compact es un lenguaje declarativo diseñado específicamente para construir aplicaciones privacy‑first.
Cuando escribes un contrato en Compact:
- Defines la lógica de negocio.
- Defines qué datos son públicos.
- Defines qué datos permanecen privados.
El compilador genera:
- APIs en JavaScript / TypeScript para tu DApp.
- Los artefactos criptográficos necesarios para generar pruebas ZK.
Todo esto ocurre localmente en el entorno del desarrollador.
Componentes básicos de un contrato en Compact
Todo contrato en Midnight se construye a partir de los mismos bloques:
Ledger state (estado público)
Datos que viven en la cadena y son visibles para todos.
export ledger value: Uint;
Witnesses (entradas privadas)
Los witnesses representan datos que vienen del usuario o del frontend. Son privados por defecto y Compact no permite que se filtren accidentalmente.
witness getSecret(): Bytes;
Circuits (lógica verificable)
Los circuits definen qué puede hacer el contrato. Solo los circuits marcados como export pueden ser llamados desde fuera.
export circuit get(): Uint {
return value;
}
Constructor
Se ejecuta una sola vez, al crear el contrato.
constructor(sk: Bytes, v: Uint) {
value = v;
}
Selective disclosure: disclose()
Una de las reglas más importantes de Compact es:
No puedes hacer público un dato privado sin decirlo explícitamente.
Si intentas usar un witness directamente en el ledger o como retorno, el compilador falla.
Forma correcta:
export ledger publicData: Bytes;
export circuit record(): [] {
publicData = disclose(getSecret());
}
Forma incorrecta (error de compilación):
publicData = getSecret(); // ❌
Esto elimina una clase completa de errores comunes en otros ecosistemas.
Opaque types: cuando Compact no debe “mirar” el dato
Compact permite tipos opacos como Opaque. Estos tipos:
- Pueden almacenarse o transferirse.
- No pueden ser inspeccionados dentro del contrato.
- Son visibles en el frontend (TypeScript), pero no manipulables en Compact.
Son útiles para:
- Mensajes
- Metadatos
- Contenido arbitrario (ej. bulletin boards)
- Compromisos y hashing
Primitivas criptográficas para pruebas sin revelar datos
Para probar propiedades sobre datos sin revelarlos, Compact incluye:
persistentCommit(value, random);
transientCommit(value);
Estas funciones son clave para:
- Votaciones privadas
- Identidad verificable
- Autenticación sin revelar credenciales
El rol del proof server
Toda la magia ZK ocurre fuera de la blockchain. El proof server:
- Corre localmente o en infraestructura controlada.
- Nunca expone datos privados a la red.
- Solo devuelve pruebas criptográficas válidas.
Esto permite que la blockchain valide hechos sin conocer los datos subyacentes.
Cómo pensar un contrato en Midnight
Al escribir en Midnight, conviene preguntarse:
- ¿Este dato realmente debe ser público?
- ¿Qué necesita verificar la red y qué no?
- ¿Puedo probar esta condición sin revelar el valor?
- ¿Quién controla el proof server?
Compact no solo te da herramientas, te obliga a pensar bien el modelo de datos.
Conclusión
Escribir smart contracts en Midnight no es solo aprender un nuevo lenguaje; es adoptar una forma distinta de diseñar aplicaciones descentralizadas:
- Privacidad por defecto
- Disclosure explícito
- Separación clara entre datos, lógica y pruebas
- Seguridad reforzada a nivel de compilador
Si vienes de ecosistemas como Solidity o Plutus, Compact puede sentirse distinto al principio. Pero una vez que el modelo hace clic, es difícil volver atrás. La privacidad deja de ser un “feature” y pasa a ser parte del lenguaje.