Publicación
Comparte tu conocimiento.
Mejores prácticas para implementar cronogramas de adjudicación de derechos en Sui
Estoy diseñando un sistema de transferencia de fichas (por ejemplo, para asignar equipos o bloquear a inversores) en Sui Move y necesito asegurarme de que:
Seguridad: sin retiros prematuros
Flexibilidad: soporte para acantilados, colocación lineal o gradual
Eficiencia del gas: costos mínimos de almacenamiento
Transparencia: fácil verificación del estado de concesión
Desafíos actuales:
- Los bloqueos de tiempo básicos funcionan pero carecen de un control granular
- ¿Tiene problemas con la administración de múltiples destinatarios
- ¿No estás seguro de cómo gestionar los casos de despido anticipado
Preguntas:
¿Cuál es la arquitectura más segura para la adjudicación de contratos?
¿Cómo implementar diferentes curvas de adjudicación (lineales, graduadas, en pendiente)?
¿Cuál es la mejor manera de gestionar los plazos revocables frente a los irrevocables?
¿Vulnerabilidades comunes que se deben evitar?
- Sui
- Move
Respuestas
1####** 1. Arquitectura Core Vesting**
#####Implementación mínima viable
module vesting::linear {
use sui::coin;
use sui::clock;
use sui::balance;
use sui::tx_context;
struct VestingSchedule has key {
id: UID,
recipient: address,
total_amount: u64,
start_time: u64, // Clock timestamp
duration_ms: u64, // Total vesting period
claimed: u64
}
/// Initialize vesting
public entry fn create(
recipient: address,
total_amount: u64,
duration_ms: u64,
clock: &Clock,
ctx: &mut TxContext
) {
let schedule = VestingSchedule {
id: object::new(ctx),
recipient,
total_amount,
start_time: clock.timestamp_ms,
duration_ms,
claimed: 0
};
transfer::transfer(schedule, recipient);
}
}
Componentes clave:
Clock
marcas de tiempo basadas en - (no números de bloque)- Objetos de programación autocustodiados
- Adquisición lineal por defecto
2. Patrones avanzados de conferencia*
#####Acantilado + Revestimiento lineal
public fun claimable_amount(
schedule: &VestingSchedule,
clock: &Clock
): u64 {
let elapsed = clock.timestamp_ms.saturating_sub(schedule.start_time);
// Cliff period (e.g., 1 year)
if (elapsed < CLIFF_MS) return 0;
// Linear vesting after cliff
let vested = (schedule.total_amount * elapsed) / schedule.duration_ms;
vested - schedule.claimed
}
#####Adquisición gradual (varios hitos)
struct GradedVesting has key {
id: UID,
milestones: vector<Milestone>, // [{time: u64, percent: u8}]
claimed: u64
}
public fun graded_claimable(schedule: &GradedVesting, clock: &Clock): u64 {
let total_vested = 0;
let i = 0;
while (i < vector::length(&schedule.milestones)) {
let milestone = vector::borrow(&schedule.milestones, i);
if (clock.timestamp_ms >= milestone.time) {
total_vested = total_vested +
(schedule.total_amount * milestone.percent as u64) / 100;
};
i = i + 1;
};
total_vested - schedule.claimed
}
####3. Mejoras de seguridad
#####Adhesión revocable (controles de administración)
struct AdminCap has key { id: UID }
public entry fn revoke(
schedule: VestingSchedule,
admin_cap: &AdminCap,
ctx: &mut TxContext
) {
assert!(address_of(signer) == admin_cap.admin, EUnauthorized);
let remaining = schedule.total_amount - schedule.claimed;
coin::transfer(remaining, admin_cap.admin, ctx);
object::delete(schedule);
}
#####Antifrontrunning
public entry fn claim(
schedule: &mut VestingSchedule,
clock: &Clock,
ctx: &mut TxContext
) {
let amount = claimable_amount(schedule, clock);
assert!(amount > 0, ENothingToClaim);
assert!(tx_context::epoch(ctx) == clock.epoch(), EStaleClock);
schedule.claimed = schedule.claimed + amount;
transfer::public_transfer(coin::mint(amount, ctx), schedule.recipient);
}
####4. Técnicas de optimización de gas
#####Cronogramas de adquisición de lotes
struct BatchVesting has key {
id: UID,
schedules: Table<address, VestingSchedule>
}
// Claim all eligible in one TXN
public entry fn batch_claim(batch: &mut BatchVesting, clock: &Clock) {
let iter = table::iter(&mut batch.schedules);
while (table::has_next(&iter)) {
let (addr, schedule) = table::next(&iter);
let amount = claimable_amount(schedule, clock);
if (amount > 0) transfer_coins(addr, amount);
}
}
#####Reembolsos de almacenamiento
// Use small types where possible
struct CompactVesting {
start_time: u64,
duration_ms: u32, // Sufficient for 49-day periods
claimed: u64
}
####5. Vulnerabilidades comunes
❌Time Oracle ataca a Oráculo
// UNSAFE: Trusting user-provided timestamps
fun unsafe_claim(user_time: u64) { ... }
❌Errores de redondeo
// May leave "dust" unclaimed
let vested = (amount * elapsed) / duration; // Use checked_math
❌Falta la lógica de revocación
// Irrevocable vesting may violate securities laws
struct DangerousVesting { ... }
6. Estrategias de prueba*
#####Simulacro de prueba de reloj
#[test]
fun test_cliff_period() {
let clock = mock_clock(0);
let schedule = create_vesting(CLIFF_MS * 2);
// Before cliff
test_clock::advance(&mut clock, CLIFF_MS - 1);
assert!(claimable(&schedule, &clock) == 0, ETestFail);
// After cliff
test_clock::advance(&mut clock, 1);
assert!(claimable(...) > 0, ETestFail);
}
#####Prueba de fuzz
#[test]
fun test_overflow_scenarios() {
let schedule = VestingSchedule {
start_time: u64::MAX - 1000,
duration_ms: 2000
};
// Should handle wrap-around correctly
claimable_amount(&schedule, &clock);
}
Sabes la respuesta?
Inicie sesión y compártalo.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Gana tu parte de 1000 Sui
Gana puntos de reputación y obtén recompensas por ayudar a crecer a la comunidad de Sui.
- ¿Por qué BCS requiere un orden de campo exacto para la deserialización cuando las estructuras Move tienen campos con nombre?53
- «Errores de verificación de múltiples fuentes» en las publicaciones del módulo Sui Move: resolución automática de errores43
- Fallo en la transacción Sui: objetos reservados para otra transacción25
- ¿Cómo interactúan las restricciones de capacidad con los campos dinámicos en colecciones heterogéneas?05