Module iota_system::timelocked_staking
- Struct
TimelockedStakedIota - Constants
- Function
request_add_stake - Function
request_add_stake_mul_bal - Function
request_withdraw_stake - Function
request_add_stake_non_entry - Function
request_add_stake_mul_bal_non_entry - Function
request_withdraw_stake_non_entry - Function
unlock - Function
unlock_with_clock - Function
split - Function
split_staked_iota - Function
join_staked_iota - Function
transfer_to_sender - Function
transfer_to_sender_multiple - Function
is_equal_staking_metadata - Function
pool_id - Function
staked_iota_amount - Function
stake_activation_epoch - Function
expiration_timestamp_ms - Function
label - Function
is_labeled_with - Function
unpack - Function
transfer - Function
transfer_multiple - Function
request_add_stake_at_genesis
use iota::address;
use iota::bag;
use iota::balance;
use iota::clock;
use iota::coin;
use iota::config;
use iota::deny_list;
use iota::dynamic_field;
use iota::dynamic_object_field;
use iota::event;
use iota::hex;
use iota::iota;
use iota::labeler;
use iota::object;
use iota::pay;
use iota::priority_queue;
use iota::system_admin_cap;
use iota::table;
use iota::table_vec;
use iota::timelock;
use iota::transfer;
use iota::tx_context;
use iota::types;
use iota::url;
use iota::vec_map;
use iota::vec_set;
use iota::versioned;
use iota_system::iota_system;
use iota_system::iota_system_state_inner;
use iota_system::staking_pool;
use iota_system::storage_fund;
use iota_system::validator;
use iota_system::validator_cap;
use iota_system::validator_set;
use iota_system::validator_wrapper;
use iota_system::voting_power;
use std::address;
use std::ascii;
use std::bcs;
use std::option;
use std::string;
use std::type_name;
use std::u64;
use std::vector;
Struct TimelockedStakedIota
A self-custodial object holding the timelocked staked IOTA tokens.
public struct TimelockedStakedIota has key
Fields
id: iota::object::UIDstaked_iota: iota_system::staking_pool::StakedIotaA self-custodial object holding the staked IOTA tokens.
expiration_timestamp_ms: u64This is the epoch time stamp of when the lock expires.
label: std::option::Option<std::string::String>Timelock related label.
Constants
For when trying to stake an expired time-locked balance.
const ETimeLockShouldNotBeExpired: u64 = 0;
Incompatible objects when joining TimelockedStakedIota.
const EIncompatibleTimelockedStakedIota: u64 = 1;
#[error]
const ETimelockedStakedIotaShouldBeExpired: vector<u8> = b"TimelockedStakedIota is not expired.";
Function request_add_stake
Add a time-locked stake to a validator's staking pool.
public entry fun request_add_stake(iota_system: &mut iota_system::iota_system::IotaSystemState, timelocked_balance: iota::timelock::TimeLock<iota::balance::Balance<iota::iota::IOTA>>, validator_address: address, ctx: &mut iota::tx_context::TxContext)
Implementation
public entry fun request_add_stake(
iota_system: &mut IotaSystemState,
timelocked_balance: TimeLock<Balance<IOTA>>,
validator_address: address,
ctx: &mut TxContext,
) {
// Stake the time-locked balance.
let timelocked_staked_iota = request_add_stake_non_entry(
iota_system,
timelocked_balance,
validator_address,
ctx,
);
// Transfer the receipt to the sender.
timelocked_staked_iota.transfer_to_sender(ctx);
}
Function request_add_stake_mul_bal
Add a time-locked stake to a validator's staking pool using multiple time-locked balances.
public entry fun request_add_stake_mul_bal(iota_system: &mut iota_system::iota_system::IotaSystemState, timelocked_balances: vector<iota::timelock::TimeLock<iota::balance::Balance<iota::iota::IOTA>>>, validator_address: address, ctx: &mut iota::tx_context::TxContext)
Implementation
public entry fun request_add_stake_mul_bal(
iota_system: &mut IotaSystemState,
timelocked_balances: vector<TimeLock<Balance<IOTA>>>,
validator_address: address,
ctx: &mut TxContext,
) {
// Stake the time-locked balances.
let mut receipts = request_add_stake_mul_bal_non_entry(
iota_system,
timelocked_balances,
validator_address,
ctx,
);
// Create useful variables.
let (mut i, len) = (0, receipts.length());
// Send all the receipts to the sender.
while (i < len) {
// Take a receipt.
let receipt = receipts.pop_back();
// Transfer the receipt to the sender.
receipt.transfer_to_sender(ctx);
i = i + 1
};
// Destroy the empty vector.
vector::destroy_empty(receipts)
}
Function request_withdraw_stake
Withdraw a time-locked stake from a validator's staking pool.
public entry fun request_withdraw_stake(iota_system: &mut iota_system::iota_system::IotaSystemState, timelocked_staked_iota: iota_system::timelocked_staking::TimelockedStakedIota, ctx: &mut iota::tx_context::TxContext)
Implementation
public entry fun request_withdraw_stake(
iota_system: &mut IotaSystemState,
timelocked_staked_iota: TimelockedStakedIota,
ctx: &mut TxContext,
) {
// Withdraw the time-locked balance.
let (timelocked_balance, reward) = request_withdraw_stake_non_entry(
iota_system,
timelocked_staked_iota,
ctx,
);
// Transfer the withdrawn time-locked balance to the sender.
timelocked_balance.transfer_to_sender(ctx);
// Send coins only if the reward is not zero.
if (reward.value() > 0) {
transfer::public_transfer(reward.into_coin(ctx), ctx.sender());
} else {
balance::destroy_zero(reward);
}
}
Function request_add_stake_non_entry
The non-entry version of request_add_stake, which returns the time-locked staked IOTA instead of transferring it to the sender.
public fun request_add_stake_non_entry(iota_system: &mut iota_system::iota_system::IotaSystemState, timelocked_balance: iota::timelock::TimeLock<iota::balance::Balance<iota::iota::IOTA>>, validator_address: address, ctx: &mut iota::tx_context::TxContext): iota_system::timelocked_staking::TimelockedStakedIota
Implementation
public fun request_add_stake_non_entry(
iota_system: &mut IotaSystemState,
timelocked_balance: TimeLock<Balance<IOTA>>,
validator_address: address,
ctx: &mut TxContext,
): TimelockedStakedIota {
// Check the preconditions.
assert!(timelocked_balance.is_locked(ctx), ETimeLockShouldNotBeExpired);
// Unpack the time-locked balance.
let sys_admin_cap = iota_system.load_iota_system_admin_cap();
let (balance, expiration_timestamp_ms, label) = timelock::system_unpack(
sys_admin_cap,
timelocked_balance,
);
// Stake the time-locked balance.
let staked_iota = iota_system.request_add_stake_non_entry(
balance.into_coin(ctx),
validator_address,
ctx,
);
// Create and return a receipt.
TimelockedStakedIota {
id: object::new(ctx),
staked_iota,
expiration_timestamp_ms,
label,
}
}
Function request_add_stake_mul_bal_non_entry
The non-entry version of request_add_stake_mul_bal,
which returns a list of the time-locked staked IOTAs instead of transferring them to the sender.
public fun request_add_stake_mul_bal_non_entry(iota_system: &mut iota_system::iota_system::IotaSystemState, timelocked_balances: vector<iota::timelock::TimeLock<iota::balance::Balance<iota::iota::IOTA>>>, validator_address: address, ctx: &mut iota::tx_context::TxContext): vector<iota_system::timelocked_staking::TimelockedStakedIota>
Implementation
public fun request_add_stake_mul_bal_non_entry(
iota_system: &mut IotaSystemState,
mut timelocked_balances: vector<TimeLock<Balance<IOTA>>>,
validator_address: address,
ctx: &mut TxContext,
): vector<TimelockedStakedIota> {
// Create a vector to store the results.
let mut result = vector[];
// Create useful variables.
let (mut i, len) = (0, timelocked_balances.length());
// Stake all the time-locked balances.
while (i < len) {
// Take a time-locked balance.
let timelocked_balance = timelocked_balances.pop_back();
// Stake the time-locked balance.
let timelocked_staked_iota = request_add_stake_non_entry(
iota_system,
timelocked_balance,
validator_address,
ctx,
);
// Store the created receipt.
result.push_back(timelocked_staked_iota);
i = i + 1
};
// Destroy the empty vector.
vector::destroy_empty(timelocked_balances);
result
}
Function request_withdraw_stake_non_entry
Non-entry version of request_withdraw_stake that returns the withdrawn time-locked IOTA and reward
instead of transferring it to the sender.
public fun request_withdraw_stake_non_entry(iota_system: &mut iota_system::iota_system::IotaSystemState, timelocked_staked_iota: iota_system::timelocked_staking::TimelockedStakedIota, ctx: &mut iota::tx_context::TxContext): (iota::timelock::TimeLock<iota::balance::Balance<iota::iota::IOTA>>, iota::balance::Balance<iota::iota::IOTA>)
Implementation
public fun request_withdraw_stake_non_entry(
iota_system: &mut IotaSystemState,
timelocked_staked_iota: TimelockedStakedIota,
ctx: &mut TxContext,
): (TimeLock<Balance<IOTA>>, Balance<IOTA>) {
// Unpack the <Link to="../iota_system/timelocked_staking#iota_system_timelocked_staking_TimelockedStakedIota">TimelockedStakedIota</Link> instance.
let (staked_iota, expiration_timestamp_ms, label) = timelocked_staked_iota.unpack();
// Store the original stake amount.
let principal = staked_iota.staked_iota_amount();
// Withdraw the balance.
let mut withdraw_stake = iota_system.request_withdraw_stake_non_entry(staked_iota, ctx);
// The iota_system withdraw functions return a balance that consists of the original staked amount plus the reward amount;
// In here, it splits the original staked balance to timelock it again.
let principal = withdraw_stake.split(principal);
// Pack and return a time-locked balance, and the reward.
let sys_admin_cap = iota_system.load_iota_system_admin_cap();
(
timelock::system_pack(sys_admin_cap, principal, expiration_timestamp_ms, label, ctx),
withdraw_stake,
)
}
Function unlock
Unlock the StakedIota from a TimelockedStakedIota based on the epoch start time.
public fun unlock(self: iota_system::timelocked_staking::TimelockedStakedIota, ctx: &iota::tx_context::TxContext): iota_system::staking_pool::StakedIota
Implementation
public fun unlock(self: TimelockedStakedIota, ctx: &TxContext): StakedIota {
// Unpack the <Link to="../iota_system/timelocked_staking#iota_system_timelocked_staking_TimelockedStakedIota">TimelockedStakedIota</Link>.
let (staked, expiration_timestamp_ms, _) = unpack(self);
// Check if the lock has expired.
assert!(
expiration_timestamp_ms <= ctx.epoch_timestamp_ms(),
ETimelockedStakedIotaShouldBeExpired,
);
staked
}
Function unlock_with_clock
Unlock the StakedIota from a TimelockedStakedIota based on the Clock object.
public fun unlock_with_clock(self: iota_system::timelocked_staking::TimelockedStakedIota, clock: &iota::clock::Clock): iota_system::staking_pool::StakedIota
Implementation
public fun unlock_with_clock(self: TimelockedStakedIota, clock: &Clock): StakedIota {
// Unpack the <Link to="../iota_system/timelocked_staking#iota_system_timelocked_staking_TimelockedStakedIota">TimelockedStakedIota</Link>.
let (staked, expiration_timestamp_ms, _) = unpack(self);
// Check if the lock has expired.
assert!(expiration_timestamp_ms <= clock.timestamp_ms(), ETimelockedStakedIotaShouldBeExpired);
staked
}
Function split
Split TimelockedStakedIota into two parts, one with principal split_amount,
and the remaining principal is left in self.
All the other parameters of the TimelockedStakedIota like stake_activation_epoch or pool_id remain the same.
public fun split(self: &mut iota_system::timelocked_staking::TimelockedStakedIota, split_amount: u64, ctx: &mut iota::tx_context::TxContext): iota_system::timelocked_staking::TimelockedStakedIota
Implementation
public fun split(
self: &mut TimelockedStakedIota,
split_amount: u64,
ctx: &mut TxContext,
): TimelockedStakedIota {
let split_stake = self.staked_iota.split(split_amount, ctx);
TimelockedStakedIota {
id: object::new(ctx),
staked_iota: split_stake,
expiration_timestamp_ms: self.expiration_timestamp_ms,
label: self.label,
}
}
Function split_staked_iota
Split the given TimelockedStakedIota to the two parts, one with principal split_amount,
transfer the newly split part to the sender address.
public entry fun split_staked_iota(stake: &mut iota_system::timelocked_staking::TimelockedStakedIota, split_amount: u64, ctx: &mut iota::tx_context::TxContext)
Implementation
public entry fun split_staked_iota(
stake: &mut TimelockedStakedIota,
split_amount: u64,
ctx: &mut TxContext,
) {
split(stake, split_amount, ctx).transfer_to_sender(ctx);
}
Function join_staked_iota
Consume the staked iota other and add its value to self.
Aborts if some of the staking parameters are incompatible (pool id, stake activation epoch, etc.)
public entry fun join_staked_iota(self: &mut iota_system::timelocked_staking::TimelockedStakedIota, other: iota_system::timelocked_staking::TimelockedStakedIota)
Implementation
public entry fun join_staked_iota(self: &mut TimelockedStakedIota, other: TimelockedStakedIota) {
assert!(self.is_equal_staking_metadata(&other), EIncompatibleTimelockedStakedIota);
let TimelockedStakedIota {
id,
staked_iota,
expiration_timestamp_ms: _,
label: _,
} = other;
id.delete();
self.staked_iota.join(staked_iota);
}
Function transfer_to_sender
A utility function to transfer a TimelockedStakedIota.
public fun transfer_to_sender(stake: iota_system::timelocked_staking::TimelockedStakedIota, ctx: &iota::tx_context::TxContext)
Implementation
public fun transfer_to_sender(stake: TimelockedStakedIota, ctx: &TxContext) {
transfer(stake, ctx.sender())
}
Function transfer_to_sender_multiple
A utility function to transfer multiple TimelockedStakedIota.
public fun transfer_to_sender_multiple(stakes: vector<iota_system::timelocked_staking::TimelockedStakedIota>, ctx: &iota::tx_context::TxContext)
Implementation
public fun transfer_to_sender_multiple(stakes: vector<TimelockedStakedIota>, ctx: &TxContext) {
transfer_multiple(stakes, ctx.sender())
}
Function is_equal_staking_metadata
A utility function that returns true if all the staking parameters of the staked iota except the principal are identical
public fun is_equal_staking_metadata(self: &iota_system::timelocked_staking::TimelockedStakedIota, other: &iota_system::timelocked_staking::TimelockedStakedIota): bool
Implementation
public fun is_equal_staking_metadata(
self: &TimelockedStakedIota,
other: &TimelockedStakedIota,
): bool {
self.staked_iota.is_equal_staking_metadata(&other.staked_iota) &&
(self.expiration_timestamp_ms == other.expiration_timestamp_ms) &&
(self.label() == other.label())
}
Function pool_id
Function to get the pool id of a TimelockedStakedIota.
public fun pool_id(self: &iota_system::timelocked_staking::TimelockedStakedIota): iota::object::ID
Implementation
public fun pool_id(self: &TimelockedStakedIota): ID { self.staked_iota.pool_id() }
Function staked_iota_amount
Function to get the staked iota amount of a TimelockedStakedIota.
public fun staked_iota_amount(self: &iota_system::timelocked_staking::TimelockedStakedIota): u64
Implementation
public fun staked_iota_amount(self: &TimelockedStakedIota): u64 {
self.staked_iota.staked_iota_amount()
}
Function stake_activation_epoch
Function to get the stake activation epoch of a TimelockedStakedIota.
public fun stake_activation_epoch(self: &iota_system::timelocked_staking::TimelockedStakedIota): u64
Implementation
public fun stake_activation_epoch(self: &TimelockedStakedIota): u64 {
self.staked_iota.stake_activation_epoch()
}
Function expiration_timestamp_ms
Function to get the expiration timestamp of a TimelockedStakedIota.
public fun expiration_timestamp_ms(self: &iota_system::timelocked_staking::TimelockedStakedIota): u64
Implementation
public fun expiration_timestamp_ms(self: &TimelockedStakedIota): u64 {
self.expiration_timestamp_ms
}
Function label
Function to get the label of a TimelockedStakedIota.
public fun label(self: &iota_system::timelocked_staking::TimelockedStakedIota): std::option::Option<std::string::String>
Implementation
public fun label(self: &TimelockedStakedIota): Option<String> {
self.label
}
Function is_labeled_with
Check if a TimelockedStakedIota is labeled with the type L.
public fun is_labeled_with<L>(self: &iota_system::timelocked_staking::TimelockedStakedIota): bool
Implementation
public fun is_labeled_with<L>(self: &TimelockedStakedIota): bool {
if (self.label.is_some()) {
self.label.borrow() == timelock::type_name<L>()
} else {
false
}
}
Function unpack
A utility function to destroy a TimelockedStakedIota.
fun unpack(self: iota_system::timelocked_staking::TimelockedStakedIota): (iota_system::staking_pool::StakedIota, u64, std::option::Option<std::string::String>)
Implementation
fun unpack(self: TimelockedStakedIota): (StakedIota, u64, Option<String>) {
let TimelockedStakedIota {
id,
staked_iota,
expiration_timestamp_ms,
label,
} = self;
object::delete(id);
(staked_iota, expiration_timestamp_ms, label)
}
Function transfer
A utility function to transfer a TimelockedStakedIota to a receiver.
fun transfer(stake: iota_system::timelocked_staking::TimelockedStakedIota, receiver: address)
Implementation
fun transfer(stake: TimelockedStakedIota, receiver: address) {
transfer::transfer(stake, receiver);
}
Function transfer_multiple
A utility function to transfer a vector of TimelockedStakedIota to a receiver.
fun transfer_multiple(stakes: vector<iota_system::timelocked_staking::TimelockedStakedIota>, receiver: address)
Implementation
fun transfer_multiple(mut stakes: vector<TimelockedStakedIota>, receiver: address) {
// Transfer all the time-locked stakes to the recipient.
while (!stakes.is_empty()) {
let stake = stakes.pop_back();
transfer::transfer(stake, receiver);
};
// Destroy the empty vector.
vector::destroy_empty(stakes);
}
Function request_add_stake_at_genesis
Request to add timelocked stake to the validator's staking pool at genesis
public(package) fun request_add_stake_at_genesis(validator: &mut iota_system::validator::ValidatorV1, stake: iota::balance::Balance<iota::iota::IOTA>, staker_address: address, expiration_timestamp_ms: u64, label: std::option::Option<std::string::String>, ctx: &mut iota::tx_context::TxContext)
Implementation
public(package) fun request_add_stake_at_genesis(
validator: &mut ValidatorV1,
stake: Balance<IOTA>,
staker_address: address,
expiration_timestamp_ms: u64,
label: Option<String>,
ctx: &mut TxContext,
) {
let staked_iota = validator.request_add_stake_at_genesis_with_receipt(stake, ctx);
let timelocked_staked_iota = TimelockedStakedIota {
id: object::new(ctx),
staked_iota,
expiration_timestamp_ms,
label,
};
transfer(timelocked_staked_iota, staker_address);
}