Backend CRUD completo para gestionar inventario de relojes en Solana
Desarrollado con Rust y Anchor Framework
Este proyecto implementa un sistema de inventario descentralizado para relojes en la blockchain de Solana. Permite realizar operaciones CRUD completas (Crear, Leer, Actualizar, Eliminar) sobre un inventario de relojes, almacenando la información de forma segura y permanente en la blockchain.
- Marca: Nombre de la marca (máx. 50 caracteres)
- Modelo: Modelo del reloj (máx. 50 caracteres)
- Piezas: Número de piezas del reloj
- Disponible: Estado de disponibilidad (true/false)
- Propietario: Dirección de la wallet propietaria
- Fecha de creación: Timestamp automático
- Fecha de actualización: Timestamp automático
Cada reloj se identifica de forma única mediante una PDA generada con las siguientes seeds:
seeds = [
b"reloj", // Prefijo constante
propietario.key(), // Dirección del propietario
marca.as_bytes(), // Marca del reloj
modelo.as_bytes() // Modelo del reloj
]Ventajas de este diseño:
- ✅ Cada combinación propietario + marca + modelo es única
- ✅ No se pueden crear relojes duplicados
- ✅ Las direcciones son determinísticas y verificables
- ✅ No se requieren seeds adicionales del usuario
pub struct Reloj {
pub propietario: Pubkey, // 32 bytes
pub marca: String, // 4 + 50 bytes
pub modelo: String, // 4 + 50 bytes
pub piezas: u32, // 4 bytes
pub disponible: bool, // 1 byte
pub fecha_creacion: i64, // 8 bytes
pub fecha_actualizacion: i64, // 8 bytes
pub bump: u8, // 1 byte
}
// Total: ~162 bytes + discriminador (8 bytes) = 170 bytesCrea un nuevo reloj en el inventario.
Parámetros:
marca: String- Marca del relojmodelo: String- Modelo del relojpiezas: u32- Número de piezasdisponible: bool- Disponibilidad inicial
Validaciones:
- Marca no puede exceder 50 caracteres
- Modelo no puede exceder 50 caracteres
- No puede existir otro reloj con la misma combinación propietario+marca+modelo
Ejemplo de uso:
await program.methods
.crearReloj("Rolex", "Submariner", 150, true)
.accounts({
reloj: relojPda,
propietario: wallet.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.rpc();Obtiene la información completa de un reloj existente.
Ejemplo de uso:
const reloj = await program.account.reloj.fetch(relojPda);
console.log(reloj.marca, reloj.modelo, reloj.piezas);Listar todos los relojes de un propietario:
const relojes = await program.account.reloj.all([
{
memcmp: {
offset: 8,
bytes: wallet.publicKey.toBase58(),
},
},
]);Actualiza uno o más campos del reloj. Todos los parámetros son opcionales.
Parámetros:
marca: Option<String>- Nueva marca (opcional)modelo: Option<String>- Nuevo modelo (opcional)piezas: Option<u32>- Nuevas piezas (opcional)disponible: Option<bool>- Nueva disponibilidad (opcional)
Ejemplo de uso:
await program.methods
.actualizarReloj("Omega", "Speedmaster", 200, false)
.accounts({
reloj: relojPda,
propietario: wallet.publicKey,
})
.rpc();Función especializada para actualizar solo el número de piezas.
Parámetros:
piezas: u32- Nuevo número de piezas
Ejemplo de uso:
await program.methods
.actualizarPiezas(175)
.accounts({
reloj: relojPda,
propietario: wallet.publicKey,
})
.rpc();Función especializada para cambiar solo el estado de disponibilidad.
Parámetros:
disponible: bool- Nuevo estado de disponibilidad
Ejemplo de uso:
await program.methods
.cambiarDisponibilidad(true)
.accounts({
reloj: relojPda,
propietario: wallet.publicKey,
})
.rpc();Elimina un reloj del inventario y recupera el rent a la wallet del propietario.
Ejemplo de uso:
await program.methods
.eliminarReloj()
.accounts({
reloj: relojPda,
propietario: wallet.publicKey,
})
.rpc();El programa implementa múltiples capas de seguridad:
#[account(has_one = propietario)]Solo el propietario puede modificar o eliminar sus relojes.
require!(marca.len() <= 50, ErrorCode::MarcaMuyLarga);
require!(modelo.len() <= 50, ErrorCode::ModeloMuyLargo);Previene ataques de overflow y garantiza límites de datos.
seeds = [b"reloj", propietario.key().as_ref(), marca.as_bytes(), modelo.as_bytes()],
bump = reloj.bumpValida que las PDAs sean correctas y no manipuladas.
#[error_code]
pub enum ErrorCode {
#[msg("La marca no puede tener más de 50 caracteres")]
MarcaMuyLarga,
#[msg("El modelo no puede tener más de 50 caracteres")]
ModeloMuyLargo,
}- Crear reloj: ~0.00124 SOL (rent-exempt) + ~0.000005 SOL (tx fee)
- Actualizar reloj: ~0.000005 SOL (tx fee)
- Eliminar reloj: Recuperas el rent (~0.00124 SOL) - tx fee
Nota: Los costos pueden variar según la congestión de la red.
Gestionar inventario de forma transparente y verificable en blockchain.
Seguimiento de piezas y disponibilidad de relojes en reparación.
Registro inmutable y verificable de colecciones personales.
Control de stock descentralizado entre múltiples ubicaciones.
Registro de relojes en custodia con timestamps verificables.
- Ve a Solana Playground
- Crea un nuevo proyecto
- Copia el contenido de
src/lib.rsal archivolib.rsdel playground - Copia el contenido de
client/client.tsal archivoclient.tsdel playground
- Click en "Connect Wallet" en la esquina superior derecha
- Crea una nueva wallet o importa una existente
- Asegúrate de estar en Devnet
- Solicita SOL de prueba desde el faucet
- Click en el botón "Build" (icono de martillo)
- Espera a que compile (puede tomar 1-2 minutos)
- Una vez compilado, click en "Deploy"
- Confirma la transacción en tu wallet
- Copia el Program ID que aparece
- Ve a la pestaña
client.ts - Click en el botón "Run" (icono de play)
- Observa la consola para ver todas las operaciones CRUD ejecutándose
La consola mostrará:
- ✅ Creación de relojes
- 📖 Lectura de datos
- 🔧 Actualizaciones de piezas
- 🔄 Cambios de disponibilidad
- ✏️ Actualizaciones completas
- 📦 Creación de múltiples relojes
- 📋 Listado completo del inventario
Solución: Solicita SOL de prueba del faucet de Devnet.
Solución: El reloj con esa combinación de marca+modelo ya existe. Usa otra combinación o elimina el existente.
Solución: Normal en el primer deploy. Ignora este mensaje.
Solución: Verifica que estés usando la wallet correcta y que tengas suficiente SOL.
├── declare_id!() // Program ID
├── #[program] // Módulo del programa
│ ├── crear_reloj() // CREATE
│ ├── actualizar_reloj() // UPDATE (múltiple)
│ ├── actualizar_piezas() // UPDATE (piezas)
│ ├── cambiar_disponibilidad() // UPDATE (disponibilidad)
│ └── eliminar_reloj() // DELETE
├── CrearReloj // Context para crear
├── ActualizarReloj // Context para actualizar
├── EliminarReloj // Context para eliminar
├── Reloj // Estructura de datos
└── ErrorCode // Errores personalizados
├── main() // Función principal
│ ├── Crear reloj // Test CREATE
│ ├── Leer reloj // Test READ
│ ├── Actualizar piezas // Test UPDATE
│ ├── Cambiar disponibilidad // Test UPDATE
│ ├── Actualizar múltiple // Test UPDATE
│ ├── Crear múltiples relojes // Test CREATE múltiple
│ └── Listar todos los relojes // Test READ múltiple
Proyecto desarrollado como backend CRUD en Solana usando Rust y Anchor Framework.
MIT License - Libre para uso educativo y comercial.
¡Listo para usar en Solana Playground! 🚀