Sui.

Пост

Поделитесь своими знаниями.

Bekky.
Jul 17, 2025
Экспертные Вопросы и Ответы

Лучшие практики внедрения графиков передачи прав собственности в Sui

Я разрабатываю систему передачи токенов (например, для распределения ресурсов между командами или блокирования инвесторов) в Sui Move, и мне необходимо обеспечить следующее:

Безопасность — отсутствие преждевременного вывода средств

Гибкость — опора на скалы, линейная или постепенная укладка

Эффективность использования газа — минимальные затраты на хранение

Прозрачность — простая проверка статуса наделения

Текущие проблемы:

  • Базовые таймеры работают, но не имеют детального управления
  • Проблемы с управлением несколькими получателями
  • Не знаете, как обращаться с случаями досрочного увольнения

Вопросы:

Какая архитектура наиболее безопасна для передачи прав на контракты?

Как реализовать различные кривые передачи прав собственности (линейные, ступенчатые, скальные)?

Как лучше всего работать с отзываемыми и безотзывными графиками?

Распространенные уязвимости, которых следует избегать?

  • Sui
  • Move
0
1
Поделиться
Комментарии
.

Ответы

1
Evgeniy CRYPTOCOIN.
Jul 17 2025, 13:24

####1. Базовая архитектура тестирования

######Минимальная жизнеспособная реализация

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);  
    }  
}  

Ключевые компоненты:

  • Clockна основе временных меток (а не номеров блоков)
  • Самостоятельно настраиваемые объекты расписания
  • По умолчанию линейное наделение

####2. Продвинутые паттерны наделения

######Клифф + Линейное жилет

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  
}  

#####Поэтапное распределение (несколько этапов)

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. Усиления безопасности

######Отзывное наделение (административный контроль)

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);  
}  

#####Антифронтальный запуск

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. Методы оптимизации газа

######Графики пакетной сдачи

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);  
    }  
}  

#####Скидки на хранение

// Use small types where possible  
struct CompactVesting {  
    start_time: u64,  
    duration_ms: u32, // Sufficient for 49-day periods  
    claimed: u64  
}  

####5. Распространенные уязвимости

Атаки Oracle со временем

// UNSAFE: Trusting user-provided timestamps  
fun unsafe_claim(user_time: u64) { ... }  

Ошибки округления

// May leave "dust" unclaimed  
let vested = (amount * elapsed) / duration; // Use checked_math  

Отсутствует логика отзыва

// Irrevocable vesting may violate securities laws  
struct DangerousVesting { ... }  

####6. Стратегии тестирования

#####Тестирование макетов часов

#[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);  
}  

#####Тестирование нечеткий

#[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);  
}  
0
Комментарии
.

Знаете ответ?

Пожалуйста, войдите в систему и поделитесь им.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

431Посты636Ответы
Sui.X.Peera.

Заработай свою долю из 1000 Sui

Зарабатывай очки репутации и получай награды за помощь в развитии сообщества Sui.

Кампания вознагражденийИюль