Module 0x3::timelocked_staking
- Resource
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
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 0x1::option;
use 0x1::string;
use 0x1::vector;
use 0x2::balance;
use 0x2::coin;
use 0x2::iota;
use 0x2::object;
use 0x2::system_admin_cap;
use 0x2::timelock;
use 0x2::transfer;
use 0x2::tx_context;
use 0x3::iota_system;
use 0x3::staking_pool;
use 0x3::validator;
Resource TimelockedStakedIota
A self-custodial object holding the timelocked staked IOTA tokens.
struct TimelockedStakedIota has key
Fields
id: object::UID
staked_iota: staking_pool::StakedIota
A self-custodial object holding the staked IOTA tokens.
expiration_timestamp_ms: u64
This is the epoch time stamp of when the lock expires.
label: option::Option<string::String>
Timelock related label.
Constants
Incompatible objects when joining TimelockedStakedIota
const EIncompatibleTimelockedStakedIota: u64 = 1;
For when trying to stake an expired time-locked balance.
const ETimeLockShouldNotBeExpired: u64 = 0;
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::IotaSystemState, timelocked_balance: timelock::TimeLock<balance::Balance<iota::IOTA>>, validator_address: address, ctx: &mut 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::IotaSystemState, timelocked_balances: vector<timelock::TimeLock<balance::Balance<iota::IOTA>>>, validator_address: address, ctx: &mut 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::IotaSystemState, timelocked_staked_iota: timelocked_staking::TimelockedStakedIota, ctx: &mut 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::IotaSystemState, timelocked_balance: timelock::TimeLock<balance::Balance<iota::IOTA>>, validator_address: address, ctx: &mut tx_context::TxContext): 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::IotaSystemState, timelocked_balances: vector<timelock::TimeLock<balance::Balance<iota::IOTA>>>, validator_address: address, ctx: &mut tx_context::TxContext): vector<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::IotaSystemState, timelocked_staked_iota: timelocked_staking::TimelockedStakedIota, ctx: &mut tx_context::TxContext): (timelock::TimeLock<balance::Balance<iota::IOTA>>, balance::Balance<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="timelocked_staking#0x3_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 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 timelocked_staking::TimelockedStakedIota, split_amount: u64, ctx: &mut tx_context::TxContext): 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 timelocked_staking::TimelockedStakedIota, split_amount: u64, ctx: &mut 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 timelocked_staking::TimelockedStakedIota, other: 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: timelocked_staking::TimelockedStakedIota, ctx: &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<timelocked_staking::TimelockedStakedIota>, ctx: &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: &timelocked_staking::TimelockedStakedIota, other: &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: &timelocked_staking::TimelockedStakedIota): 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: &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: &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: &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: &timelocked_staking::TimelockedStakedIota): option::Option<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: &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: timelocked_staking::TimelockedStakedIota): (staking_pool::StakedIota, u64, option::Option<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: 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<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(friend) fun request_add_stake_at_genesis(validator: &mut validator::ValidatorV1, stake: balance::Balance<iota::IOTA>, staker_address: address, expiration_timestamp_ms: u64, label: option::Option<string::String>, ctx: &mut 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);
}