Skip to main content

Module 0x3::genesis

use 0x1::option;
use 0x1::vector;
use 0x2::balance;
use 0x2::coin;
use 0x2::object;
use 0x2::sui;
use 0x2::tx_context;
use 0x3::stake_subsidy;
use 0x3::sui_system;
use 0x3::sui_system_state_inner;
use 0x3::validator;
use 0x3::validator_set;

Struct GenesisValidatorMetadata

struct GenesisValidatorMetadata has copy, drop
Fields
name: vector<u8>
description: vector<u8>
image_url: vector<u8>
project_url: vector<u8>
sui_address: address
gas_price: u64
commission_rate: u64
protocol_public_key: vector<u8>
proof_of_possession: vector<u8>
network_public_key: vector<u8>
worker_public_key: vector<u8>
network_address: vector<u8>
p2p_address: vector<u8>
primary_address: vector<u8>
worker_address: vector<u8>

Struct GenesisChainParameters

struct GenesisChainParameters has copy, drop
Fields
protocol_version: u64
chain_start_timestamp_ms: u64
epoch_duration_ms: u64
stake_subsidy_start_epoch: u64
stake_subsidy_initial_distribution_amount: u64
stake_subsidy_period_length: u64
stake_subsidy_decrease_rate: u16
max_validator_count: u64
min_validator_joining_stake: u64
validator_low_stake_threshold: u64
validator_very_low_stake_threshold: u64
validator_low_stake_grace_period: u64

Struct TokenDistributionSchedule

struct TokenDistributionSchedule
Fields
stake_subsidy_fund_mist: u64
allocations: vector<genesis::TokenAllocation>

Struct TokenAllocation

struct TokenAllocation
Fields
recipient_address: address
amount_mist: u64
staked_with_validator: option::Option<address>
Indicates if this allocation should be staked at genesis and with which validator

Constants

The create function was called with duplicate validators.

const EDuplicateValidator: u64 = 1;

The create function was called at a non-genesis epoch.

const ENotCalledAtGenesis: u64 = 0;

Function create

This function will be explicitly called once at genesis. It will create a singleton SuiSystemState object, which contains all the information we need in the system.

fun create(sui_system_state_id: object::UID, sui_supply: balance::Balance<sui::SUI>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
Implementation
fun create(
    sui_system_state_id: UID,
    mut sui_supply: Balance<SUI>,
    genesis_chain_parameters: GenesisChainParameters,
    genesis_validators: vector<GenesisValidatorMetadata>,
    token_distribution_schedule: TokenDistributionSchedule,
    ctx: &mut TxContext,
) {
    // Ensure this is only called at genesis
    assert!(ctx.epoch() == 0, ENotCalledAtGenesis);

    let TokenDistributionSchedule {
        stake_subsidy_fund_mist,
        allocations,
    } = token_distribution_schedule;

    let subsidy_fund = sui_supply.split(stake_subsidy_fund_mist);
    let storage_fund = balance::zero();

    // Create all the `Validator` structs
    let mut validators = vector[];
    let count = genesis_validators.length();
    let mut i = 0;
    while (i < count) {
        let GenesisValidatorMetadata {
            name,
            description,
            image_url,
            project_url,
            sui_address,
            gas_price,
            commission_rate,
            protocol_public_key,
            proof_of_possession,
            network_public_key,
            worker_public_key,
            network_address,
            p2p_address,
            primary_address,
            worker_address,
        } = genesis_validators[i];

        let validator = validator::new(
            sui_address,
            protocol_public_key,
            network_public_key,
            worker_public_key,
            proof_of_possession,
            name,
            description,
            image_url,
            project_url,
            network_address,
            p2p_address,
            primary_address,
            worker_address,
            gas_price,
            commission_rate,
            ctx
        );

        // Ensure that each validator is unique
        assert!(
            !validator_set::is_duplicate_validator(&validators, &validator),
            EDuplicateValidator,
        );

        validators.push_back(validator);

        i = i + 1;
    };

    // Allocate tokens and staking operations
    allocate_tokens(
        sui_supply,
        allocations,
        &mut validators,
        ctx
    );

    // Activate all validators
    activate_validators(&mut validators);

    let system_parameters = sui_system_state_inner::create_system_parameters(
        genesis_chain_parameters.epoch_duration_ms,
        genesis_chain_parameters.stake_subsidy_start_epoch,

        // Validator committee parameters
        genesis_chain_parameters.max_validator_count,
        genesis_chain_parameters.min_validator_joining_stake,
        genesis_chain_parameters.validator_low_stake_threshold,
        genesis_chain_parameters.validator_very_low_stake_threshold,
        genesis_chain_parameters.validator_low_stake_grace_period,

        ctx,
    );

    let stake_subsidy = stake_subsidy::create(
        subsidy_fund,
        genesis_chain_parameters.stake_subsidy_initial_distribution_amount,
        genesis_chain_parameters.stake_subsidy_period_length,
        genesis_chain_parameters.stake_subsidy_decrease_rate,
        ctx,
    );

    sui_system::create(
        sui_system_state_id,
        validators,
        storage_fund,
        genesis_chain_parameters.protocol_version,
        genesis_chain_parameters.chain_start_timestamp_ms,
        system_parameters,
        stake_subsidy,
        ctx,
    );
}

Function allocate_tokens

fun allocate_tokens(sui_supply: balance::Balance<sui::SUI>, allocations: vector<genesis::TokenAllocation>, validators: &mut vector<validator::Validator>, ctx: &mut tx_context::TxContext)
Implementation
fun allocate_tokens(
    mut sui_supply: Balance<SUI>,
    mut allocations: vector<TokenAllocation>,
    validators: &mut vector<Validator>,
    ctx: &mut TxContext,
) {

    while (!allocations.is_empty()) {
        let TokenAllocation {
            recipient_address,
            amount_mist,
            staked_with_validator,
        } = allocations.pop_back();

        let allocation_balance = sui_supply.split(amount_mist);

        if (staked_with_validator.is_some()) {
            let validator_address = staked_with_validator.destroy_some();
            let validator = validator_set::get_validator_mut(validators, validator_address);
            validator.request_add_stake_at_genesis(
                allocation_balance,
                recipient_address,
                ctx
            );
        } else {
            sui::transfer(
                allocation_balance.into_coin(ctx),
                recipient_address,
            );
        };
    };
    allocations.destroy_empty();

    // Provided allocations must fully allocate the sui_supply and there
    // should be none left at this point.
    sui_supply.destroy_zero();
}

Function activate_validators

fun activate_validators(validators: &mut vector<validator::Validator>)
Implementation
fun activate_validators(validators: &mut vector<Validator>) {
    // Activate all genesis validators
    let count = validators.length();
    let mut i = 0;
    while (i < count) {
        let validator = &mut validators[i];
        validator.activate(0);

        i = i + 1;
    };

}