← Todos los artículos

N.º 11Solucky

Quién puede tocar el bote

Alex contó cómo Solucky sortea un ganador. Esta es la otra mitad: dónde está el dinero de los jugadores hasta entonces, quién puede moverlo y quién no.

Vincent Porret

Cofundador y CEO · · 4 min de lectura

Estampa 11, Trenza. Gotas y peines sobre un baño, sacada al construir el sitio.Pasa el puntero por encima para dejar caer tinta.

Alex contó cómo Solucky sortea su boleto ganador. En riesgos, el sorteo es solo la mitad de la pregunta. La otra mitad es la custodia: dónde está el dinero entre el primer boleto y el pago, quién puede moverlo y qué se lo impide. En un banco, la respuesta es un conjunto de controles y las personas que los aprueban. En Solucky 1.0, es un programa de ocho instrucciones, y cualquiera puede leerlas todas.

El bote es la ronda

No hay ninguna caja fuerte ni ningún wallet de la casa en medio. Cada día UTC es una ronda, y la propia cuenta de la ronda guarda su bote, además del pequeño saldo que Solana exige para que una cuenta exista. Un boleto es una transferencia simple del comprador directamente a esa cuenta. La cuenta pertenece al programa, y ninguna persona tiene una clave que pueda firmar por ella, así que los lamports solo salen cuando lo dice una de las instrucciones del programa.

De las ocho, dos sacan dinero de una ronda, y el código es lo bastante corto para citarlo. claim_prize paga al ganador:

let fee = fee_for(round.pot, round.fee_bps);
let payout = round.pot - fee;

ctx.accounts.round.sub_lamports(payout)?;
ctx.accounts.owner.add_lamports(payout)?;

collect_fee paga a la casa, y nada más saca lamports de una ronda. Una tercera instrucción, close_ticket, solo devuelve el alquiler de la cuenta de un boleto al jugador que lo pagó, cuando la ronda ya está liquidada.

Cualquiera puede enviarla, solo una persona cobra

claim_prize no necesita ninguna firma. El ganador, un amigo o un script pueden enviarla, pero el programa comprueba que la cuenta a la que paga es el propietario escrito en el boleto ganador, y que el boleto pertenece a esta ronda. Si se envía con cualquier otra dirección, falla. La comisión funciona igual: cualquiera puede enviar collect_fee, y solo paga a la dirección de tesorería que figura en la configuración del programa. Tampoco hay plazo para reclamar. Un premio sin reclamar espera en su ronda, y nadie más se lo puede llevar.

El orden importa igual. collect_fee solo funciona con una ronda liquidada, así que la comisión se queda en la ronda hasta que se ha pagado al ganador. Una tesorería mal configurada, o simplemente lenta, no puede retener un premio.

La casa cobra después del ganador, nunca antes.

Lo que puede cambiar el operador

El programa tiene una autoridad, y hoy somos nosotros. Puede cambiar el precio del boleto, la comisión de la casa, el número de boleto más alto y la dirección de tesorería, y puede pausar las ventas. Cada uno de esos poderes tiene un límite. La comisión tiene un tope en el código del 10 %, MAX_FEE_BPS: u16 = 1_000. Una ronda copia el precio y la comisión de la configuración cuando se vende su primer boleto, y se los queda, así que un cambio solo llega a las rondas que aún no se han abierto, nunca a un bote que ya se está llenando. Además, los compradores envían lo máximo que aceptan pagar, así que un precio subido entre la pantalla y la firma hace fallar la compra en lugar de cobrar más.

Una pausa detiene la venta de boletos y nada más. El cierre, el sorteo y el cobro siguen abiertos, y un comentario del código da la razón: que una pausa nunca pueda bloquear un bote. La única palanca que la autoridad conserva sobre el dinero es la dirección de tesorería: una comisión va a la tesorería que esté configurada cuando se cobra. Lo que no tiene está igual de claro. Ninguna instrucción envía un bote a otro sitio que a su ganador, ni una comisión a otro sitio que a la tesorería.

Redondeos y desbordamientos

La comisión se redondea hacia abajo, así que una fracción de lamport va al ganador, no a la casa. El número de boletos y el bote se suman con aritmética comprobada, y el programa se compila con los controles de desbordamiento activados, así que un desbordamiento anula la transacción en lugar de dar la vuelta. Y un boleto cuesta al menos 0,001 SOL: con la comisión limitada al 10 %, un premio siempre está por encima del saldo mínimo que necesita un wallet vacío en Solana, así que siempre se puede pagar.

Lo que el código no cubre

Hay dos límites fuera de las instrucciones. El programa se puede actualizar, así que quien tenga su autoridad de actualización podría sustituir el código, y cada garantía de arriba vale para el código desplegado ahora. Nuestro README lo dice: un programa actualizable solo es tan fiable como su autoridad de actualización, y la salida es un multisig, o hacer el programa inmutable cuando sea estable. Y como escribió Alex, el sorteo es justo frente a los jugadores, no frente a los validadores. Por eso la app pública funciona en devnet, con SOL de prueba, y por eso nuestra política de seguridad dice que no se jueguen botes con dinero real en este sorteo.

En un banco, controles como estos viven en un documento de políticas. Aquí viven en el código, y se comprueban en cada transacción.

Vincent