From 3c9403d232fbacc3a88d2cc4049c5720719165df Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Tue, 2 Jul 2024 17:43:15 +0300 Subject: [PATCH 01/50] feat: store IOTA's TreasutyCap in SystemObject --- .../docs/iota-framework/iota.md | 43 ++++++++++++++++--- .../docs/iota-system/genesis.md | 4 +- .../docs/iota-system/iota_system.md | 4 +- .../iota-system/iota_system_state_inner.md | 18 +++++++- .../packages/iota-framework/sources/iota.move | 24 ++++++++--- .../packages/iota-system/Move.lock | 12 +++--- .../packages/iota-system/sources/genesis.move | 3 ++ .../iota-system/sources/iota_system.move | 4 +- .../sources/iota_system_state_inner.move | 10 ++++- .../tests/governance_test_utils.move | 12 ++++-- crates/iota-genesis-builder/src/lib.rs | 36 ++++++++++------ 11 files changed, 129 insertions(+), 41 deletions(-) diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md index 7c76bcebee9..cdfe7c56477 100644 --- a/crates/iota-framework/docs/iota-framework/iota.md +++ b/crates/iota-framework/docs/iota-framework/iota.md @@ -10,6 +10,7 @@ It has 9 decimals, and the smallest unit (10^-9) is called "micros". - [Constants](#@Constants_0) - [Function `new`](#0x2_iota_new) - [Function `transfer`](#0x2_iota_transfer) +- [Function `mint_genesis_supply`](#0x2_iota_mint_genesis_supply)
use 0x1::option;
@@ -109,11 +110,11 @@ The total supply of Iota denominated in Micros (10 Billion * 10^9)
 
 ## Function `new`
 
-Register the IOTA Coin to acquire its Supply.
+Register the IOTA Coin to acquire its TreasuryCap.
 This should be called only once during genesis creation.
 
 
-
fun new(ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
fun new(ctx: &mut tx_context::TxContext): coin::TreasuryCap<iota::IOTA>
 
@@ -122,7 +123,7 @@ This should be called only once during genesis creation. Implementation -
fun new(ctx: &mut TxContext): Balance<IOTA> {
+
fun new(ctx: &mut TxContext): TreasuryCap<IOTA> {
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
     assert!(ctx.epoch() == 0, EAlreadyMinted);
 
@@ -136,11 +137,10 @@ This should be called only once during genesis creation.
         option::none(),
         ctx
     );
+
     transfer::public_freeze_object(metadata);
-    let mut supply = treasury.treasury_into_supply();
-    let total_iota = supply.increase_supply(TOTAL_SUPPLY_MICROS);
-    supply.destroy_supply();
-    total_iota
+
+    treasury
 }
 
@@ -170,4 +170,33 @@ This should be called only once during genesis creation. + + + + +## Function `mint_genesis_supply` + +Increase the IOTA supply. +This should be called only once during genesis creation. + + +
fun mint_genesis_supply(cap: &mut coin::TreasuryCap<iota::IOTA>, amount: u64, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
fun mint_genesis_supply(cap: &mut TreasuryCap<IOTA>, amount: u64, ctx: &TxContext): Balance<IOTA> {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+    assert!(ctx.epoch() == 0, EAlreadyMinted);
+
+    cap.mint_balance(amount)
+}
+
+ + +
diff --git a/crates/iota-framework/docs/iota-system/genesis.md b/crates/iota-framework/docs/iota-system/genesis.md index 6596d57ac48..15afdec723b 100644 --- a/crates/iota-framework/docs/iota-system/genesis.md +++ b/crates/iota-framework/docs/iota-system/genesis.md @@ -340,7 +340,7 @@ It will create a singleton IotaSystemState object, which contains all the information we need in the system. -
fun create(iota_system_state_id: object::UID, iota_supply: balance::Balance<iota::IOTA>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
+
fun create(iota_system_state_id: object::UID, iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, iota_supply: balance::Balance<iota::IOTA>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
 
@@ -351,6 +351,7 @@ all the information we need in the system.
fun create(
     iota_system_state_id: UID,
+    iota_treasury_cap: TreasuryCap<IOTA>,
     mut iota_supply: Balance<IOTA>,
     genesis_chain_parameters: GenesisChainParameters,
     genesis_validators: vector<GenesisValidatorMetadata>,
@@ -456,6 +457,7 @@ all the information we need in the system.
 
     iota_system::create(
         iota_system_state_id,
+        iota_treasury_cap,
         validators,
         storage_fund,
         genesis_chain_parameters.protocol_version,
diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md
index cf6ab5c3c8a..0d030e5f8a8 100644
--- a/crates/iota-framework/docs/iota-system/iota_system.md
+++ b/crates/iota-framework/docs/iota-system/iota_system.md
@@ -167,7 +167,7 @@ Create a new IotaSystemState object and make it shared.
 This function will be called only once in genesis.
 
 
-
public(friend) fun create(id: object::UID, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
+
public(friend) fun create(id: object::UID, iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
 
@@ -178,6 +178,7 @@ This function will be called only once in genesis.
public(package) fun create(
     id: UID,
+    iota_treasury_cap: TreasuryCap<IOTA>,
     validators: vector<Validator>,
     storage_fund: Balance<IOTA>,
     protocol_version: u64,
@@ -187,6 +188,7 @@ This function will be called only once in genesis.
     ctx: &mut TxContext,
 ) {
     let system_state = iota_system_state_inner::create(
+        iota_treasury_cap,
         validators,
         storage_fund,
         protocol_version,
diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index 457f001f402..d9229cd6374 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -281,6 +281,12 @@ The top-level object containing all information of the Iota system.
  we know what version it is by inspecting IotaSystemStateInner as well.
 
 
+iota_treasury_cap: coin::TreasuryCap<iota::IOTA> +
+
+ The IOTA's TreasuryCap. +
+
validators: validator_set::ValidatorSet
@@ -413,6 +419,12 @@ Uses SystemParametersV2 as the parameters. we know what version it is by inspecting IotaSystemStateInner as well.
+iota_treasury_cap: coin::TreasuryCap<iota::IOTA> +
+
+ The IOTA's TreasuryCap. +
+
validators: validator_set::ValidatorSet
@@ -741,7 +753,7 @@ Create a new IotaSystemState object and make it shared. This function will be called only once in genesis. -
public(friend) fun create(validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
+
public(friend) fun create(iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
 
@@ -751,6 +763,7 @@ This function will be called only once in genesis.
public(package) fun create(
+    iota_treasury_cap: TreasuryCap<IOTA>,
     validators: vector<Validator>,
     initial_storage_fund: Balance<IOTA>,
     protocol_version: u64,
@@ -766,6 +779,7 @@ This function will be called only once in genesis.
         epoch: 0,
         protocol_version,
         system_state_version: genesis_system_state_version(),
+        iota_treasury_cap,
         validators,
         storage_fund: storage_fund::new(initial_storage_fund),
         parameters,
@@ -852,6 +866,7 @@ This function will be called only once in genesis.
         epoch,
         protocol_version,
         system_state_version: _,
+        iota_treasury_cap,
         validators,
         storage_fund,
         parameters,
@@ -880,6 +895,7 @@ This function will be called only once in genesis.
         epoch,
         protocol_version,
         system_state_version: 2,
+        iota_treasury_cap,
         validators,
         storage_fund,
         parameters: SystemParametersV2 {
diff --git a/crates/iota-framework/packages/iota-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move
index e2ceb1fe3fc..cf836d2e969 100644
--- a/crates/iota-framework/packages/iota-framework/sources/iota.move
+++ b/crates/iota-framework/packages/iota-framework/sources/iota.move
@@ -6,7 +6,7 @@
 /// It has 9 decimals, and the smallest unit (10^-9) is called "micros".
 module iota::iota {
     use iota::balance::Balance;
-    use iota::coin;
+    use iota::coin::{Self, TreasuryCap};
 
     const EAlreadyMinted: u64 = 0;
     /// Sender is not @0x0 the system address.
@@ -21,6 +21,7 @@ module iota::iota {
     /// The total supply of Iota denominated in whole Iota tokens (10 Billion)
     const TOTAL_SUPPLY_IOTA: u64 = 10_000_000_000;
 
+    #[allow(unused_const)]
     /// The total supply of Iota denominated in Micros (10 Billion * 10^9)
     const TOTAL_SUPPLY_MICROS: u64 = 10_000_000_000_000_000_000;
 
@@ -28,9 +29,9 @@ module iota::iota {
     public struct IOTA has drop {}
 
     #[allow(unused_function)]
-    /// Register the `IOTA` Coin to acquire its `Supply`.
+    /// Register the `IOTA` Coin to acquire its `TreasuryCap`.
     /// This should be called only once during genesis creation.
-    fun new(ctx: &mut TxContext): Balance {
+    fun new(ctx: &mut TxContext): TreasuryCap {
         assert!(ctx.sender() == @0x0, ENotSystemAddress);
         assert!(ctx.epoch() == 0, EAlreadyMinted);
 
@@ -44,14 +45,23 @@ module iota::iota {
             option::none(),
             ctx
         );
+
         transfer::public_freeze_object(metadata);
-        let mut supply = treasury.treasury_into_supply();
-        let total_iota = supply.increase_supply(TOTAL_SUPPLY_MICROS);
-        supply.destroy_supply();
-        total_iota
+
+        treasury
     }
 
     public entry fun transfer(c: coin::Coin, recipient: address) {
         transfer::public_transfer(c, recipient)
     }
+
+    #[allow(unused_function)]
+    /// Increase the IOTA supply.
+    /// This should be called only once during genesis creation.
+    fun mint_genesis_supply(cap: &mut TreasuryCap, amount: u64, ctx: &TxContext): Balance {
+        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+        assert!(ctx.epoch() == 0, EAlreadyMinted);
+
+        cap.mint_balance(amount)
+    }
 }
diff --git a/crates/iota-framework/packages/iota-system/Move.lock b/crates/iota-framework/packages/iota-system/Move.lock
index 9128d14190f..f01fb34d06f 100644
--- a/crates/iota-framework/packages/iota-system/Move.lock
+++ b/crates/iota-framework/packages/iota-system/Move.lock
@@ -2,18 +2,14 @@
 
 [move]
 version = 1
-manifest_digest = "68AEB9354EE1D616F6D2293EC721FE3D7E810FEC4FE34197676ECFA3DA72CAE3"
+manifest_digest = "4B3F098CD3A1E550ED834159EF4E2978435F6159F321C7143AD27440B6A74BDC"
 deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600"
 
 dependencies = [
-  { name = "MoveStdlib" },
   { name = "Iota" },
+  { name = "MoveStdlib" },
 ]
 
-[[move.package]]
-name = "MoveStdlib"
-source = { local = "../move-stdlib" }
-
 [[move.package]]
 name = "Iota"
 source = { local = "../iota-framework" }
@@ -22,6 +18,10 @@ dependencies = [
   { name = "MoveStdlib" },
 ]
 
+[[move.package]]
+name = "MoveStdlib"
+source = { local = "../move-stdlib" }
+
 [move.toolchain-version]
 compiler-version = "1.22.0"
 edition = "legacy"
diff --git a/crates/iota-framework/packages/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move
index 68133f283a7..b669b58398c 100644
--- a/crates/iota-framework/packages/iota-system/sources/genesis.move
+++ b/crates/iota-framework/packages/iota-system/sources/genesis.move
@@ -5,6 +5,7 @@
 module iota_system::genesis {
 
     use iota::balance::{Self, Balance};
+    use iota::coin::TreasuryCap;
     use iota::iota::{Self, IOTA};
     use iota_system::iota_system;
     use iota_system::validator::{Self, Validator};
@@ -79,6 +80,7 @@ module iota_system::genesis {
     /// all the information we need in the system.
     fun create(
         iota_system_state_id: UID,
+        iota_treasury_cap: TreasuryCap,
         mut iota_supply: Balance,
         genesis_chain_parameters: GenesisChainParameters,
         genesis_validators: vector,
@@ -184,6 +186,7 @@ module iota_system::genesis {
 
         iota_system::create(
             iota_system_state_id,
+            iota_treasury_cap,
             validators,
             storage_fund,
             genesis_chain_parameters.protocol_version,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move
index 9906271b539..4f01e7cf08f 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move
@@ -42,7 +42,7 @@
 module iota_system::iota_system {
     use iota::balance::Balance;
 
-    use iota::coin::Coin;
+    use iota::coin::{Coin, TreasuryCap};
     use iota_system::staking_pool::StakedIota;
     use iota::iota::IOTA;
     use iota::table::Table;
@@ -78,6 +78,7 @@ module iota_system::iota_system {
     /// This function will be called only once in genesis.
     public(package) fun create(
         id: UID,
+        iota_treasury_cap: TreasuryCap,
         validators: vector,
         storage_fund: Balance,
         protocol_version: u64,
@@ -87,6 +88,7 @@ module iota_system::iota_system {
         ctx: &mut TxContext,
     ) {
         let system_state = iota_system_state_inner::create(
+            iota_treasury_cap,
             validators,
             storage_fund,
             protocol_version,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index f4270501b06..ceaf0a25532 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -4,7 +4,7 @@
 
 module iota_system::iota_system_state_inner {
     use iota::balance::{Self, Balance};
-    use iota::coin::Coin;
+    use iota::coin::{Coin, TreasuryCap};
     use iota_system::staking_pool::{stake_activation_epoch, StakedIota};
     use iota::iota::IOTA;
     use iota_system::validator::{Self, Validator};
@@ -110,6 +110,8 @@ module iota_system::iota_system_state_inner {
         /// This is always the same as IotaSystemState.version. Keeping a copy here so that
         /// we know what version it is by inspecting IotaSystemStateInner as well.
         system_state_version: u64,
+        /// The IOTA's TreasuryCap.
+        iota_treasury_cap: TreasuryCap,
         /// Contains all information about the validators.
         validators: ValidatorSet,
         /// The storage fund.
@@ -158,6 +160,8 @@ module iota_system::iota_system_state_inner {
         /// This is always the same as IotaSystemState.version. Keeping a copy here so that
         /// we know what version it is by inspecting IotaSystemStateInner as well.
         system_state_version: u64,
+        /// The IOTA's TreasuryCap.
+        iota_treasury_cap: TreasuryCap,
         /// Contains all information about the validators.
         validators: ValidatorSet,
         /// The storage fund.
@@ -232,6 +236,7 @@ module iota_system::iota_system_state_inner {
     /// Create a new IotaSystemState object and make it shared.
     /// This function will be called only once in genesis.
     public(package) fun create(
+        iota_treasury_cap: TreasuryCap,
         validators: vector,
         initial_storage_fund: Balance,
         protocol_version: u64,
@@ -247,6 +252,7 @@ module iota_system::iota_system_state_inner {
             epoch: 0,
             protocol_version,
             system_state_version: genesis_system_state_version(),
+            iota_treasury_cap,
             validators,
             storage_fund: storage_fund::new(initial_storage_fund),
             parameters,
@@ -293,6 +299,7 @@ module iota_system::iota_system_state_inner {
             epoch,
             protocol_version,
             system_state_version: _,
+            iota_treasury_cap,
             validators,
             storage_fund,
             parameters,
@@ -321,6 +328,7 @@ module iota_system::iota_system_state_inner {
             epoch,
             protocol_version,
             system_state_version: 2,
+            iota_treasury_cap,
             validators,
             storage_fund,
             parameters: SystemParametersV2 {
diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
index 327418973ac..2a3f4fee26c 100644
--- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
+++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
@@ -73,16 +73,20 @@ module iota_system::governance_test_utils {
             ctx,
         );
 
+        let mut iota_treasury_cap = coin::create_treasury_cap_for_testing(ctx);
+        let supply = iota_treasury_cap.supply_mut().increase_supply(iota_supply_amount * MICROS_PER_IOTA);
+
         let stake_subsidy = stake_subsidy::create(
-            balance::create_for_testing(iota_supply_amount * MICROS_PER_IOTA), // iota_supply
-            0,   // stake subsidy initial distribution amount
-            10,  // stake_subsidy_period_length
-            0,   // stake_subsidy_decrease_rate
+            supply, // iota_supply
+            0,      // stake subsidy initial distribution amount
+            10,     // stake_subsidy_period_length
+            0,      // stake_subsidy_decrease_rate
             ctx,
         );
 
         iota_system::create(
             object::new(ctx), // it doesn't matter what ID iota system state has in tests
+            iota_treasury_cap,
             validators,
             balance::create_for_testing(storage_fund_amount * MICROS_PER_IOTA), // storage_fund
             1,   // protocol version
diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs
index 6fc9f97307c..527dc74d03b 100644
--- a/crates/iota-genesis-builder/src/lib.rs
+++ b/crates/iota-genesis-builder/src/lib.rs
@@ -35,7 +35,7 @@ use iota_types::{
     effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents},
     epoch_data::EpochData,
     gas::IotaGasStatus,
-    gas_coin::{GasCoin, GAS},
+    gas_coin::{GasCoin, GAS, TOTAL_SUPPLY_MICROS},
     governance::StakedIota,
     in_memory_storage::InMemoryStorage,
     inner_temporary_store::InnerTemporaryStore,
@@ -49,7 +49,7 @@ use iota_types::{
         CallArg, CheckedInputObjects, Command, InputObjectKind, ObjectArg, ObjectReadResult,
         Transaction,
     },
-    IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS, IOTA_SYSTEM_STATE_OBJECT_ID,
+    IOTA_FRAMEWORK_PACKAGE_ID, IOTA_SYSTEM_ADDRESS, IOTA_SYSTEM_STATE_OBJECT_ID,
     IOTA_SYSTEM_STATE_OBJECT_SHARED_VERSION, TIMELOCK_ADDRESS,
 };
 use move_binary_format::CompiledModule;
@@ -1163,7 +1163,7 @@ pub fn generate_genesis_system_object(
         let mut builder = ProgrammableTransactionBuilder::new();
         // Step 1: Create the IotaSystemState UID
         let iota_system_state_uid = builder.programmable_move_call(
-            IOTA_FRAMEWORK_ADDRESS.into(),
+            IOTA_FRAMEWORK_PACKAGE_ID,
             ident_str!("object").to_owned(),
             ident_str!("iota_system_state").to_owned(),
             vec![],
@@ -1172,7 +1172,7 @@ pub fn generate_genesis_system_object(
 
         // Step 2: Create and share the Clock.
         builder.move_call(
-            IOTA_FRAMEWORK_ADDRESS.into(),
+            IOTA_FRAMEWORK_PACKAGE_ID,
             ident_str!("clock").to_owned(),
             ident_str!("create").to_owned(),
             vec![],
@@ -1183,7 +1183,7 @@ pub fn generate_genesis_system_object(
         // (which only happens in tests).
         if protocol_config.create_authenticator_state_in_genesis() {
             builder.move_call(
-                IOTA_FRAMEWORK_ADDRESS.into(),
+                IOTA_FRAMEWORK_PACKAGE_ID,
                 ident_str!("authenticator_state").to_owned(),
                 ident_str!("create").to_owned(),
                 vec![],
@@ -1192,7 +1192,7 @@ pub fn generate_genesis_system_object(
         }
         if protocol_config.random_beacon() {
             builder.move_call(
-                IOTA_FRAMEWORK_ADDRESS.into(),
+                IOTA_FRAMEWORK_PACKAGE_ID,
                 ident_str!("random").to_owned(),
                 ident_str!("create").to_owned(),
                 vec![],
@@ -1201,7 +1201,7 @@ pub fn generate_genesis_system_object(
         }
         if protocol_config.enable_coin_deny_list() {
             builder.move_call(
-                IOTA_FRAMEWORK_ADDRESS.into(),
+                IOTA_FRAMEWORK_PACKAGE_ID,
                 DENY_LIST_MODULE.to_owned(),
                 DENY_LIST_CREATE_FUNC.to_owned(),
                 vec![],
@@ -1209,19 +1209,31 @@ pub fn generate_genesis_system_object(
             )?;
         }
 
-        // Step 4: Mint the supply of IOTA.
-        let iota_supply = builder.programmable_move_call(
-            IOTA_FRAMEWORK_ADDRESS.into(),
+        // Step 4: Create the IOTA Coin.
+        let iota_treasury_cap = builder.programmable_move_call(
+            IOTA_FRAMEWORK_PACKAGE_ID,
             ident_str!("iota").to_owned(),
             ident_str!("new").to_owned(),
             vec![],
             vec![],
         );
+        // TODO: This is will need to be modified after the timelock staking changes and
+        // to account for the migration objects with pre-allocated funds.
+        let total_iota_supply = builder
+            .pure(&(TOTAL_SUPPLY_MICROS))
+            .expect("serialization of u64 should succeed");
+        let total_iota = builder.programmable_move_call(
+            IOTA_FRAMEWORK_PACKAGE_ID,
+            ident_str!("iota").to_owned(),
+            ident_str!("mint_genesis_supply").to_owned(),
+            vec![],
+            vec![iota_treasury_cap, total_iota_supply],
+        );
 
         // Step 5: Run genesis.
         // The first argument is the system state uid we got from step 1 and the second
-        // one is the IOTA supply we got from step 3.
-        let mut arguments = vec![iota_system_state_uid, iota_supply];
+        // one is the IOTA `TreasuryCap` we got from step 4.
+        let mut arguments = vec![iota_system_state_uid, iota_treasury_cap, total_iota];
         let mut call_arg_arguments = vec![
             CallArg::Pure(bcs::to_bytes(&genesis_chain_parameters).unwrap()),
             CallArg::Pure(bcs::to_bytes(&genesis_validators).unwrap()),

From 9c0bbd3014726eb34a05d3817f9d021fa17c8932 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Wed, 3 Jul 2024 09:23:24 +0200
Subject: [PATCH 02/50] feat: Add minting and burning of IOTA tokens

---
 .../iota-system/sources/iota_system.move      |  2 ++
 .../sources/iota_system_state_inner.move      | 29 +++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move
index 4f01e7cf08f..ce27a0cc996 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move
@@ -538,6 +538,7 @@ module iota_system::iota_system {
     /// 3. Distribute computation charge to validator stake.
     /// 4. Update all validators.
     fun advance_epoch(
+        validator_target_reward: u64,
         storage_reward: Balance,
         computation_reward: Balance,
         wrapper: &mut IotaSystemState,
@@ -557,6 +558,7 @@ module iota_system::iota_system {
         let storage_rebate = self.advance_epoch(
             new_epoch,
             next_protocol_version,
+            validator_target_reward,
             storage_reward,
             computation_reward,
             storage_rebate,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index ceaf0a25532..5e0700f86b5 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -827,6 +827,7 @@ module iota_system::iota_system_state_inner {
         self: &mut IotaSystemStateInnerV2,
         new_epoch: u64,
         next_protocol_version: u64,
+        validator_target_reward: u64,
         mut storage_reward: Balance,
         mut computation_reward: Balance,
         mut storage_rebate_amount: u64,
@@ -896,6 +897,12 @@ module iota_system::iota_system_state_inner {
             storage_fund_reinvestment_amount as u64,
         );
 
+        let mut computation_reward = match_iota_supply_to_target_reward(
+          validator_target_reward,
+          computation_reward,
+          &mut self.iota_treasury_cap,
+        );
+
         self.epoch = self.epoch + 1;
         // Sanity check to make sure we are advancing to the right epoch.
         assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch);
@@ -968,6 +975,28 @@ module iota_system::iota_system_state_inner {
         refunded_storage_rebate
     }
 
+    /// Mint or burn IOTA tokens depending on the given target reward per validator
+    /// and the amount of computation fees burned in this epoch.
+    public(package) fun match_iota_supply_to_target_reward(
+      validator_target_reward: u64,
+      mut computation_reward: Balance,
+      iota_treasury_cap: &mut iota::coin::TreasuryCap
+    ): Balance {
+      if (computation_reward.value() < validator_target_reward) {
+        let tokens_to_mint = validator_target_reward - computation_reward.value();
+        let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint);
+        computation_reward.join(new_tokens);
+        computation_reward
+      } else if (computation_reward.value() > validator_target_reward) {
+        let tokens_to_burn = computation_reward.value() - validator_target_reward;
+        let rewards_to_burn = computation_reward.split(tokens_to_burn);
+        iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn);
+        computation_reward
+      } else {
+        computation_reward
+      }
+    }
+
     /// Return the current epoch number. Useful for applications that need a coarse-grained concept of time,
     /// since epochs are ever-increasing and epoch changes are intended to happen every 24 hours.
     public(package) fun epoch(self: &IotaSystemStateInnerV2): u64 {

From 94c95acdda5cb706f9b0a9b2dc2b9a00cdc35159 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Wed, 3 Jul 2024 11:00:10 +0200
Subject: [PATCH 03/50] feat: Fix tests and add target reward mint/burn tests

---
 .../iota-system/sources/iota_system.move      |  9 +++
 .../sources/iota_system_state_inner.move      |  6 ++
 .../tests/governance_test_utils.move          | 25 ++++++--
 .../iota-system/tests/iota_system_tests.move  |  2 +-
 .../tests/rewards_distribution_tests.move     | 57 ++++++++++++++++++-
 5 files changed, 93 insertions(+), 6 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move
index ce27a0cc996..7a3664c740c 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move
@@ -700,6 +700,13 @@ module iota_system::iota_system {
         self.get_stake_subsidy_distribution_counter()
     }
 
+    #[test_only]
+    /// Returns the total iota supply.
+    public fun get_iota_supply(wrapper: &mut IotaSystemState): u64 {
+      let self = load_system_state(wrapper);
+      self.get_total_iota_supply()
+    }
+
     // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED.  Creates a
     // candidate validator - bypassing the proof of possession check and other metadata validation
     // in the process.
@@ -748,6 +755,7 @@ module iota_system::iota_system {
         wrapper: &mut IotaSystemState,
         new_epoch: u64,
         next_protocol_version: u64,
+        validator_target_reward: u64,
         storage_charge: u64,
         computation_charge: u64,
         storage_rebate: u64,
@@ -760,6 +768,7 @@ module iota_system::iota_system {
         let storage_reward = balance::create_for_testing(storage_charge);
         let computation_reward = balance::create_for_testing(computation_charge);
         let storage_rebate = advance_epoch(
+            validator_target_reward,
             storage_reward,
             computation_reward,
             wrapper,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index 5e0700f86b5..00befe40684 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -1041,6 +1041,12 @@ module iota_system::iota_system_state_inner {
         self.validators.staking_pool_mappings()
     }
 
+    #[test_only]
+    /// Returns the total iota supply.
+    public(package) fun get_total_iota_supply(self: &IotaSystemStateInnerV2): u64 {
+        self.iota_treasury_cap.total_supply()
+    }
+
     /// Returns all the validators who are currently reporting `addr`
     public(package) fun get_reporters_of(self: &IotaSystemStateInnerV2, addr: address): VecSet
{ diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move index 2a3f4fee26c..314490901ce 100644 --- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move +++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move @@ -117,7 +117,7 @@ module iota_system::governance_test_utils { } public fun advance_epoch_with_reward_amounts_return_rebate( - storage_charge: u64, computation_charge: u64, stoarge_rebate: u64, non_refundable_storage_rebate: u64, scenario: &mut Scenario, + validator_target_reward: u64, storage_charge: u64, computation_charge: u64, stoarge_rebate: u64, non_refundable_storage_rebate: u64, scenario: &mut Scenario, ): Balance { scenario.next_tx(@0x0); let new_epoch = scenario.ctx().epoch() + 1; @@ -126,17 +126,25 @@ module iota_system::governance_test_utils { let ctx = scenario.ctx(); let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, + new_epoch, 1, validator_target_reward, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, ); test_scenario::return_shared(system_state); scenario.next_epoch(@0x0); storage_rebate } + /// Advances the epoch with the given reward amounts and setting validator_target_reward equal to the computation charge. public fun advance_epoch_with_reward_amounts( storage_charge: u64, computation_charge: u64, scenario: &mut Scenario ) { - let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, scenario); + advance_epoch_with_target_reward_amounts(computation_charge, storage_charge, computation_charge, scenario) + } + + /// Advances the epoch with the given validator target reward and storage and computation charge amounts. + public fun advance_epoch_with_target_reward_amounts( + validator_target_reward: u64, storage_charge: u64, computation_charge: u64, scenario: &mut Scenario + ) { + let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(validator_target_reward * MICROS_PER_IOTA, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, scenario); test_utils::destroy(storage_rebate) } @@ -152,8 +160,9 @@ module iota_system::governance_test_utils { let ctx = scenario.ctx(); + let validator_target_reward = computation_charge; let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, 0, reward_slashing_rate, 0, ctx + new_epoch, 1, validator_target_reward * MICROS_PER_IOTA, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, 0, reward_slashing_rate, 0, ctx ); test_utils::destroy(storage_rebate); test_scenario::return_shared(system_state); @@ -344,4 +353,12 @@ module iota_system::governance_test_utils { }; sum } + + /// Returns the total IOTA supply in the system state. + public fun total_supply(scenario: &mut Scenario): u64 { + let mut system_state = scenario.take_shared(); + let total_supply = system_state.get_iota_supply(); + test_scenario::return_shared(system_state); + total_supply + } } diff --git a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move index 0761eab8301..3378c7e160b 100644 --- a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move @@ -996,7 +996,7 @@ module iota_system::iota_system_tests { let prev_counter = system_state.get_stake_subsidy_distribution_counter(); let rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, 0, 0, 0, 0, 0, 0, prev_epoch_time + epoch_length, scenario.ctx() + new_epoch, 1, 0, 0, 0, 0, 0, 0, 0, prev_epoch_time + epoch_length, scenario.ctx() ); destroy(rebate); assert_eq(system_state.get_stake_subsidy_distribution_counter(), prev_counter + (if (should_increment_counter) 1 else 0)); diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move index 11c6fa0d8c1..40555c8d38c 100644 --- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -11,13 +11,15 @@ module iota_system::rewards_distribution_tests { advance_epoch, advance_epoch_with_reward_amounts, advance_epoch_with_reward_amounts_and_slashing_rates, + advance_epoch_with_target_reward_amounts, assert_validator_total_stake_amounts, assert_validator_non_self_stake_amounts, assert_validator_self_stake_amounts, create_validator_for_testing, create_iota_system_state_for_testing, stake_with, - total_iota_balance, unstake + total_iota_balance, total_supply, + unstake }; use iota::test_utils::assert_eq; use iota::address; @@ -78,6 +80,59 @@ module iota_system::rewards_distribution_tests { scenario_val.end(); } + #[test] + fun test_validator_target_reward_no_supply_change() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + let prev_supply = total_supply(scenario); + + // need to advance epoch so validator's staking starts counting + advance_epoch(scenario); + advance_epoch_with_target_reward_amounts(100, 0, 100, scenario); + + let new_supply = total_supply(scenario); + assert!(prev_supply == new_supply, 0); + + scenario_val.end(); + } + + #[test] + fun test_validator_target_reward_deflation() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + let prev_supply = total_supply(scenario); + + // need to advance epoch so validator's staking starts counting + advance_epoch(scenario); + advance_epoch_with_target_reward_amounts(60, 0, 100, scenario); + + let new_supply = total_supply(scenario); + // 40 tokens should have been burned. + assert!(prev_supply - 40 * MICROS_PER_IOTA == new_supply, 0); + + scenario_val.end(); + } + + #[test] + fun test_validator_target_reward_inflation() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + let prev_supply = total_supply(scenario); + + // need to advance epoch so validator's staking starts counting + advance_epoch(scenario); + advance_epoch_with_target_reward_amounts(100, 0, 60, scenario); + + let new_supply = total_supply(scenario); + // 40 tokens should have been minted. + assert!(prev_supply + 40 * MICROS_PER_IOTA == new_supply, 0); + + scenario_val.end(); + } + #[test] fun test_stake_rewards() { set_up_iota_system_state(); From fda585428e17466eac956663d7938a9acc19e38e Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 3 Jul 2024 11:06:50 +0200 Subject: [PATCH 04/50] fix: Update docs --- .../docs/iota-system/iota_system.md | 4 +- .../iota-system/iota_system_state_inner.md | 52 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md index 0d030e5f8a8..e4d8ae69993 100644 --- a/crates/iota-framework/docs/iota-system/iota_system.md +++ b/crates/iota-framework/docs/iota-system/iota_system.md @@ -1362,7 +1362,7 @@ gas coins. 4. Update all validators. -
fun advance_epoch(storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
fun advance_epoch(validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -1372,6 +1372,7 @@ gas coins.
fun advance_epoch(
+    validator_target_reward: u64,
     storage_reward: Balance<IOTA>,
     computation_reward: Balance<IOTA>,
     wrapper: &mut IotaSystemState,
@@ -1391,6 +1392,7 @@ gas coins.
     let storage_rebate = self.advance_epoch(
         new_epoch,
         next_protocol_version,
+        validator_target_reward,
         storage_reward,
         computation_reward,
         storage_rebate,
diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index d9229cd6374..7eb0b5050db 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -48,6 +48,7 @@ title: Module `0x3::iota_system_state_inner`
 -  [Function `update_validator_next_epoch_network_pubkey`](#0x3_iota_system_state_inner_update_validator_next_epoch_network_pubkey)
 -  [Function `update_candidate_validator_network_pubkey`](#0x3_iota_system_state_inner_update_candidate_validator_network_pubkey)
 -  [Function `advance_epoch`](#0x3_iota_system_state_inner_advance_epoch)
+-  [Function `match_iota_supply_to_target_reward`](#0x3_iota_system_state_inner_match_iota_supply_to_target_reward)
 -  [Function `epoch`](#0x3_iota_system_state_inner_epoch)
 -  [Function `protocol_version`](#0x3_iota_system_state_inner_protocol_version)
 -  [Function `system_state_version`](#0x3_iota_system_state_inner_system_state_version)
@@ -2076,7 +2077,7 @@ gas coins.
 4. Update all validators.
 
 
-
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -2089,6 +2090,7 @@ gas coins. self: &mut IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, + validator_target_reward: u64, mut storage_reward: Balance<IOTA>, mut computation_reward: Balance<IOTA>, mut storage_rebate_amount: u64, @@ -2158,6 +2160,12 @@ gas coins. storage_fund_reinvestment_amount as u64, ); + let mut computation_reward = match_iota_supply_to_target_reward( + validator_target_reward, + computation_reward, + &mut self.iota_treasury_cap, + ); + self.epoch = self.epoch + 1; // Sanity check to make sure we are advancing to the right epoch. assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch); @@ -2233,6 +2241,48 @@ gas coins. + + + + +## Function `match_iota_supply_to_target_reward` + +Mint or burn IOTA tokens depending on the given target reward per validator +and the amount of computation fees burned in this epoch. + + +
public(friend) fun match_iota_supply_to_target_reward(validator_target_reward: u64, computation_reward: balance::Balance<iota::IOTA>, iota_treasury_cap: &mut coin::TreasuryCap<iota::IOTA>): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
public(package) fun match_iota_supply_to_target_reward(
+  validator_target_reward: u64,
+  mut computation_reward: Balance<IOTA>,
+  iota_treasury_cap: &mut iota::coin::TreasuryCap<IOTA>
+): Balance<IOTA> {
+  if (computation_reward.value() < validator_target_reward) {
+    let tokens_to_mint = validator_target_reward - computation_reward.value();
+    let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint);
+    computation_reward.join(new_tokens);
+    computation_reward
+  } else if (computation_reward.value() > validator_target_reward) {
+    let tokens_to_burn = computation_reward.value() - validator_target_reward;
+    let rewards_to_burn = computation_reward.split(tokens_to_burn);
+    iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn);
+    computation_reward
+  } else {
+    computation_reward
+  }
+}
+
+ + +
From 5be190c6705cf7b014100cec859a57560cb18764 Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Wed, 3 Jul 2024 14:55:27 +0300 Subject: [PATCH 05/50] feat: implemented IotaTreasuryCap --- .../docs/iota-framework/iota.md | 186 +++++++++++++++++- .../docs/iota-system/genesis.md | 4 +- .../docs/iota-system/iota_system.md | 4 +- .../iota-system/iota_system_state_inner.md | 8 +- .../packages/iota-framework/sources/iota.move | 62 +++++- .../iota-framework/tests/iota_tests.move | 133 +++++++++++++ .../packages/iota-system/sources/genesis.move | 5 +- .../iota-system/sources/iota_system.move | 6 +- .../sources/iota_system_state_inner.move | 10 +- .../tests/governance_test_utils.move | 25 ++- .../iota-system/tests/iota_system_tests.move | 4 +- 11 files changed, 403 insertions(+), 44 deletions(-) create mode 100644 crates/iota-framework/packages/iota-framework/tests/iota_tests.move diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md index cdfe7c56477..40578216259 100644 --- a/crates/iota-framework/docs/iota-framework/iota.md +++ b/crates/iota-framework/docs/iota-framework/iota.md @@ -7,9 +7,15 @@ It has 9 decimals, and the smallest unit (10^-9) is called "micros". - [Struct `IOTA`](#0x2_iota_IOTA) +- [Struct `IotaTreasuryCap`](#0x2_iota_IotaTreasuryCap) - [Constants](#@Constants_0) - [Function `new`](#0x2_iota_new) - [Function `transfer`](#0x2_iota_transfer) +- [Function `mint`](#0x2_iota_mint) +- [Function `mint_balance`](#0x2_iota_mint_balance) +- [Function `burn`](#0x2_iota_burn) +- [Function `burn_balance`](#0x2_iota_burn_balance) +- [Function `total_supply`](#0x2_iota_total_supply) - [Function `mint_genesis_supply`](#0x2_iota_mint_genesis_supply) @@ -49,6 +55,35 @@ Name of the coin + + + + +## Struct `IotaTreasuryCap` + +The IOTA token treasury capability. +Protects the token from unauthorized changes. + + +
struct IotaTreasuryCap has store
+
+ + + +
+Fields + + +
+
+inner: coin::TreasuryCap<iota::IOTA> +
+
+ +
+
+ +
@@ -110,11 +145,11 @@ The total supply of Iota denominated in Micros (10 Billion * 10^9) ## Function `new` -Register the IOTA Coin to acquire its TreasuryCap. +Register the IOTA Coin to acquire IotaTreasuryCap. This should be called only once during genesis creation. -
fun new(ctx: &mut tx_context::TxContext): coin::TreasuryCap<iota::IOTA>
+
fun new(ctx: &mut tx_context::TxContext): iota::IotaTreasuryCap
 
@@ -123,7 +158,7 @@ This should be called only once during genesis creation. Implementation -
fun new(ctx: &mut TxContext): TreasuryCap<IOTA> {
+
fun new(ctx: &mut TxContext): IotaTreasuryCap {
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
     assert!(ctx.epoch() == 0, EAlreadyMinted);
 
@@ -140,7 +175,9 @@ This should be called only once during genesis creation.
 
     transfer::public_freeze_object(metadata);
 
-    treasury
+    IotaTreasuryCap {
+        inner: treasury,
+    }
 }
 
@@ -170,6 +207,140 @@ This should be called only once during genesis creation. + + + + +## Function `mint` + +Create an IOTA coin worth value and increase the total supply in cap accordingly. + + +
public fun mint(cap: &mut iota::IotaTreasuryCap, value: u64, ctx: &mut tx_context::TxContext): coin::Coin<iota::IOTA>
+
+ + + +
+Implementation + + +
public fun mint(cap: &mut IotaTreasuryCap, value: u64, ctx: &mut TxContext): Coin<IOTA> {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    cap.inner.mint(value, ctx)
+}
+
+ + + +
+ + + +## Function `mint_balance` + +Mint some amount of IOTA as a Balance and increase the total supply in cap accordingly. +Aborts if value + cap.inner.total_supply >= U64_MAX + + +
public fun mint_balance(cap: &mut iota::IotaTreasuryCap, value: u64, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
public fun mint_balance(cap: &mut IotaTreasuryCap, value: u64, ctx: &TxContext): Balance<IOTA> {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    cap.inner.mint_balance(value)
+}
+
+ + + +
+ + + +## Function `burn` + +Destroy the IOTA coin c and decrease the total supply in cap accordingly. + + +
public fun burn(cap: &mut iota::IotaTreasuryCap, c: coin::Coin<iota::IOTA>, ctx: &tx_context::TxContext): u64
+
+ + + +
+Implementation + + +
public fun burn(cap: &mut IotaTreasuryCap, c: Coin<IOTA>, ctx: &TxContext): u64 {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    cap.inner.burn(c)
+}
+
+ + + +
+ + + +## Function `burn_balance` + +Destroy the IOTA balance b and decrease the total supply in cap accordingly. + + +
public fun burn_balance(cap: &mut iota::IotaTreasuryCap, b: balance::Balance<iota::IOTA>, ctx: &tx_context::TxContext): u64
+
+ + + +
+Implementation + + +
public fun burn_balance(cap: &mut IotaTreasuryCap, b: Balance<IOTA>, ctx: &TxContext): u64 {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    cap.inner.supply_mut().decrease_supply(b)
+}
+
+ + + +
+ + + +## Function `total_supply` + +Return the total number of IOTA's in circulation. + + +
public fun total_supply(cap: &iota::IotaTreasuryCap): u64
+
+ + + +
+Implementation + + +
public fun total_supply(cap: &IotaTreasuryCap): u64 {
+    cap.inner.total_supply()
+}
+
+ + +
@@ -180,7 +351,7 @@ Increase the IOTA supply. This should be called only once during genesis creation. -
fun mint_genesis_supply(cap: &mut coin::TreasuryCap<iota::IOTA>, amount: u64, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
+
fun mint_genesis_supply(cap: &mut iota::IotaTreasuryCap, value: u64, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -189,11 +360,10 @@ This should be called only once during genesis creation. Implementation -
fun mint_genesis_supply(cap: &mut TreasuryCap<IOTA>, amount: u64, ctx: &TxContext): Balance<IOTA> {
-    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
fun mint_genesis_supply(cap: &mut IotaTreasuryCap, value: u64, ctx: &TxContext): Balance<IOTA> {
     assert!(ctx.epoch() == 0, EAlreadyMinted);
 
-    cap.mint_balance(amount)
+    cap.mint_balance(value, ctx)
 }
 
diff --git a/crates/iota-framework/docs/iota-system/genesis.md b/crates/iota-framework/docs/iota-system/genesis.md index 15afdec723b..7df192aa1c3 100644 --- a/crates/iota-framework/docs/iota-system/genesis.md +++ b/crates/iota-framework/docs/iota-system/genesis.md @@ -340,7 +340,7 @@ It will create a singleton IotaSystemState object, which contains all the information we need in the system. -
fun create(iota_system_state_id: object::UID, iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, iota_supply: balance::Balance<iota::IOTA>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
+
fun create(iota_system_state_id: object::UID, iota_treasury_cap: iota::IotaTreasuryCap, iota_supply: balance::Balance<iota::IOTA>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
 
@@ -351,7 +351,7 @@ all the information we need in the system.
fun create(
     iota_system_state_id: UID,
-    iota_treasury_cap: TreasuryCap<IOTA>,
+    iota_treasury_cap: IotaTreasuryCap,
     mut iota_supply: Balance<IOTA>,
     genesis_chain_parameters: GenesisChainParameters,
     genesis_validators: vector<GenesisValidatorMetadata>,
diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md
index 0d030e5f8a8..e54f243c8f2 100644
--- a/crates/iota-framework/docs/iota-system/iota_system.md
+++ b/crates/iota-framework/docs/iota-system/iota_system.md
@@ -167,7 +167,7 @@ Create a new IotaSystemState object and make it shared.
 This function will be called only once in genesis.
 
 
-
public(friend) fun create(id: object::UID, iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
+
public(friend) fun create(id: object::UID, iota_treasury_cap: iota::IotaTreasuryCap, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
 
@@ -178,7 +178,7 @@ This function will be called only once in genesis.
public(package) fun create(
     id: UID,
-    iota_treasury_cap: TreasuryCap<IOTA>,
+    iota_treasury_cap: IotaTreasuryCap,
     validators: vector<Validator>,
     storage_fund: Balance<IOTA>,
     protocol_version: u64,
diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index d9229cd6374..f20fbea3919 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -281,7 +281,7 @@ The top-level object containing all information of the Iota system.
  we know what version it is by inspecting IotaSystemStateInner as well.
 
-iota_treasury_cap: coin::TreasuryCap<iota::IOTA> +iota_treasury_cap: iota::IotaTreasuryCap
The IOTA's TreasuryCap. @@ -419,7 +419,7 @@ Uses SystemParametersV2 as the parameters. we know what version it is by inspecting IotaSystemStateInner as well.
-iota_treasury_cap: coin::TreasuryCap<iota::IOTA> +iota_treasury_cap: iota::IotaTreasuryCap
The IOTA's TreasuryCap. @@ -753,7 +753,7 @@ Create a new IotaSystemState object and make it shared. This function will be called only once in genesis. -
public(friend) fun create(iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
+
public(friend) fun create(iota_treasury_cap: iota::IotaTreasuryCap, validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
 
@@ -763,7 +763,7 @@ This function will be called only once in genesis.
public(package) fun create(
-    iota_treasury_cap: TreasuryCap<IOTA>,
+    iota_treasury_cap: IotaTreasuryCap,
     validators: vector<Validator>,
     initial_storage_fund: Balance<IOTA>,
     protocol_version: u64,
diff --git a/crates/iota-framework/packages/iota-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move
index cf836d2e969..716da1f68c8 100644
--- a/crates/iota-framework/packages/iota-framework/sources/iota.move
+++ b/crates/iota-framework/packages/iota-framework/sources/iota.move
@@ -6,7 +6,7 @@
 /// It has 9 decimals, and the smallest unit (10^-9) is called "micros".
 module iota::iota {
     use iota::balance::Balance;
-    use iota::coin::{Self, TreasuryCap};
+    use iota::coin::{Self, Coin, TreasuryCap};
 
     const EAlreadyMinted: u64 = 0;
     /// Sender is not @0x0 the system address.
@@ -28,10 +28,16 @@ module iota::iota {
     /// Name of the coin
     public struct IOTA has drop {}
 
+    /// The IOTA token treasury capability.
+    /// Protects the token from unauthorized changes.
+    public struct IotaTreasuryCap has store {
+        inner: TreasuryCap,
+    }
+
     #[allow(unused_function)]
-    /// Register the `IOTA` Coin to acquire its `TreasuryCap`.
+    /// Register the `IOTA` Coin to acquire `IotaTreasuryCap`.
     /// This should be called only once during genesis creation.
-    fun new(ctx: &mut TxContext): TreasuryCap {
+    fun new(ctx: &mut TxContext): IotaTreasuryCap {
         assert!(ctx.sender() == @0x0, ENotSystemAddress);
         assert!(ctx.epoch() == 0, EAlreadyMinted);
 
@@ -48,20 +54,62 @@ module iota::iota {
 
         transfer::public_freeze_object(metadata);
 
-        treasury
+        IotaTreasuryCap {
+            inner: treasury,
+        }
     }
 
     public entry fun transfer(c: coin::Coin, recipient: address) {
         transfer::public_transfer(c, recipient)
     }
 
+    /// Create an IOTA coin worth `value` and increase the total supply in `cap` accordingly.
+    public fun mint(cap: &mut IotaTreasuryCap, value: u64, ctx: &mut TxContext): Coin {
+        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+        cap.inner.mint(value, ctx)
+    }
+
+    /// Mint some amount of IOTA as a `Balance` and increase the total supply in `cap` accordingly.
+    /// Aborts if `value` + `cap.inner.total_supply` >= U64_MAX
+    public fun mint_balance(cap: &mut IotaTreasuryCap, value: u64, ctx: &TxContext): Balance {
+        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+        cap.inner.mint_balance(value)
+    }
+
+    /// Destroy the IOTA coin `c` and decrease the total supply in `cap` accordingly.
+    public fun burn(cap: &mut IotaTreasuryCap, c: Coin, ctx: &TxContext): u64 {
+        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+        cap.inner.burn(c)
+    }
+
+    /// Destroy the IOTA balance `b` and decrease the total supply in `cap` accordingly.
+    public fun burn_balance(cap: &mut IotaTreasuryCap, b: Balance, ctx: &TxContext): u64 {
+        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+        cap.inner.supply_mut().decrease_supply(b)
+    }
+
+    /// Return the total number of IOTA's in circulation.
+    public fun total_supply(cap: &IotaTreasuryCap): u64 {
+        cap.inner.total_supply()
+    }
+
     #[allow(unused_function)]
     /// Increase the IOTA supply.
     /// This should be called only once during genesis creation.
-    fun mint_genesis_supply(cap: &mut TreasuryCap, amount: u64, ctx: &TxContext): Balance {
-        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+    fun mint_genesis_supply(cap: &mut IotaTreasuryCap, value: u64, ctx: &TxContext): Balance {
         assert!(ctx.epoch() == 0, EAlreadyMinted);
 
-        cap.mint_balance(amount)
+        cap.mint_balance(value, ctx)
+    }
+
+    #[test_only]
+    public fun create_for_testing(ctx: &mut TxContext): IotaTreasuryCap {
+        // The `new` function must be called here to be sure that the test function
+        // contains all the important checks.
+        new(ctx)
     }
 }
diff --git a/crates/iota-framework/packages/iota-framework/tests/iota_tests.move b/crates/iota-framework/packages/iota-framework/tests/iota_tests.move
new file mode 100644
index 00000000000..0a9d3a3e8d6
--- /dev/null
+++ b/crates/iota-framework/packages/iota-framework/tests/iota_tests.move
@@ -0,0 +1,133 @@
+// Copyright (c) 2024 IOTA Stiftung
+// SPDX-License-Identifier: Apache-2.0
+
+#[test_only]
+module iota::iota_tests {
+
+    use iota::iota;
+    use iota::test_scenario;
+    use iota::test_utils::{Self, assert_eq};
+
+    #[test]
+    fun test_mint_burn_flow() {
+        // Set up a test enviroment.
+        let mut scenario = test_scenario::begin(@0x0);
+        let ctx = scenario.ctx();
+
+        // Create an IOTA treasury capability.
+        let mut iota_treasury_cap = iota::create_for_testing(ctx);
+
+        // Mint some IOTA.
+        let iota_coin = iota_treasury_cap.mint(100, ctx);
+
+        assert_eq(iota_treasury_cap.total_supply(), 100);
+
+        let iota_balance = iota_treasury_cap.mint_balance(200, ctx);
+
+        assert_eq(iota_treasury_cap.total_supply(), 300);
+
+        // Burn some IOTA.
+        iota_treasury_cap.burn(iota_coin, ctx);
+
+        assert_eq(iota_treasury_cap.total_supply(), 200);
+
+        iota_treasury_cap.burn_balance(iota_balance, ctx);
+
+        assert_eq(iota_treasury_cap.total_supply(), 0);
+
+        // Cleanup.
+        test_utils::destroy(iota_treasury_cap);
+    
+        scenario.end();
+    }
+
+    #[test]
+    #[expected_failure(abort_code = iota::ENotSystemAddress)]
+    fun test_mint_coins_by_custom_address() {
+        // Set up a test enviroment.
+        let mut scenario = test_scenario::begin(@0xA);
+
+        // Create an IOTA treasury capability.
+        let mut iota_treasury_cap = iota::create_for_testing(scenario.ctx());
+
+        // Mint some IOTA coins.
+        let iota = iota_treasury_cap.mint(100, scenario.ctx());
+
+        // Cleanup.
+        test_utils::destroy(iota);
+        test_utils::destroy(iota_treasury_cap);
+
+        scenario.end();
+    }
+
+    #[test]
+    #[expected_failure(abort_code = iota::ENotSystemAddress)]
+    fun test_burn_coins_by_custom_address() {
+        // Set up a test enviroment.
+        let mut scenario = test_scenario::begin(@0x0);
+
+        // Create an IOTA treasury capability.
+        let mut iota_treasury_cap = iota::create_for_testing(scenario.ctx());
+
+        // Mint some IOTA coins.
+        let iota = iota_treasury_cap.mint(100, scenario.ctx());
+
+        assert_eq(iota_treasury_cap.total_supply(), 100);
+
+        // Switch to a custom address.
+        scenario.next_tx(@0xA);
+
+        // Burn some IOTA coins.
+        iota_treasury_cap.burn(iota, scenario.ctx());
+
+        // Cleanup.
+        test_utils::destroy(iota_treasury_cap);
+
+        scenario.end();
+    }
+
+    #[test]
+    #[expected_failure(abort_code = iota::ENotSystemAddress)]
+    fun test_mint_balance_by_custom_address() {
+        // Set up a test enviroment.
+        let mut scenario = test_scenario::begin(@0xA);
+
+        // Create an IOTA treasury capability.
+        let mut iota_treasury_cap = iota::create_for_testing(scenario.ctx());
+
+        // Mint some IOTA balance.
+        let iota = iota_treasury_cap.mint_balance(100, scenario.ctx());
+
+        // Cleanup.
+        test_utils::destroy(iota);
+        test_utils::destroy(iota_treasury_cap);
+
+        scenario.end();
+    }
+
+    #[test]
+    #[expected_failure(abort_code = iota::ENotSystemAddress)]
+    fun test_burn_balance_by_custom_address() {
+        // Set up a test enviroment.
+        let mut scenario = test_scenario::begin(@0x0);
+
+        // Create an IOTA treasury capability.
+        let mut iota_treasury_cap = iota::create_for_testing(scenario.ctx());
+
+        // Mint some IOTA balance.
+        let iota = iota_treasury_cap.mint_balance(100, scenario.ctx());
+
+        assert_eq(iota_treasury_cap.total_supply(), 100);
+
+        // Switch to a custom address.
+        scenario.next_tx(@0xA);
+
+        // Burn some IOTA balance.
+        iota_treasury_cap.burn_balance(iota, scenario.ctx());
+
+        // Cleanup.
+        test_utils::destroy(iota_treasury_cap);
+
+        scenario.end();
+    }
+}
diff --git a/crates/iota-framework/packages/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move
index b669b58398c..037666f57aa 100644
--- a/crates/iota-framework/packages/iota-system/sources/genesis.move
+++ b/crates/iota-framework/packages/iota-system/sources/genesis.move
@@ -5,8 +5,7 @@
 module iota_system::genesis {
 
     use iota::balance::{Self, Balance};
-    use iota::coin::TreasuryCap;
-    use iota::iota::{Self, IOTA};
+    use iota::iota::{Self, IOTA, IotaTreasuryCap};
     use iota_system::iota_system;
     use iota_system::validator::{Self, Validator};
     use iota_system::validator_set;
@@ -80,7 +79,7 @@ module iota_system::genesis {
     /// all the information we need in the system.
     fun create(
         iota_system_state_id: UID,
-        iota_treasury_cap: TreasuryCap,
+        iota_treasury_cap: IotaTreasuryCap,
         mut iota_supply: Balance,
         genesis_chain_parameters: GenesisChainParameters,
         genesis_validators: vector,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move
index 4f01e7cf08f..7d07457998e 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move
@@ -42,9 +42,9 @@
 module iota_system::iota_system {
     use iota::balance::Balance;
 
-    use iota::coin::{Coin, TreasuryCap};
+    use iota::coin::Coin;
     use iota_system::staking_pool::StakedIota;
-    use iota::iota::IOTA;
+    use iota::iota::{IOTA, IotaTreasuryCap};
     use iota::table::Table;
     use iota_system::validator::Validator;
     use iota_system::validator_cap::UnverifiedValidatorOperationCap;
@@ -78,7 +78,7 @@ module iota_system::iota_system {
     /// This function will be called only once in genesis.
     public(package) fun create(
         id: UID,
-        iota_treasury_cap: TreasuryCap,
+        iota_treasury_cap: IotaTreasuryCap,
         validators: vector,
         storage_fund: Balance,
         protocol_version: u64,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index ceaf0a25532..ba3e04c01f4 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -4,9 +4,9 @@
 
 module iota_system::iota_system_state_inner {
     use iota::balance::{Self, Balance};
-    use iota::coin::{Coin, TreasuryCap};
+    use iota::coin::Coin;
     use iota_system::staking_pool::{stake_activation_epoch, StakedIota};
-    use iota::iota::IOTA;
+    use iota::iota::{IOTA, IotaTreasuryCap};
     use iota_system::validator::{Self, Validator};
     use iota_system::validator_set::{Self, ValidatorSet};
     use iota_system::validator_cap::{UnverifiedValidatorOperationCap, ValidatorOperationCap};
@@ -111,7 +111,7 @@ module iota_system::iota_system_state_inner {
         /// we know what version it is by inspecting IotaSystemStateInner as well.
         system_state_version: u64,
         /// The IOTA's TreasuryCap.
-        iota_treasury_cap: TreasuryCap,
+        iota_treasury_cap: IotaTreasuryCap,
         /// Contains all information about the validators.
         validators: ValidatorSet,
         /// The storage fund.
@@ -161,7 +161,7 @@ module iota_system::iota_system_state_inner {
         /// we know what version it is by inspecting IotaSystemStateInner as well.
         system_state_version: u64,
         /// The IOTA's TreasuryCap.
-        iota_treasury_cap: TreasuryCap,
+        iota_treasury_cap: IotaTreasuryCap,
         /// Contains all information about the validators.
         validators: ValidatorSet,
         /// The storage fund.
@@ -236,7 +236,7 @@ module iota_system::iota_system_state_inner {
     /// Create a new IotaSystemState object and make it shared.
     /// This function will be called only once in genesis.
     public(package) fun create(
-        iota_treasury_cap: TreasuryCap,
+        iota_treasury_cap: IotaTreasuryCap,
         validators: vector,
         initial_storage_fund: Balance,
         protocol_version: u64,
diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
index 2a3f4fee26c..c1df45791a5 100644
--- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
+++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
@@ -6,7 +6,7 @@
 module iota_system::governance_test_utils {
     use iota::address;
     use iota::balance;
-    use iota::iota::IOTA;
+    use iota::iota::{Self, IOTA};
     use iota::coin::{Self, Coin};
     use iota_system::staking_pool::{StakedIota, StakingPool};
     use iota::test_utils::assert_eq;
@@ -73,14 +73,23 @@ module iota_system::governance_test_utils {
             ctx,
         );
 
-        let mut iota_treasury_cap = coin::create_treasury_cap_for_testing(ctx);
-        let supply = iota_treasury_cap.supply_mut().increase_supply(iota_supply_amount * MICROS_PER_IOTA);
+        let mut iota_treasury_cap = iota::create_for_testing(ctx);
+
+        let stake_subsidy_balance = iota_treasury_cap.mint_balance(
+            iota_supply_amount * MICROS_PER_IOTA,
+            ctx,
+        );
 
         let stake_subsidy = stake_subsidy::create(
-            supply, // iota_supply
-            0,      // stake subsidy initial distribution amount
-            10,     // stake_subsidy_period_length
-            0,      // stake_subsidy_decrease_rate
+            stake_subsidy_balance,
+            0,  // stake subsidy initial distribution amount
+            10, // stake_subsidy_period_length
+            0,  // stake_subsidy_decrease_rate
+            ctx,
+        );
+
+        let storage_fund = iota_treasury_cap.mint_balance(
+            storage_fund_amount * MICROS_PER_IOTA,
             ctx,
         );
 
@@ -88,7 +97,7 @@ module iota_system::governance_test_utils {
             object::new(ctx), // it doesn't matter what ID iota system state has in tests
             iota_treasury_cap,
             validators,
-            balance::create_for_testing(storage_fund_amount * MICROS_PER_IOTA), // storage_fund
+            storage_fund, // storage_fund
             1,   // protocol version
             0,   // chain_start_timestamp_ms
             system_parameters,
diff --git a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
index 0761eab8301..43107d246d5 100644
--- a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
@@ -578,7 +578,7 @@ module iota_system::iota_system_tests {
         let new_pubkey1 = x"91b8de031e0b60861c655c8168596d98b065d57f26f287f8c810590b06a636eff13c4055983e95b2f60a4d6ba5484fa4176923d1f7807cc0b222ddf6179c1db099dba0433f098aae82542b3fd27b411d64a0a35aad01b2c07ac67f7d0a1d2c11";
         let new_pop1 = x"b61913eb4dc7ea1d92f174e1a3c6cad3f49ae8de40b13b69046ce072d8d778bfe87e734349c7394fd1543fff0cb6e2d0";
 
-        let mut scenario_val = test_scenario::begin(validator_addr);
+        let mut scenario_val = test_scenario::begin(@0x0);
         let scenario = &mut scenario_val;
 
         // Set up IotaSystemState with an active validator
@@ -920,7 +920,7 @@ module iota_system::iota_system_tests {
         let new_pubkey = x"96d19c53f1bee2158c3fcfb5bb2f06d3a8237667529d2d8f0fbb22fe5c3b3e64748420b4103674490476d98530d063271222d2a59b0f7932909cc455a30f00c69380e6885375e94243f7468e9563aad29330aca7ab431927540e9508888f0e1c";
         let new_pop = x"932336c35a8c393019c63eb0f7d385dd4e0bd131f04b54cf45aa9544f14dca4dab53bd70ffcb8e0b34656e4388309720";
 
-        let mut scenario_val = test_scenario::begin(validator_addr);
+        let mut scenario_val = test_scenario::begin(@0x0);
         let scenario = &mut scenario_val;
 
         // Set up IotaSystemState with an active validator

From 7ca61902bfdc8a1f95307a84bfc4a563e2ae2fe6 Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Wed, 3 Jul 2024 15:28:45 +0300
Subject: [PATCH 06/50] feat: added tests checking IOTA creation processes

---
 .../iota-framework/tests/iota_tests.move      | 53 +++++++++++++++----
 1 file changed, 43 insertions(+), 10 deletions(-)

diff --git a/crates/iota-framework/packages/iota-framework/tests/iota_tests.move b/crates/iota-framework/packages/iota-framework/tests/iota_tests.move
index 0a9d3a3e8d6..3aff62dbb99 100644
--- a/crates/iota-framework/packages/iota-framework/tests/iota_tests.move
+++ b/crates/iota-framework/packages/iota-framework/tests/iota_tests.move
@@ -8,9 +8,42 @@ module iota::iota_tests {
     use iota::test_scenario;
     use iota::test_utils::{Self, assert_eq};
 
+    #[test]
+    #[expected_failure(abort_code = iota::ENotSystemAddress)]
+    fun test_create_iota_from_wrong_address() {
+        // Set up a test environment.
+        let mut scenario = test_scenario::begin(@0xA);
+
+        // Create an IOTA treasury capability.
+        let iota_treasury_cap = iota::create_for_testing(scenario.ctx());
+
+        // Cleanup.
+        test_utils::destroy(iota_treasury_cap);
+
+        scenario.end();
+    }
+
+    #[test]
+    #[expected_failure(abort_code = iota::EAlreadyMinted)]
+    fun test_create_iota_during_wrong_epoch() {
+        // Set up a test environment.
+        let mut scenario = test_scenario::begin(@0x0);
+
+        // Advance the scenario to a new epoch.
+        scenario.next_epoch(@0x0);
+
+        // Create an IOTA treasury capability.
+        let iota_treasury_cap = iota::create_for_testing(scenario.ctx());
+
+        // Cleanup.
+        test_utils::destroy(iota_treasury_cap);
+
+        scenario.end();
+    }
+
     #[test]
     fun test_mint_burn_flow() {
-        // Set up a test enviroment.
+        // Set up a test environment.
         let mut scenario = test_scenario::begin(@0x0);
         let ctx = scenario.ctx();
 
@@ -43,8 +76,8 @@ module iota::iota_tests {
 
     #[test]
     #[expected_failure(abort_code = iota::ENotSystemAddress)]
-    fun test_mint_coins_by_custom_address() {
-        // Set up a test enviroment.
+    fun test_mint_coins_by_wrong_address() {
+        // Set up a test environment.
         let mut scenario = test_scenario::begin(@0xA);
 
         // Create an IOTA treasury capability.
@@ -62,8 +95,8 @@ module iota::iota_tests {
 
     #[test]
     #[expected_failure(abort_code = iota::ENotSystemAddress)]
-    fun test_burn_coins_by_custom_address() {
-        // Set up a test enviroment.
+    fun test_burn_coins_by_wrong_address() {
+        // Set up a test environment.
         let mut scenario = test_scenario::begin(@0x0);
 
         // Create an IOTA treasury capability.
@@ -74,7 +107,7 @@ module iota::iota_tests {
 
         assert_eq(iota_treasury_cap.total_supply(), 100);
 
-        // Switch to a custom address.
+        // Switch to a wrong address.
         scenario.next_tx(@0xA);
 
         // Burn some IOTA coins.
@@ -88,8 +121,8 @@ module iota::iota_tests {
 
     #[test]
     #[expected_failure(abort_code = iota::ENotSystemAddress)]
-    fun test_mint_balance_by_custom_address() {
-        // Set up a test enviroment.
+    fun test_mint_balance_by_wrong_address() {
+        // Set up a test environment.
         let mut scenario = test_scenario::begin(@0xA);
 
         // Create an IOTA treasury capability.
@@ -108,7 +141,7 @@ module iota::iota_tests {
     #[test]
     #[expected_failure(abort_code = iota::ENotSystemAddress)]
     fun test_burn_balance_by_custom_address() {
-        // Set up a test enviroment.
+        // Set up a test environment.
         let mut scenario = test_scenario::begin(@0x0);
 
         // Create an IOTA treasury capability.
@@ -119,7 +152,7 @@ module iota::iota_tests {
 
         assert_eq(iota_treasury_cap.total_supply(), 100);
 
-        // Switch to a custom address.
+        // Switch to a wrong address.
         scenario.next_tx(@0xA);
 
         // Burn some IOTA balance.

From bee2ce27f13da2f7906c3773f190495e926f2209 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Wed, 3 Jul 2024 16:18:49 +0200
Subject: [PATCH 07/50] feat: Make inflation/deflation tests more
 understandable

---
 .../tests/rewards_distribution_tests.move     | 25 +++++++++++++------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
index 40555c8d38c..d93649d9aba 100644
--- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
@@ -87,11 +87,16 @@ module iota_system::rewards_distribution_tests {
         let scenario = &mut scenario_val;
         let prev_supply = total_supply(scenario);
 
+        let validator_target_reward = 100;
+        let computation_reward = 100;
+
         // need to advance epoch so validator's staking starts counting
         advance_epoch(scenario);
-        advance_epoch_with_target_reward_amounts(100, 0, 100, scenario);
+        advance_epoch_with_target_reward_amounts(validator_target_reward, 0, computation_reward, scenario);
 
         let new_supply = total_supply(scenario);
+        // Since the target reward and computation reward are the same, no new tokens should
+        // have been minted, so the supply should stay constant.
         assert!(prev_supply == new_supply, 0);
 
         scenario_val.end();
@@ -104,13 +109,16 @@ module iota_system::rewards_distribution_tests {
         let scenario = &mut scenario_val;
         let prev_supply = total_supply(scenario);
 
+        let validator_target_reward = 60;
+        let computation_reward = 100;
+
         // need to advance epoch so validator's staking starts counting
         advance_epoch(scenario);
-        advance_epoch_with_target_reward_amounts(60, 0, 100, scenario);
+        advance_epoch_with_target_reward_amounts(validator_target_reward, 0, computation_reward, scenario);
 
         let new_supply = total_supply(scenario);
-        // 40 tokens should have been burned.
-        assert!(prev_supply - 40 * MICROS_PER_IOTA == new_supply, 0);
+        // The difference between target reward and computation reward should have been burned.
+        assert!(prev_supply - (computation_reward - validator_target_reward) * MICROS_PER_IOTA == new_supply, 0);
 
         scenario_val.end();
     }
@@ -122,13 +130,16 @@ module iota_system::rewards_distribution_tests {
         let scenario = &mut scenario_val;
         let prev_supply = total_supply(scenario);
 
+        let validator_target_reward = 100;
+        let computation_reward = 60;
+
         // need to advance epoch so validator's staking starts counting
         advance_epoch(scenario);
-        advance_epoch_with_target_reward_amounts(100, 0, 60, scenario);
+        advance_epoch_with_target_reward_amounts(validator_target_reward, 0, computation_reward, scenario);
 
         let new_supply = total_supply(scenario);
-        // 40 tokens should have been minted.
-        assert!(prev_supply + 40 * MICROS_PER_IOTA == new_supply, 0);
+        // The difference between target reward and computation reward should have been minted.
+        assert!(prev_supply + (validator_target_reward - computation_reward) * MICROS_PER_IOTA == new_supply, 0);
 
         scenario_val.end();
     }

From 123ef7baeccb7dd3713b54162e20871c95736080 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Thu, 4 Jul 2024 08:32:21 +0200
Subject: [PATCH 08/50] feat: Use `IotaTreasuryCap` for minting and burning

---
 .../iota-system/sources/iota_system_state_inner.move      | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index 966f8448511..2e1ba11dbfe 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -901,6 +901,7 @@ module iota_system::iota_system_state_inner {
           validator_target_reward,
           computation_reward,
           &mut self.iota_treasury_cap,
+          ctx
         );
 
         self.epoch = self.epoch + 1;
@@ -980,17 +981,18 @@ module iota_system::iota_system_state_inner {
     public(package) fun match_iota_supply_to_target_reward(
       validator_target_reward: u64,
       mut computation_reward: Balance,
-      iota_treasury_cap: &mut iota::coin::TreasuryCap
+      iota_treasury_cap: &mut iota::iota::IotaTreasuryCap,
+      ctx: &TxContext,
     ): Balance {
       if (computation_reward.value() < validator_target_reward) {
         let tokens_to_mint = validator_target_reward - computation_reward.value();
-        let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint);
+        let new_tokens = iota_treasury_cap.mint_balance(tokens_to_mint, ctx);
         computation_reward.join(new_tokens);
         computation_reward
       } else if (computation_reward.value() > validator_target_reward) {
         let tokens_to_burn = computation_reward.value() - validator_target_reward;
         let rewards_to_burn = computation_reward.split(tokens_to_burn);
-        iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn);
+        iota_treasury_cap.burn_balance(rewards_to_burn, ctx);
         computation_reward
       } else {
         computation_reward

From ae2bff79e42dbf11853bf727cb32fdce8d4ff6fa Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Thu, 4 Jul 2024 16:12:51 +0200
Subject: [PATCH 09/50] feat(sc-platform): Disable stake subsidies (#992)

* feat: Set disabling params for stake subsidies

* feat: Never pay out rewards from stake subsidies

* fix: Remove stake subsidy start epoch overwrite completely
---
 .../docs/iota-system/iota_system_state_inner.md            | 7 ++++---
 .../iota-system/sources/iota_system_state_inner.move       | 5 -----
 2 files changed, 4 insertions(+), 8 deletions(-)

diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index f20fbea3919..875956cc8ef 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -2110,10 +2110,11 @@ gas coins.
         EBpsTooLarge,
     );
 
+    // Do not overwrite the start epoch.
     // TODO: remove this in later upgrade.
-    if (self.parameters.stake_subsidy_start_epoch > 0) {
-        self.parameters.stake_subsidy_start_epoch = 20;
-    };
+    // if (self.parameters.stake_subsidy_start_epoch > 0) {
+    //     self.parameters.stake_subsidy_start_epoch = 20;
+    // };
 
     // Accumulate the gas summary during safe_mode before processing any rewards:
     let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all();
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index ba3e04c01f4..97546d4066c 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -848,11 +848,6 @@ module iota_system::iota_system_state_inner {
             EBpsTooLarge,
         );
 
-        // TODO: remove this in later upgrade.
-        if (self.parameters.stake_subsidy_start_epoch > 0) {
-            self.parameters.stake_subsidy_start_epoch = 20;
-        };
-
         // Accumulate the gas summary during safe_mode before processing any rewards:
         let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all();
         storage_reward.join(safe_mode_storage_rewards);

From 1d049d0b6ae18d4bb8be74deb911c415913b006b Mon Sep 17 00:00:00 2001
From: Dkwcs 
Date: Thu, 4 Jul 2024 19:08:10 +0300
Subject: [PATCH 10/50] feat(iota-protocol-config): disabling
 storage_fund_reinvest_rate

---
 .../docs/iota-system/iota_system_state_inner.md             | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index 875956cc8ef..24bb5b0cff9 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -2110,12 +2110,6 @@ gas coins.
         EBpsTooLarge,
     );
 
-    // Do not overwrite the start epoch.
-    // TODO: remove this in later upgrade.
-    // if (self.parameters.stake_subsidy_start_epoch > 0) {
-    //     self.parameters.stake_subsidy_start_epoch = 20;
-    // };
-
     // Accumulate the gas summary during safe_mode before processing any rewards:
     let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all();
     storage_reward.join(safe_mode_storage_rewards);

From 40d1056e98702ab48acfe85adaf69491ce4cc908 Mon Sep 17 00:00:00 2001
From: Dkwcs 
Date: Thu, 4 Jul 2024 23:01:50 +0300
Subject: [PATCH 11/50] feat(iota-framework): burning leftover rewards,
 storage_fund doesn't earn from that

---
 .../docs/iota-system/iota_system_state_inner.md       | 11 ++++-------
 .../iota-framework/docs/iota-system/storage_fund.md   |  6 ++----
 .../iota-system/sources/iota_system_state_inner.move  |  5 ++++-
 .../packages/iota-system/sources/storage_fund.move    |  4 +---
 .../iota-system/tests/rewards_distribution_tests.move |  8 ++++----
 5 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index 875956cc8ef..1e0734d0de0 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -2110,12 +2110,6 @@ gas coins.
         EBpsTooLarge,
     );
 
-    // Do not overwrite the start epoch.
-    // TODO: remove this in later upgrade.
-    // if (self.parameters.stake_subsidy_start_epoch > 0) {
-    //     self.parameters.stake_subsidy_start_epoch = 20;
-    // };
-
     // Accumulate the gas summary during safe_mode before processing any rewards:
     let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all();
     storage_reward.join(safe_mode_storage_rewards);
@@ -2195,16 +2189,19 @@ gas coins.
     leftover_staking_rewards.join(computation_reward);
     let leftover_storage_fund_inflow = leftover_staking_rewards.value();
 
+    // Burning leftover rewards
+    self.iota_treasury_cap.burn_balance(leftover_staking_rewards, ctx);
+
     let refunded_storage_rebate =
         self.storage_fund.advance_epoch(
             storage_reward,
             storage_fund_reinvestment,
-            leftover_staking_rewards,
             storage_rebate_amount,
             non_refundable_storage_fee_amount,
         );
 
     event::emit(
+        //TODO: Add additional information (e.g., how much was burned, how much was leftover, etc.)
         SystemEpochInfoEvent {
             epoch: self.epoch,
             protocol_version: self.protocol_version,
diff --git a/crates/iota-framework/docs/iota-system/storage_fund.md b/crates/iota-framework/docs/iota-system/storage_fund.md
index a9205a960c8..2a9da300d6d 100644
--- a/crates/iota-framework/docs/iota-system/storage_fund.md
+++ b/crates/iota-framework/docs/iota-system/storage_fund.md
@@ -94,7 +94,7 @@ Called by iota_system
 Called by iota_system at epoch change times to process the inflows and outflows of storage fund.
 
 
-
public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, storage_fund_reinvestment: balance::Balance<iota::IOTA>, leftover_staking_rewards: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, storage_fund_reinvestment: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<iota::IOTA>
 
@@ -107,13 +107,11 @@ Called by iota_system self: &mut StorageFund, storage_charges: Balance<IOTA>, storage_fund_reinvestment: Balance<IOTA>, - leftover_staking_rewards: Balance<IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, ) : Balance<IOTA> { - // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance. + // The reinvestment rewards are not to be refunded so they go to the non-refundable balance. self.non_refundable_balance.join(storage_fund_reinvestment); - self.non_refundable_balance.join(leftover_staking_rewards); // The storage charges for the epoch come from the storage rebate of the new objects created // and the new storage rebates of the objects modified during the epoch so we put the charges diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 97546d4066c..23af4d3b09d 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -927,16 +927,19 @@ module iota_system::iota_system_state_inner { leftover_staking_rewards.join(computation_reward); let leftover_storage_fund_inflow = leftover_staking_rewards.value(); + // Burning leftover rewards + self.iota_treasury_cap.burn_balance(leftover_staking_rewards, ctx); + let refunded_storage_rebate = self.storage_fund.advance_epoch( storage_reward, storage_fund_reinvestment, - leftover_staking_rewards, storage_rebate_amount, non_refundable_storage_fee_amount, ); event::emit( + //TODO: Add additional information (e.g., how much was burned, how much was leftover, etc.) SystemEpochInfoEvent { epoch: self.epoch, protocol_version: self.protocol_version, diff --git a/crates/iota-framework/packages/iota-system/sources/storage_fund.move b/crates/iota-framework/packages/iota-system/sources/storage_fund.move index 02b1187b07d..b12a270c575 100644 --- a/crates/iota-framework/packages/iota-system/sources/storage_fund.move +++ b/crates/iota-framework/packages/iota-system/sources/storage_fund.move @@ -35,13 +35,11 @@ module iota_system::storage_fund { self: &mut StorageFund, storage_charges: Balance, storage_fund_reinvestment: Balance, - leftover_staking_rewards: Balance, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, ) : Balance { - // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance. + // The reinvestment rewards are not to be refunded so they go to the non-refundable balance. self.non_refundable_balance.join(storage_fund_reinvestment); - self.non_refundable_balance.join(leftover_staking_rewards); // The storage charges for the epoch come from the storage rebate of the new objects created // and the new storage rebates of the objects modified during the epoch so we put the charges diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move index 11c6fa0d8c1..f05f30f2dd3 100644 --- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -308,7 +308,7 @@ module iota_system::rewards_distribution_tests { #[test] fun test_everyone_slashed() { // This test is to make sure that if everyone is slashed, our protocol works as expected without aborting - // and all rewards go to the storage fund. + // and rewards are burned, and no tokens go to the storage fund. set_up_iota_system_state(); let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); let scenario = &mut scenario_val; @@ -327,16 +327,16 @@ module iota_system::rewards_distribution_tests { report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_1, scenario); advance_epoch_with_reward_amounts_and_slashing_rates( - 1000, 3000, 10_000, scenario + 1000, 500, 10_000, scenario ); // All validators should have 0 rewards added so their stake stays the same. assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MICROS_PER_IOTA, 200 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 400 * MICROS_PER_IOTA], scenario); scenario.next_tx(@0x0); - // Storage fund balance should increase by 4000 IOTA. + // Storage fund balance should be the same as before. let mut system_state = scenario.take_shared(); - assert_eq(system_state.get_storage_fund_total_balance(), 4000 * MICROS_PER_IOTA); + assert_eq(system_state.get_storage_fund_total_balance(), 1000 * MICROS_PER_IOTA); // The entire 1000 IOTA of storage rewards should go to the object rebate portion of the storage fund. assert_eq(system_state.get_storage_fund_object_rebates(), 1000 * MICROS_PER_IOTA); From ed26346b139c5c298e696bbeb481a2d6d5643fe2 Mon Sep 17 00:00:00 2001 From: Dkwcs Date: Fri, 5 Jul 2024 01:40:10 +0300 Subject: [PATCH 12/50] feat(iota-framework): storage_fund_reward has been removed --- .../iota-system/iota_system_state_inner.md | 61 +++--------- .../docs/iota-system/storage_fund.md | 6 +- .../docs/iota-system/validator_set.md | 98 ++++--------------- .../sources/iota_system_state_inner.move | 32 ++---- .../iota-system/sources/storage_fund.move | 4 +- .../iota-system/sources/validator_set.move | 92 +++-------------- .../tests/validator_set_tests.move | 6 -- 7 files changed, 55 insertions(+), 244 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 24bb5b0cff9..424946ff6b0 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -560,12 +560,6 @@ the epoch advancement transaction.
-
-
-storage_fund_reinvestment: u64 -
-
-
storage_charge: u64 @@ -584,12 +578,6 @@ the epoch advancement transaction.
-
-
-stake_subsidy_amount: u64 -
-
-
total_gas_fees: u64 @@ -2099,7 +2087,7 @@ gas coins. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, ) : Balance<IOTA> { - let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms; + //let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms; self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; @@ -2120,49 +2108,33 @@ gas coins. non_refundable_storage_fee_amount = non_refundable_storage_fee_amount + self.safe_mode_non_refundable_storage_fee; self.safe_mode_non_refundable_storage_fee = 0; - let total_validators_stake = self.validators.total_stake(); - let storage_fund_balance = self.storage_fund.total_balance(); - let total_stake = storage_fund_balance + total_validators_stake; - let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); // Include stake subsidy in the rewards given out to validators and stakers. // Delay distributing any stake subsidies until after `stake_subsidy_start_epoch`. // And if this epoch is shorter than the regular epoch duration, don't distribute any stake subsidy. - let stake_subsidy = - if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch && - epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms) - { - self.stake_subsidy.advance_epoch() - } else { - balance::zero() - }; - - let stake_subsidy_amount = stake_subsidy.value(); - computation_reward.join(stake_subsidy); + // let stake_subsidy = + // if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch && + // epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms) + // { + // self.stake_subsidy.advance_epoch() + // } else { + // balance::zero() + // }; - let total_stake_u128 = total_stake as u128; - let computation_charge_u128 = computation_charge as u128; + // let stake_subsidy_amount = stake_subsidy.value(); + //computation_reward.join(stake_subsidy); - let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128; - let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64); - let storage_fund_reinvestment_amount = - storage_fund_reward_amount * (storage_fund_reinvest_rate as u128) / BASIS_POINT_DENOMINATOR; - let storage_fund_reinvestment = storage_fund_reward.split( - storage_fund_reinvestment_amount as u64, - ); self.epoch = self.epoch + 1; // Sanity check to make sure we are advancing to the right epoch. assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch); let computation_reward_amount_before_distribution = computation_reward.value(); - let storage_fund_reward_amount_before_distribution = storage_fund_reward.value(); self.validators.advance_epoch( &mut computation_reward, - &mut storage_fund_reward, &mut self.validator_report_records, reward_slashing_rate, self.parameters.validator_low_stake_threshold, @@ -2174,9 +2146,7 @@ gas coins. let new_total_stake = self.validators.total_stake(); let computation_reward_amount_after_distribution = computation_reward.value(); - let storage_fund_reward_amount_after_distribution = storage_fund_reward.value(); let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; - let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution; self.protocol_version = next_protocol_version; @@ -2185,14 +2155,12 @@ gas coins. // Because of precision issues with integer divisions, we expect that there will be some // remaining balance in `storage_fund_reward` and `computation_reward`. // All of these go to the storage fund. - let mut leftover_staking_rewards = storage_fund_reward; - leftover_staking_rewards.join(computation_reward); + let leftover_staking_rewards = computation_reward; let leftover_storage_fund_inflow = leftover_staking_rewards.value(); let refunded_storage_rebate = self.storage_fund.advance_epoch( storage_reward, - storage_fund_reinvestment, leftover_staking_rewards, storage_rebate_amount, non_refundable_storage_fee_amount, @@ -2205,12 +2173,11 @@ gas coins. reference_gas_price: self.reference_gas_price, total_stake: new_total_stake, storage_charge, - storage_fund_reinvestment: storage_fund_reinvestment_amount as u64, storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), - stake_subsidy_amount, + //stake_subsidy_amount, total_gas_fees: computation_charge, - total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, + total_stake_rewards_distributed: computation_reward_distributed, leftover_storage_fund_inflow, } ); diff --git a/crates/iota-framework/docs/iota-system/storage_fund.md b/crates/iota-framework/docs/iota-system/storage_fund.md index a9205a960c8..1b844f3c14a 100644 --- a/crates/iota-framework/docs/iota-system/storage_fund.md +++ b/crates/iota-framework/docs/iota-system/storage_fund.md @@ -94,7 +94,7 @@ Called by iota_system Called by iota_system at epoch change times to process the inflows and outflows of storage fund. -
public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, storage_fund_reinvestment: balance::Balance<iota::IOTA>, leftover_staking_rewards: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, leftover_staking_rewards: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<iota::IOTA>
 
@@ -106,13 +106,11 @@ Called by iota_system
public(package) fun advance_epoch(
     self: &mut StorageFund,
     storage_charges: Balance<IOTA>,
-    storage_fund_reinvestment: Balance<IOTA>,
     leftover_staking_rewards: Balance<IOTA>,
     storage_rebate_amount: u64,
     non_refundable_storage_fee_amount: u64,
 ) : Balance<IOTA> {
-    // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance.
-    self.non_refundable_balance.join(storage_fund_reinvestment);
+    // Th leftover rewards are not to be refunded so they go to the non-refundable balance.
     self.non_refundable_balance.join(leftover_staking_rewards);
 
     // The storage charges for the epoch come from the storage rebate of the new objects created
diff --git a/crates/iota-framework/docs/iota-system/validator_set.md b/crates/iota-framework/docs/iota-system/validator_set.md
index 98d96d0b20c..72fde28e341 100644
--- a/crates/iota-framework/docs/iota-system/validator_set.md
+++ b/crates/iota-framework/docs/iota-system/validator_set.md
@@ -318,12 +318,6 @@ V2 of ValidatorEpochInfoEvent containing more information about the validator.
 
-
-
-storage_fund_staking_reward: u64 -
-
-
pool_token_exchange_rate: staking_pool::PoolTokenExchangeRate @@ -992,7 +986,7 @@ It does the following things: 5. At the end, we calculate the total stake for the new epoch. -
public(friend) fun advance_epoch(self: &mut validator_set::ValidatorSet, computation_reward: &mut balance::Balance<iota::IOTA>, storage_fund_reward: &mut balance::Balance<iota::IOTA>, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, reward_slashing_rate: u64, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, ctx: &mut tx_context::TxContext)
+
public(friend) fun advance_epoch(self: &mut validator_set::ValidatorSet, computation_reward: &mut balance::Balance<iota::IOTA>, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, reward_slashing_rate: u64, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, ctx: &mut tx_context::TxContext)
 
@@ -1004,7 +998,6 @@ It does the following things:
public(package) fun advance_epoch(
     self: &mut ValidatorSet,
     computation_reward: &mut Balance<IOTA>,
-    storage_fund_reward: &mut Balance<IOTA>,
     validator_report_records: &mut VecMap<address, VecSet<address>>,
     reward_slashing_rate: u64,
     low_stake_threshold: u64,
@@ -1016,11 +1009,10 @@ It does the following things:
     let total_voting_power = voting_power::total_voting_power();
 
     // Compute the reward distribution without taking into account the tallying rule slashing.
-    let (unadjusted_staking_reward_amounts, unadjusted_storage_fund_reward_amounts) = compute_unadjusted_reward_distribution(
+    let unadjusted_staking_reward_amounts = compute_unadjusted_reward_distribution(
         &self.active_validators,
         total_voting_power,
         computation_reward.value(),
-        storage_fund_reward.value(),
     );
 
     // Use the tallying rule report records for the epoch to compute validators that will be
@@ -1031,30 +1023,24 @@ It does the following things:
 
     // Compute the reward adjustments of slashed validators, to be taken into
     // account in adjusted reward computation.
-    let (total_staking_reward_adjustment, individual_staking_reward_adjustments,
-         total_storage_fund_reward_adjustment, individual_storage_fund_reward_adjustments
-        ) =
+    let (total_staking_reward_adjustment, individual_staking_reward_adjustments) =
         compute_reward_adjustments(
             get_validator_indices(&self.active_validators, &slashed_validators),
             reward_slashing_rate,
             &unadjusted_staking_reward_amounts,
-            &unadjusted_storage_fund_reward_amounts,
         );
 
     // Compute the adjusted amounts of stake each validator should get given the tallying rule
     // reward adjustments we computed before.
     // `compute_adjusted_reward_distribution` must be called before `distribute_reward` and `adjust_stake_and_gas_price` to
     // make sure we are using the current epoch's stake information to compute reward distribution.
-    let (adjusted_staking_reward_amounts, adjusted_storage_fund_reward_amounts) = compute_adjusted_reward_distribution(
+    let adjusted_staking_reward_amounts = compute_adjusted_reward_distribution(
         &self.active_validators,
         total_voting_power,
         total_slashed_validator_voting_power,
         unadjusted_staking_reward_amounts,
-        unadjusted_storage_fund_reward_amounts,
         total_staking_reward_adjustment,
         individual_staking_reward_adjustments,
-        total_storage_fund_reward_adjustment,
-        individual_storage_fund_reward_adjustments
     );
 
     // Distribute the rewards before adjusting stake so that we immediately start compounding
@@ -1062,9 +1048,7 @@ It does the following things:
     distribute_reward(
         &mut self.active_validators,
         &adjusted_staking_reward_amounts,
-        &adjusted_storage_fund_reward_amounts,
         computation_reward,
-        storage_fund_reward,
         ctx
     );
 
@@ -1074,7 +1058,7 @@ It does the following things:
 
     // Emit events after we have processed all the rewards distribution and pending stakes.
     emit_validator_epoch_events(new_epoch, &self.active_validators, &adjusted_staking_reward_amounts,
-        &adjusted_storage_fund_reward_amounts, validator_report_records, &slashed_validators);
+        validator_report_records, &slashed_validators);
 
     // Note that all their staged next epoch metadata will be effectuated below.
     process_pending_validators(self, new_epoch);
@@ -2390,7 +2374,7 @@ Compute both the individual reward adjustments and total reward adjustment for s
 as well as storage fund rewards.
 
 
-
fun compute_reward_adjustments(slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>, unadjusted_storage_fund_reward_amounts: &vector<u64>): (u64, vec_map::VecMap<u64, u64>, u64, vec_map::VecMap<u64, u64>)
+
fun compute_reward_adjustments(slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>): (u64, vec_map::VecMap<u64, u64>)
 
@@ -2403,17 +2387,12 @@ as well as storage fund rewards. mut slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>, - unadjusted_storage_fund_reward_amounts: &vector<u64>, ): ( u64, // sum of staking reward adjustments VecMap<u64, u64>, // mapping of individual validator's staking reward adjustment from index -> amount - u64, // sum of storage fund reward adjustments - VecMap<u64, u64>, // mapping of individual validator's storage fund reward adjustment from index -> amount ) { let mut total_staking_reward_adjustment = 0; let mut individual_staking_reward_adjustments = vec_map::empty(); - let mut total_storage_fund_reward_adjustment = 0; - let mut individual_storage_fund_reward_adjustments = vec_map::empty(); while (!slashed_validator_indices.is_empty()) { let validator_index = slashed_validator_indices.pop_back(); @@ -2427,20 +2406,9 @@ as well as storage fund rewards. // Insert into individual mapping and record into the total adjustment sum. individual_staking_reward_adjustments.insert(validator_index, staking_reward_adjustment_u128 as u64); total_staking_reward_adjustment = total_staking_reward_adjustment + (staking_reward_adjustment_u128 as u64); - - // Do the same thing for storage fund rewards. - let unadjusted_storage_fund_reward = unadjusted_storage_fund_reward_amounts[validator_index]; - let storage_fund_reward_adjustment_u128 = - unadjusted_storage_fund_reward as u128 * (reward_slashing_rate as u128) - / BASIS_POINT_DENOMINATOR; - individual_storage_fund_reward_adjustments.insert(validator_index, storage_fund_reward_adjustment_u128 as u64); - total_storage_fund_reward_adjustment = total_storage_fund_reward_adjustment + (storage_fund_reward_adjustment_u128 as u64); }; - ( - total_staking_reward_adjustment, individual_staking_reward_adjustments, - total_storage_fund_reward_adjustment, individual_storage_fund_reward_adjustments - ) + (total_staking_reward_adjustment, individual_staking_reward_adjustments) }
@@ -2501,7 +2469,7 @@ account the tallying rule results. Returns the unadjusted amounts of staking reward and storage fund reward for each validator. -
fun compute_unadjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_staking_reward: u64, total_storage_fund_reward: u64): (vector<u64>, vector<u64>)
+
fun compute_unadjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_staking_reward: u64): vector<u64>
 
@@ -2514,12 +2482,9 @@ Returns the unadjusted amounts of staking reward and storage fund reward for eac validators: &vector<Validator>, total_voting_power: u64, total_staking_reward: u64, - total_storage_fund_reward: u64, -): (vector<u64>, vector<u64>) { +): vector<u64> { let mut staking_reward_amounts = vector[]; - let mut storage_fund_reward_amounts = vector[]; let length = validators.length(); - let storage_fund_reward_per_validator = total_storage_fund_reward / length; let mut i = 0; while (i < length) { let validator = &validators[i]; @@ -2530,10 +2495,9 @@ Returns the unadjusted amounts of staking reward and storage fund reward for eac let reward_amount = voting_power * (total_staking_reward as u128) / (total_voting_power as u128); staking_reward_amounts.push_back(reward_amount as u64); // Storage fund's share of the rewards are equally distributed among validators. - storage_fund_reward_amounts.push_back(storage_fund_reward_per_validator); i = i + 1; }; - (staking_reward_amounts, storage_fund_reward_amounts) + staking_reward_amounts }
@@ -2550,7 +2514,7 @@ Returns the staking rewards each validator gets and the storage fund rewards eac The staking rewards are shared with the stakers while the storage fund ones are not. -
fun compute_adjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, unadjusted_storage_fund_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: vec_map::VecMap<u64, u64>, total_storage_fund_reward_adjustment: u64, individual_storage_fund_reward_adjustments: vec_map::VecMap<u64, u64>): (vector<u64>, vector<u64>)
+
fun compute_adjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: vec_map::VecMap<u64, u64>): vector<u64>
 
@@ -2564,18 +2528,13 @@ The staking rewards are shared with the stakers while the storage fund ones are total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, - unadjusted_storage_fund_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: VecMap<u64, u64>, - total_storage_fund_reward_adjustment: u64, - individual_storage_fund_reward_adjustments: VecMap<u64, u64>, -): (vector<u64>, vector<u64>) { +): vector<u64> { let total_unslashed_validator_voting_power = total_voting_power - total_slashed_validator_voting_power; let mut adjusted_staking_reward_amounts = vector[]; - let mut adjusted_storage_fund_reward_amounts = vector[]; let length = validators.length(); - let num_unslashed_validators = length - individual_staking_reward_adjustments.size(); let mut i = 0; while (i < length) { @@ -2601,24 +2560,10 @@ The staking rewards are shared with the stakers while the storage fund ones are }; adjusted_staking_reward_amounts.push_back(adjusted_staking_reward_amount); - // Compute adjusted storage fund reward. - let unadjusted_storage_fund_reward_amount = unadjusted_storage_fund_reward_amounts[i]; - let adjusted_storage_fund_reward_amount = - // If the validator is one of the slashed ones, then subtract the adjustment. - if (individual_storage_fund_reward_adjustments.contains(&i)) { - let adjustment = individual_storage_fund_reward_adjustments[&i]; - unadjusted_storage_fund_reward_amount - adjustment - } else { - // Otherwise the slashed rewards should be equally distributed among the unslashed validators. - let adjustment = total_storage_fund_reward_adjustment / num_unslashed_validators; - unadjusted_storage_fund_reward_amount + adjustment - }; - adjusted_storage_fund_reward_amounts.push_back(adjusted_storage_fund_reward_amount); - i = i + 1; }; - (adjusted_staking_reward_amounts, adjusted_storage_fund_reward_amounts) + adjusted_staking_reward_amounts }
@@ -2632,7 +2577,7 @@ The staking rewards are shared with the stakers while the storage fund ones are -
fun distribute_reward(validators: &mut vector<validator::Validator>, adjusted_staking_reward_amounts: &vector<u64>, adjusted_storage_fund_reward_amounts: &vector<u64>, staking_rewards: &mut balance::Balance<iota::IOTA>, storage_fund_reward: &mut balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext)
+
fun distribute_reward(validators: &mut vector<validator::Validator>, adjusted_staking_reward_amounts: &vector<u64>, staking_rewards: &mut balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext)
 
@@ -2644,9 +2589,7 @@ The staking rewards are shared with the stakers while the storage fund ones are
fun distribute_reward(
     validators: &mut vector<Validator>,
     adjusted_staking_reward_amounts: &vector<u64>,
-    adjusted_storage_fund_reward_amounts: &vector<u64>,
     staking_rewards: &mut Balance<IOTA>,
-    storage_fund_reward: &mut Balance<IOTA>,
     ctx: &mut TxContext
 ) {
     let length = validators.length();
@@ -2660,13 +2603,8 @@ The staking rewards are shared with the stakers while the storage fund ones are
         // Validator takes a cut of the rewards as commission.
         let validator_commission_amount = (staking_reward_amount as u128) * (validator.commission_rate() as u128) / BASIS_POINT_DENOMINATOR;
 
-        // The validator reward = storage_fund_reward + commission.
-        let mut validator_reward = staker_reward.split(validator_commission_amount as u64);
-
-        // Add storage fund rewards to the validator's reward.
-        validator_reward.join(
-	    	storage_fund_reward.split(adjusted_storage_fund_reward_amounts[i])
-	    );
+        // The validator reward = commission.
+        let validator_reward = staker_reward.split(validator_commission_amount as u64);
 
         // Add rewards to the validator. Don't try and distribute rewards though if the payout is zero.
         if (validator_reward.value() > 0) {
@@ -2696,7 +2634,7 @@ Emit events containing information of each validator for the epoch,
 including stakes, rewards, performance, etc.
 
 
-
fun emit_validator_epoch_events(new_epoch: u64, vs: &vector<validator::Validator>, pool_staking_reward_amounts: &vector<u64>, storage_fund_staking_reward_amounts: &vector<u64>, report_records: &vec_map::VecMap<address, vec_set::VecSet<address>>, slashed_validators: &vector<address>)
+
fun emit_validator_epoch_events(new_epoch: u64, vs: &vector<validator::Validator>, pool_staking_reward_amounts: &vector<u64>, report_records: &vec_map::VecMap<address, vec_set::VecSet<address>>, slashed_validators: &vector<address>)
 
@@ -2709,7 +2647,6 @@ including stakes, rewards, performance, etc. new_epoch: u64, vs: &vector<Validator>, pool_staking_reward_amounts: &vector<u64>, - storage_fund_staking_reward_amounts: &vector<u64>, report_records: &VecMap<address, VecSet<address>>, slashed_validators: &vector<address>, ) { @@ -2736,7 +2673,6 @@ including stakes, rewards, performance, etc. voting_power: v.voting_power(), commission_rate: v.commission_rate(), pool_staking_reward: pool_staking_reward_amounts[i], - storage_fund_staking_reward: storage_fund_staking_reward_amounts[i], pool_token_exchange_rate: v.pool_token_exchange_rate_at_epoch(new_epoch), tallying_rule_reporters, tallying_rule_global_score, diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 97546d4066c..7a8fbae7cbb 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -207,7 +207,6 @@ module iota_system::iota_system_state_inner { protocol_version: u64, reference_gas_price: u64, total_stake: u64, - storage_fund_reinvestment: u64, storage_charge: u64, storage_rebate: u64, storage_fund_balance: u64, @@ -831,6 +830,7 @@ module iota_system::iota_system_state_inner { mut computation_reward: Balance, mut storage_rebate_amount: u64, mut non_refundable_storage_fee_amount: u64, + //TODO: should be removed(obsolete) storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested // into storage fund, in basis point. reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. @@ -843,6 +843,7 @@ module iota_system::iota_system_state_inner { let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; // Rates can't be higher than 100%. assert!( + //TODO: should be removed(obsolete) storage_fund_reinvest_rate <= bps_denominator_u64 && reward_slashing_rate <= bps_denominator_u64, EBpsTooLarge, @@ -858,10 +859,6 @@ module iota_system::iota_system_state_inner { non_refundable_storage_fee_amount = non_refundable_storage_fee_amount + self.safe_mode_non_refundable_storage_fee; self.safe_mode_non_refundable_storage_fee = 0; - let total_validators_stake = self.validators.total_stake(); - let storage_fund_balance = self.storage_fund.total_balance(); - let total_stake = storage_fund_balance + total_validators_stake; - let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); @@ -880,27 +877,15 @@ module iota_system::iota_system_state_inner { let stake_subsidy_amount = stake_subsidy.value(); computation_reward.join(stake_subsidy); - let total_stake_u128 = total_stake as u128; - let computation_charge_u128 = computation_charge as u128; - - let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128; - let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64); - let storage_fund_reinvestment_amount = - storage_fund_reward_amount * (storage_fund_reinvest_rate as u128) / BASIS_POINT_DENOMINATOR; - let storage_fund_reinvestment = storage_fund_reward.split( - storage_fund_reinvestment_amount as u64, - ); self.epoch = self.epoch + 1; // Sanity check to make sure we are advancing to the right epoch. assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch); let computation_reward_amount_before_distribution = computation_reward.value(); - let storage_fund_reward_amount_before_distribution = storage_fund_reward.value(); self.validators.advance_epoch( &mut computation_reward, - &mut storage_fund_reward, &mut self.validator_report_records, reward_slashing_rate, self.parameters.validator_low_stake_threshold, @@ -912,9 +897,7 @@ module iota_system::iota_system_state_inner { let new_total_stake = self.validators.total_stake(); let computation_reward_amount_after_distribution = computation_reward.value(); - let storage_fund_reward_amount_after_distribution = storage_fund_reward.value(); let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; - let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution; self.protocol_version = next_protocol_version; @@ -923,15 +906,13 @@ module iota_system::iota_system_state_inner { // Because of precision issues with integer divisions, we expect that there will be some // remaining balance in `storage_fund_reward` and `computation_reward`. // All of these go to the storage fund. - let mut leftover_staking_rewards = storage_fund_reward; - leftover_staking_rewards.join(computation_reward); + let leftover_staking_rewards = computation_reward; let leftover_storage_fund_inflow = leftover_staking_rewards.value(); let refunded_storage_rebate = self.storage_fund.advance_epoch( - storage_reward, - storage_fund_reinvestment, - leftover_staking_rewards, + storage_reward, + leftover_staking_rewards, storage_rebate_amount, non_refundable_storage_fee_amount, ); @@ -943,12 +924,11 @@ module iota_system::iota_system_state_inner { reference_gas_price: self.reference_gas_price, total_stake: new_total_stake, storage_charge, - storage_fund_reinvestment: storage_fund_reinvestment_amount as u64, storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), stake_subsidy_amount, total_gas_fees: computation_charge, - total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, + total_stake_rewards_distributed: computation_reward_distributed, leftover_storage_fund_inflow, } ); diff --git a/crates/iota-framework/packages/iota-system/sources/storage_fund.move b/crates/iota-framework/packages/iota-system/sources/storage_fund.move index 02b1187b07d..f4de4b62308 100644 --- a/crates/iota-framework/packages/iota-system/sources/storage_fund.move +++ b/crates/iota-framework/packages/iota-system/sources/storage_fund.move @@ -34,13 +34,11 @@ module iota_system::storage_fund { public(package) fun advance_epoch( self: &mut StorageFund, storage_charges: Balance, - storage_fund_reinvestment: Balance, leftover_staking_rewards: Balance, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, ) : Balance { - // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance. - self.non_refundable_balance.join(storage_fund_reinvestment); + // Th leftover rewards are not to be refunded so they go to the non-refundable balance. self.non_refundable_balance.join(leftover_staking_rewards); // The storage charges for the epoch come from the storage rebate of the new objects created diff --git a/crates/iota-framework/packages/iota-system/sources/validator_set.move b/crates/iota-framework/packages/iota-system/sources/validator_set.move index 6ef543868b1..9379eaabdee 100644 --- a/crates/iota-framework/packages/iota-system/sources/validator_set.move +++ b/crates/iota-framework/packages/iota-system/sources/validator_set.move @@ -77,7 +77,6 @@ module iota_system::validator_set { stake: u64, commission_rate: u64, pool_staking_reward: u64, - storage_fund_staking_reward: u64, pool_token_exchange_rate: PoolTokenExchangeRate, tallying_rule_reporters: vector
, tallying_rule_global_score: u64, @@ -92,7 +91,6 @@ module iota_system::validator_set { voting_power: u64, commission_rate: u64, pool_staking_reward: u64, - storage_fund_staking_reward: u64, pool_token_exchange_rate: PoolTokenExchangeRate, tallying_rule_reporters: vector
, tallying_rule_global_score: u64, @@ -344,7 +342,6 @@ module iota_system::validator_set { public(package) fun advance_epoch( self: &mut ValidatorSet, computation_reward: &mut Balance, - storage_fund_reward: &mut Balance, validator_report_records: &mut VecMap>, reward_slashing_rate: u64, low_stake_threshold: u64, @@ -356,11 +353,10 @@ module iota_system::validator_set { let total_voting_power = voting_power::total_voting_power(); // Compute the reward distribution without taking into account the tallying rule slashing. - let (unadjusted_staking_reward_amounts, unadjusted_storage_fund_reward_amounts) = compute_unadjusted_reward_distribution( + let unadjusted_staking_reward_amounts = compute_unadjusted_reward_distribution( &self.active_validators, total_voting_power, computation_reward.value(), - storage_fund_reward.value(), ); // Use the tallying rule report records for the epoch to compute validators that will be @@ -371,30 +367,24 @@ module iota_system::validator_set { // Compute the reward adjustments of slashed validators, to be taken into // account in adjusted reward computation. - let (total_staking_reward_adjustment, individual_staking_reward_adjustments, - total_storage_fund_reward_adjustment, individual_storage_fund_reward_adjustments - ) = + let (total_staking_reward_adjustment, individual_staking_reward_adjustments) = compute_reward_adjustments( get_validator_indices(&self.active_validators, &slashed_validators), reward_slashing_rate, &unadjusted_staking_reward_amounts, - &unadjusted_storage_fund_reward_amounts, ); // Compute the adjusted amounts of stake each validator should get given the tallying rule // reward adjustments we computed before. // `compute_adjusted_reward_distribution` must be called before `distribute_reward` and `adjust_stake_and_gas_price` to // make sure we are using the current epoch's stake information to compute reward distribution. - let (adjusted_staking_reward_amounts, adjusted_storage_fund_reward_amounts) = compute_adjusted_reward_distribution( + let adjusted_staking_reward_amounts = compute_adjusted_reward_distribution( &self.active_validators, total_voting_power, total_slashed_validator_voting_power, unadjusted_staking_reward_amounts, - unadjusted_storage_fund_reward_amounts, total_staking_reward_adjustment, individual_staking_reward_adjustments, - total_storage_fund_reward_adjustment, - individual_storage_fund_reward_adjustments ); // Distribute the rewards before adjusting stake so that we immediately start compounding @@ -402,9 +392,7 @@ module iota_system::validator_set { distribute_reward( &mut self.active_validators, &adjusted_staking_reward_amounts, - &adjusted_storage_fund_reward_amounts, computation_reward, - storage_fund_reward, ctx ); @@ -414,7 +402,7 @@ module iota_system::validator_set { // Emit events after we have processed all the rewards distribution and pending stakes. emit_validator_epoch_events(new_epoch, &self.active_validators, &adjusted_staking_reward_amounts, - &adjusted_storage_fund_reward_amounts, validator_report_records, &slashed_validators); + validator_report_records, &slashed_validators); // Note that all their staged next epoch metadata will be effectuated below. process_pending_validators(self, new_epoch); @@ -971,22 +959,16 @@ module iota_system::validator_set { } /// Compute both the individual reward adjustments and total reward adjustment for staking rewards - /// as well as storage fund rewards. fun compute_reward_adjustments( mut slashed_validator_indices: vector, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector, - unadjusted_storage_fund_reward_amounts: &vector, ): ( u64, // sum of staking reward adjustments VecMap, // mapping of individual validator's staking reward adjustment from index -> amount - u64, // sum of storage fund reward adjustments - VecMap, // mapping of individual validator's storage fund reward adjustment from index -> amount ) { let mut total_staking_reward_adjustment = 0; let mut individual_staking_reward_adjustments = vec_map::empty(); - let mut total_storage_fund_reward_adjustment = 0; - let mut individual_storage_fund_reward_adjustments = vec_map::empty(); while (!slashed_validator_indices.is_empty()) { let validator_index = slashed_validator_indices.pop_back(); @@ -1000,20 +982,9 @@ module iota_system::validator_set { // Insert into individual mapping and record into the total adjustment sum. individual_staking_reward_adjustments.insert(validator_index, staking_reward_adjustment_u128 as u64); total_staking_reward_adjustment = total_staking_reward_adjustment + (staking_reward_adjustment_u128 as u64); - - // Do the same thing for storage fund rewards. - let unadjusted_storage_fund_reward = unadjusted_storage_fund_reward_amounts[validator_index]; - let storage_fund_reward_adjustment_u128 = - unadjusted_storage_fund_reward as u128 * (reward_slashing_rate as u128) - / BASIS_POINT_DENOMINATOR; - individual_storage_fund_reward_adjustments.insert(validator_index, storage_fund_reward_adjustment_u128 as u64); - total_storage_fund_reward_adjustment = total_storage_fund_reward_adjustment + (storage_fund_reward_adjustment_u128 as u64); }; - ( - total_staking_reward_adjustment, individual_staking_reward_adjustments, - total_storage_fund_reward_adjustment, individual_storage_fund_reward_adjustments - ) + (total_staking_reward_adjustment, individual_staking_reward_adjustments) } /// Process the validator report records of the epoch and return the addresses of the @@ -1042,17 +1013,14 @@ module iota_system::validator_set { /// Given the current list of active validators, the total stake and total reward, /// calculate the amount of reward each validator should get, without taking into /// account the tallying rule results. - /// Returns the unadjusted amounts of staking reward and storage fund reward for each validator. + /// Returns the unadjusted amounts of staking reward for each validator. fun compute_unadjusted_reward_distribution( validators: &vector, total_voting_power: u64, total_staking_reward: u64, - total_storage_fund_reward: u64, - ): (vector, vector) { + ): vector { let mut staking_reward_amounts = vector[]; - let mut storage_fund_reward_amounts = vector[]; let length = validators.length(); - let storage_fund_reward_per_validator = total_storage_fund_reward / length; let mut i = 0; while (i < length) { let validator = &validators[i]; @@ -1062,33 +1030,26 @@ module iota_system::validator_set { let voting_power: u128 = validator.voting_power() as u128; let reward_amount = voting_power * (total_staking_reward as u128) / (total_voting_power as u128); staking_reward_amounts.push_back(reward_amount as u64); - // Storage fund's share of the rewards are equally distributed among validators. - storage_fund_reward_amounts.push_back(storage_fund_reward_per_validator); i = i + 1; }; - (staking_reward_amounts, storage_fund_reward_amounts) + staking_reward_amounts } /// Use the reward adjustment info to compute the adjusted rewards each validator should get. - /// Returns the staking rewards each validator gets and the storage fund rewards each validator gets. - /// The staking rewards are shared with the stakers while the storage fund ones are not. + /// Returns the staking rewards each validator gets. + /// The staking rewards are shared with the stakers. fun compute_adjusted_reward_distribution( validators: &vector, total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector, - unadjusted_storage_fund_reward_amounts: vector, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: VecMap, - total_storage_fund_reward_adjustment: u64, - individual_storage_fund_reward_adjustments: VecMap, - ): (vector, vector) { + ): vector { let total_unslashed_validator_voting_power = total_voting_power - total_slashed_validator_voting_power; let mut adjusted_staking_reward_amounts = vector[]; - let mut adjusted_storage_fund_reward_amounts = vector[]; let length = validators.length(); - let num_unslashed_validators = length - individual_staking_reward_adjustments.size(); let mut i = 0; while (i < length) { @@ -1114,32 +1075,16 @@ module iota_system::validator_set { }; adjusted_staking_reward_amounts.push_back(adjusted_staking_reward_amount); - // Compute adjusted storage fund reward. - let unadjusted_storage_fund_reward_amount = unadjusted_storage_fund_reward_amounts[i]; - let adjusted_storage_fund_reward_amount = - // If the validator is one of the slashed ones, then subtract the adjustment. - if (individual_storage_fund_reward_adjustments.contains(&i)) { - let adjustment = individual_storage_fund_reward_adjustments[&i]; - unadjusted_storage_fund_reward_amount - adjustment - } else { - // Otherwise the slashed rewards should be equally distributed among the unslashed validators. - let adjustment = total_storage_fund_reward_adjustment / num_unslashed_validators; - unadjusted_storage_fund_reward_amount + adjustment - }; - adjusted_storage_fund_reward_amounts.push_back(adjusted_storage_fund_reward_amount); - i = i + 1; }; - (adjusted_staking_reward_amounts, adjusted_storage_fund_reward_amounts) + adjusted_staking_reward_amounts } fun distribute_reward( validators: &mut vector, adjusted_staking_reward_amounts: &vector, - adjusted_storage_fund_reward_amounts: &vector, staking_rewards: &mut Balance, - storage_fund_reward: &mut Balance, ctx: &mut TxContext ) { let length = validators.length(); @@ -1153,13 +1098,8 @@ module iota_system::validator_set { // Validator takes a cut of the rewards as commission. let validator_commission_amount = (staking_reward_amount as u128) * (validator.commission_rate() as u128) / BASIS_POINT_DENOMINATOR; - // The validator reward = storage_fund_reward + commission. - let mut validator_reward = staker_reward.split(validator_commission_amount as u64); - - // Add storage fund rewards to the validator's reward. - validator_reward.join( - storage_fund_reward.split(adjusted_storage_fund_reward_amounts[i]) - ); + // The validator reward = commission. + let validator_reward = staker_reward.split(validator_commission_amount as u64); // Add rewards to the validator. Don't try and distribute rewards though if the payout is zero. if (validator_reward.value() > 0) { @@ -1169,7 +1109,7 @@ module iota_system::validator_set { } else { validator_reward.destroy_zero(); }; - + // Add rewards to stake staking pool to auto compound for stakers. validator.deposit_stake_rewards(staker_reward); i = i + 1; @@ -1182,7 +1122,6 @@ module iota_system::validator_set { new_epoch: u64, vs: &vector, pool_staking_reward_amounts: &vector, - storage_fund_staking_reward_amounts: &vector, report_records: &VecMap>, slashed_validators: &vector
, ) { @@ -1209,7 +1148,6 @@ module iota_system::validator_set { voting_power: v.voting_power(), commission_rate: v.commission_rate(), pool_staking_reward: pool_staking_reward_amounts[i], - storage_fund_staking_reward: storage_fund_staking_reward_amounts[i], pool_token_exchange_rate: v.pool_token_exchange_rate_at_epoch(new_epoch), tallying_rule_reporters, tallying_rule_global_score, diff --git a/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move b/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move index 87461e3a91f..978a895afcd 100644 --- a/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move @@ -433,11 +433,9 @@ module iota_system::validator_set_tests { fun advance_epoch_with_dummy_rewards(validator_set: &mut ValidatorSet, scenario: &mut Scenario) { scenario.next_epoch(@0x0); let mut dummy_computation_reward = balance::zero(); - let mut dummy_storage_fund_reward = balance::zero(); validator_set.advance_epoch( &mut dummy_computation_reward, - &mut dummy_storage_fund_reward, &mut vec_map::empty(), 0, // reward_slashing_rate 0, // low_stake_threshold @@ -447,7 +445,6 @@ module iota_system::validator_set_tests { ); dummy_computation_reward.destroy_zero(); - dummy_storage_fund_reward.destroy_zero(); } fun advance_epoch_with_low_stake_params( @@ -459,10 +456,8 @@ module iota_system::validator_set_tests { ) { scenario.next_epoch(@0x0); let mut dummy_computation_reward = balance::zero(); - let mut dummy_storage_fund_reward = balance::zero(); validator_set.advance_epoch( &mut dummy_computation_reward, - &mut dummy_storage_fund_reward, &mut vec_map::empty(), 0, // reward_slashing_rate low_stake_threshold * MICROS_PER_IOTA, @@ -472,7 +467,6 @@ module iota_system::validator_set_tests { ); dummy_computation_reward.destroy_zero(); - dummy_storage_fund_reward.destroy_zero(); } fun add_and_activate_validator(validator_set: &mut ValidatorSet, validator: Validator, scenario: &mut Scenario) { From c586a9b8afcb50964290fd711b630ea3b66071f6 Mon Sep 17 00:00:00 2001 From: Dkwcs Date: Fri, 5 Jul 2024 01:54:55 +0300 Subject: [PATCH 13/50] feat(iota-framework): storage_fund_reinvest_rate has been removed from advance_epoch signature --- .../docs/iota-system/iota_system.md | 5 +-- .../iota-system/iota_system_state_inner.md | 40 +++++++++---------- .../docs/iota-system/validator_set.md | 14 ++----- .../iota-system/sources/iota_system.move | 5 --- .../sources/iota_system_state_inner.move | 10 +---- .../tests/governance_test_utils.move | 4 +- .../iota-system/tests/iota_system_tests.move | 2 +- 7 files changed, 28 insertions(+), 52 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md index e54f243c8f2..3c414fe0139 100644 --- a/crates/iota-framework/docs/iota-system/iota_system.md +++ b/crates/iota-framework/docs/iota-system/iota_system.md @@ -1362,7 +1362,7 @@ gas coins. 4. Update all validators. -
fun advance_epoch(storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
fun advance_epoch(storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -1379,8 +1379,6 @@ gas coins. next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, - storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -1395,7 +1393,6 @@ gas coins. computation_reward, storage_rebate, non_refundable_storage_fee, - storage_fund_reinvest_rate, reward_slashing_rate, epoch_start_timestamp_ms, ctx, diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 424946ff6b0..e5edceb18c3 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -578,6 +578,12 @@ the epoch advancement transaction.
+
+
+stake_subsidy_amount: u64 +
+
+
total_gas_fees: u64 @@ -2064,7 +2070,7 @@ gas coins. 4. Update all validators. -
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -2081,22 +2087,16 @@ gas coins. mut computation_reward: Balance<IOTA>, mut storage_rebate_amount: u64, mut non_refundable_storage_fee_amount: u64, - storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, ) : Balance<IOTA> { - //let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms; + let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms; self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; // Rates can't be higher than 100%. - assert!( - storage_fund_reinvest_rate <= bps_denominator_u64 - && reward_slashing_rate <= bps_denominator_u64, - EBpsTooLarge, - ); + assert!(reward_slashing_rate <= bps_denominator_u64, EBpsTooLarge); // Accumulate the gas summary during safe_mode before processing any rewards: let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all(); @@ -2114,17 +2114,17 @@ gas coins. // Include stake subsidy in the rewards given out to validators and stakers. // Delay distributing any stake subsidies until after `stake_subsidy_start_epoch`. // And if this epoch is shorter than the regular epoch duration, don't distribute any stake subsidy. - // let stake_subsidy = - // if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch && - // epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms) - // { - // self.stake_subsidy.advance_epoch() - // } else { - // balance::zero() - // }; + let stake_subsidy = + if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch && + epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms) + { + self.stake_subsidy.advance_epoch() + } else { + balance::zero() + }; - // let stake_subsidy_amount = stake_subsidy.value(); - //computation_reward.join(stake_subsidy); + let stake_subsidy_amount = stake_subsidy.value(); + computation_reward.join(stake_subsidy); self.epoch = self.epoch + 1; @@ -2175,7 +2175,7 @@ gas coins. storage_charge, storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), - //stake_subsidy_amount, + stake_subsidy_amount, total_gas_fees: computation_charge, total_stake_rewards_distributed: computation_reward_distributed, leftover_storage_fund_inflow, diff --git a/crates/iota-framework/docs/iota-system/validator_set.md b/crates/iota-framework/docs/iota-system/validator_set.md index 72fde28e341..00efabf245e 100644 --- a/crates/iota-framework/docs/iota-system/validator_set.md +++ b/crates/iota-framework/docs/iota-system/validator_set.md @@ -230,12 +230,6 @@ each validator, emitted during epoch advancement.
-
-
-storage_fund_staking_reward: u64 -
-
-
pool_token_exchange_rate: staking_pool::PoolTokenExchangeRate @@ -2371,7 +2365,6 @@ Process the pending stake changes for each validator. ## Function `compute_reward_adjustments` Compute both the individual reward adjustments and total reward adjustment for staking rewards -as well as storage fund rewards.
fun compute_reward_adjustments(slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>): (u64, vec_map::VecMap<u64, u64>)
@@ -2466,7 +2459,7 @@ non-performant validators according to the input threshold.
 Given the current list of active validators, the total stake and total reward,
 calculate the amount of reward each validator should get, without taking into
 account the tallying rule results.
-Returns the unadjusted amounts of staking reward and storage fund reward for each validator.
+Returns the unadjusted amounts of staking reward for each validator.
 
 
 
fun compute_unadjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_staking_reward: u64): vector<u64>
@@ -2494,7 +2487,6 @@ Returns the unadjusted amounts of staking reward and storage fund reward for eac
         let voting_power: u128 = validator.voting_power() as u128;
         let reward_amount = voting_power * (total_staking_reward as u128) / (total_voting_power as u128);
         staking_reward_amounts.push_back(reward_amount as u64);
-        // Storage fund's share of the rewards are equally distributed among validators.
         i = i + 1;
     };
     staking_reward_amounts
@@ -2510,8 +2502,8 @@ Returns the unadjusted amounts of staking reward and storage fund reward for eac
 ## Function `compute_adjusted_reward_distribution`
 
 Use the reward adjustment info to compute the adjusted rewards each validator should get.
-Returns the staking rewards each validator gets and the storage fund rewards each validator gets.
-The staking rewards are shared with the stakers while the storage fund ones are not.
+Returns the staking rewards each validator gets.
+The staking rewards are shared with the stakers.
 
 
 
fun compute_adjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: vec_map::VecMap<u64, u64>): vector<u64>
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move
index 7d07457998e..08e2a23672a 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move
@@ -545,8 +545,6 @@ module iota_system::iota_system {
         next_protocol_version: u64,
         storage_rebate: u64,
         non_refundable_storage_fee: u64,
-        storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested
-                                         // into storage fund, in basis point.
         reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps.
         epoch_start_timestamp_ms: u64, // Timestamp of the epoch start
         ctx: &mut TxContext,
@@ -561,7 +559,6 @@ module iota_system::iota_system {
             computation_reward,
             storage_rebate,
             non_refundable_storage_fee,
-            storage_fund_reinvest_rate,
             reward_slashing_rate,
             epoch_start_timestamp_ms,
             ctx,
@@ -750,7 +747,6 @@ module iota_system::iota_system {
         computation_charge: u64,
         storage_rebate: u64,
         non_refundable_storage_fee: u64,
-        storage_fund_reinvest_rate: u64,
         reward_slashing_rate: u64,
         epoch_start_timestamp_ms: u64,
         ctx: &mut TxContext,
@@ -765,7 +761,6 @@ module iota_system::iota_system {
             next_protocol_version,
             storage_rebate,
             non_refundable_storage_fee,
-            storage_fund_reinvest_rate,
             reward_slashing_rate,
             epoch_start_timestamp_ms,
             ctx,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index 7a8fbae7cbb..9f1a5501605 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -830,9 +830,6 @@ module iota_system::iota_system_state_inner {
         mut computation_reward: Balance,
         mut storage_rebate_amount: u64,
         mut non_refundable_storage_fee_amount: u64,
-        //TODO: should be removed(obsolete)
-        storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested
-                                         // into storage fund, in basis point.
         reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps.
         epoch_start_timestamp_ms: u64, // Timestamp of the epoch start
         ctx: &mut TxContext,
@@ -842,12 +839,7 @@ module iota_system::iota_system_state_inner {
 
         let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64;
         // Rates can't be higher than 100%.
-        assert!(
-            //TODO: should be removed(obsolete)
-            storage_fund_reinvest_rate <= bps_denominator_u64
-            && reward_slashing_rate <= bps_denominator_u64,
-            EBpsTooLarge,
-        );
+        assert!(reward_slashing_rate <= bps_denominator_u64, EBpsTooLarge);
 
         // Accumulate the gas summary during safe_mode before processing any rewards:
         let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all();
diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
index c1df45791a5..ff23b1dbf80 100644
--- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
+++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
@@ -135,7 +135,7 @@ module iota_system::governance_test_utils {
         let ctx = scenario.ctx();
 
         let storage_rebate = system_state.advance_epoch_for_testing(
-            new_epoch, 1, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx,
+            new_epoch, 1, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, ctx,
         );
         test_scenario::return_shared(system_state);
         scenario.next_epoch(@0x0);
@@ -162,7 +162,7 @@ module iota_system::governance_test_utils {
         let ctx = scenario.ctx();
 
         let storage_rebate = system_state.advance_epoch_for_testing(
-            new_epoch, 1, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, 0, reward_slashing_rate, 0, ctx
+            new_epoch, 1, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, reward_slashing_rate, 0, ctx
         );
         test_utils::destroy(storage_rebate);
         test_scenario::return_shared(system_state);
diff --git a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
index 43107d246d5..0a93a0587cf 100644
--- a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
@@ -996,7 +996,7 @@ module iota_system::iota_system_tests {
         let prev_counter = system_state.get_stake_subsidy_distribution_counter();
 
         let rebate = system_state.advance_epoch_for_testing(
-            new_epoch, 1, 0, 0, 0, 0, 0, 0, prev_epoch_time + epoch_length, scenario.ctx()
+            new_epoch, 1, 0, 0, 0, 0, 0, prev_epoch_time + epoch_length, scenario.ctx()
         );
         destroy(rebate);
         assert_eq(system_state.get_stake_subsidy_distribution_counter(), prev_counter + (if (should_increment_counter) 1 else 0));

From acdb32d4b4ddea50ba07652738257e6448ee2927 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 5 Jul 2024 09:38:15 +0200
Subject: [PATCH 14/50] fix: Use indentation of 4 everywhere

---
 .../iota-system/sources/iota_system.move      |  4 +-
 .../sources/iota_system_state_inner.move      | 42 +++++++++----------
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move
index a2cd37ea7ad..65012596188 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move
@@ -703,8 +703,8 @@ module iota_system::iota_system {
     #[test_only]
     /// Returns the total iota supply.
     public fun get_iota_supply(wrapper: &mut IotaSystemState): u64 {
-      let self = load_system_state(wrapper);
-      self.get_total_iota_supply()
+        let self = load_system_state(wrapper);
+        self.get_total_iota_supply()
     }
 
     // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED.  Creates a
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index 2e1ba11dbfe..d1c659f5872 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -898,10 +898,10 @@ module iota_system::iota_system_state_inner {
         );
 
         let mut computation_reward = match_iota_supply_to_target_reward(
-          validator_target_reward,
-          computation_reward,
-          &mut self.iota_treasury_cap,
-          ctx
+            validator_target_reward,
+            computation_reward,
+            &mut self.iota_treasury_cap,
+            ctx
         );
 
         self.epoch = self.epoch + 1;
@@ -979,24 +979,24 @@ module iota_system::iota_system_state_inner {
     /// Mint or burn IOTA tokens depending on the given target reward per validator
     /// and the amount of computation fees burned in this epoch.
     public(package) fun match_iota_supply_to_target_reward(
-      validator_target_reward: u64,
-      mut computation_reward: Balance,
-      iota_treasury_cap: &mut iota::iota::IotaTreasuryCap,
-      ctx: &TxContext,
+        validator_target_reward: u64,
+        mut computation_reward: Balance,
+        iota_treasury_cap: &mut iota::iota::IotaTreasuryCap,
+        ctx: &TxContext,
     ): Balance {
-      if (computation_reward.value() < validator_target_reward) {
-        let tokens_to_mint = validator_target_reward - computation_reward.value();
-        let new_tokens = iota_treasury_cap.mint_balance(tokens_to_mint, ctx);
-        computation_reward.join(new_tokens);
-        computation_reward
-      } else if (computation_reward.value() > validator_target_reward) {
-        let tokens_to_burn = computation_reward.value() - validator_target_reward;
-        let rewards_to_burn = computation_reward.split(tokens_to_burn);
-        iota_treasury_cap.burn_balance(rewards_to_burn, ctx);
-        computation_reward
-      } else {
-        computation_reward
-      }
+        if (computation_reward.value() < validator_target_reward) {
+            let tokens_to_mint = validator_target_reward - computation_reward.value();
+            let new_tokens = iota_treasury_cap.mint_balance(tokens_to_mint, ctx);
+            computation_reward.join(new_tokens);
+            computation_reward
+        } else if (computation_reward.value() > validator_target_reward) {
+            let tokens_to_burn = computation_reward.value() - validator_target_reward;
+            let rewards_to_burn = computation_reward.split(tokens_to_burn);
+            iota_treasury_cap.burn_balance(rewards_to_burn, ctx);
+            computation_reward
+        } else {
+            computation_reward
+        }
     }
 
     /// Return the current epoch number. Useful for applications that need a coarse-grained concept of time,

From 49de4012daa792854a0b6c4e7c11f9c029b58f18 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 5 Jul 2024 09:39:52 +0200
Subject: [PATCH 15/50] fix: Better name for minting/burning function

---
 .../packages/iota-system/sources/iota_system_state_inner.move | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index d1c659f5872..ac0931f4c48 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -897,7 +897,7 @@ module iota_system::iota_system_state_inner {
             storage_fund_reinvestment_amount as u64,
         );
 
-        let mut computation_reward = match_iota_supply_to_target_reward(
+        let mut computation_reward = match_computation_reward_to_target_reward(
             validator_target_reward,
             computation_reward,
             &mut self.iota_treasury_cap,
@@ -978,7 +978,7 @@ module iota_system::iota_system_state_inner {
 
     /// Mint or burn IOTA tokens depending on the given target reward per validator
     /// and the amount of computation fees burned in this epoch.
-    public(package) fun match_iota_supply_to_target_reward(
+    public(package) fun match_computation_reward_to_target_reward(
         validator_target_reward: u64,
         mut computation_reward: Balance,
         iota_treasury_cap: &mut iota::iota::IotaTreasuryCap,

From 2c9fa628e644a65e1138a2fc66281a03e06ee8e6 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 5 Jul 2024 09:57:23 +0200
Subject: [PATCH 16/50] fix: Make mint/burn function private

---
 .../iota-system/iota_system_state_inner.md    | 52 ++++++++++---------
 .../sources/iota_system_state_inner.move      |  2 +-
 2 files changed, 28 insertions(+), 26 deletions(-)

diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index eb6859c2fa3..ef576bf1361 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -48,7 +48,7 @@ title: Module `0x3::iota_system_state_inner`
 -  [Function `update_validator_next_epoch_network_pubkey`](#0x3_iota_system_state_inner_update_validator_next_epoch_network_pubkey)
 -  [Function `update_candidate_validator_network_pubkey`](#0x3_iota_system_state_inner_update_candidate_validator_network_pubkey)
 -  [Function `advance_epoch`](#0x3_iota_system_state_inner_advance_epoch)
--  [Function `match_iota_supply_to_target_reward`](#0x3_iota_system_state_inner_match_iota_supply_to_target_reward)
+-  [Function `match_computation_reward_to_target_reward`](#0x3_iota_system_state_inner_match_computation_reward_to_target_reward)
 -  [Function `epoch`](#0x3_iota_system_state_inner_epoch)
 -  [Function `protocol_version`](#0x3_iota_system_state_inner_protocol_version)
 -  [Function `system_state_version`](#0x3_iota_system_state_inner_system_state_version)
@@ -2155,10 +2155,11 @@ gas coins.
         storage_fund_reinvestment_amount as u64,
     );
 
-    let mut computation_reward = match_iota_supply_to_target_reward(
-      validator_target_reward,
-      computation_reward,
-      &mut self.iota_treasury_cap,
+    let mut computation_reward = match_computation_reward_to_target_reward(
+        validator_target_reward,
+        computation_reward,
+        &mut self.iota_treasury_cap,
+        ctx
     );
 
     self.epoch = self.epoch + 1;
@@ -2241,15 +2242,15 @@ gas coins.
 
 
 
-
+
 
-## Function `match_iota_supply_to_target_reward`
+## Function `match_computation_reward_to_target_reward`
 
 Mint or burn IOTA tokens depending on the given target reward per validator
 and the amount of computation fees burned in this epoch.
 
 
-
public(friend) fun match_iota_supply_to_target_reward(validator_target_reward: u64, computation_reward: balance::Balance<iota::IOTA>, iota_treasury_cap: &mut coin::TreasuryCap<iota::IOTA>): balance::Balance<iota::IOTA>
+
fun match_computation_reward_to_target_reward(validator_target_reward: u64, computation_reward: balance::Balance<iota::IOTA>, iota_treasury_cap: &mut iota::IotaTreasuryCap, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -2258,24 +2259,25 @@ and the amount of computation fees burned in this epoch. Implementation -
public(package) fun match_iota_supply_to_target_reward(
-  validator_target_reward: u64,
-  mut computation_reward: Balance<IOTA>,
-  iota_treasury_cap: &mut iota::coin::TreasuryCap<IOTA>
+
fun match_computation_reward_to_target_reward(
+    validator_target_reward: u64,
+    mut computation_reward: Balance<IOTA>,
+    iota_treasury_cap: &mut iota::iota::IotaTreasuryCap,
+    ctx: &TxContext,
 ): Balance<IOTA> {
-  if (computation_reward.value() < validator_target_reward) {
-    let tokens_to_mint = validator_target_reward - computation_reward.value();
-    let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint);
-    computation_reward.join(new_tokens);
-    computation_reward
-  } else if (computation_reward.value() > validator_target_reward) {
-    let tokens_to_burn = computation_reward.value() - validator_target_reward;
-    let rewards_to_burn = computation_reward.split(tokens_to_burn);
-    iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn);
-    computation_reward
-  } else {
-    computation_reward
-  }
+    if (computation_reward.value() < validator_target_reward) {
+        let tokens_to_mint = validator_target_reward - computation_reward.value();
+        let new_tokens = iota_treasury_cap.mint_balance(tokens_to_mint, ctx);
+        computation_reward.join(new_tokens);
+        computation_reward
+    } else if (computation_reward.value() > validator_target_reward) {
+        let tokens_to_burn = computation_reward.value() - validator_target_reward;
+        let rewards_to_burn = computation_reward.split(tokens_to_burn);
+        iota_treasury_cap.burn_balance(rewards_to_burn, ctx);
+        computation_reward
+    } else {
+        computation_reward
+    }
 }
 
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index ecf227d1fa7..9874b223539 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -976,7 +976,7 @@ module iota_system::iota_system_state_inner { /// Mint or burn IOTA tokens depending on the given target reward per validator /// and the amount of computation fees burned in this epoch. - public(package) fun match_computation_reward_to_target_reward( + fun match_computation_reward_to_target_reward( validator_target_reward: u64, mut computation_reward: Balance, iota_treasury_cap: &mut iota::iota::IotaTreasuryCap, From aab442f7842c40b43232ac8cebbf2ca402608bbf Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Fri, 5 Jul 2024 11:07:35 +0300 Subject: [PATCH 17/50] fix(iota-framework): typos --- .../packages/iota-system/sources/iota_system_state_inner.move | 3 +-- .../packages/iota-system/sources/validator_set.move | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 78499c10727..f566a148166 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -896,8 +896,7 @@ module iota_system::iota_system_state_inner { // Derive the reference gas price for the new epoch self.reference_gas_price = self.validators.derive_reference_gas_price(); // Because of precision issues with integer divisions, we expect that there will be some - // remaining balance in `storage_fund_reward` and `computation_reward`. - // All of these go to the storage fund. + // remaining balance in `computation_reward`. let leftover_staking_rewards = computation_reward; let leftover_storage_fund_inflow = leftover_staking_rewards.value(); diff --git a/crates/iota-framework/packages/iota-system/sources/validator_set.move b/crates/iota-framework/packages/iota-system/sources/validator_set.move index 9379eaabdee..4eb268359f4 100644 --- a/crates/iota-framework/packages/iota-system/sources/validator_set.move +++ b/crates/iota-framework/packages/iota-system/sources/validator_set.move @@ -958,7 +958,7 @@ module iota_system::validator_set { } } - /// Compute both the individual reward adjustments and total reward adjustment for staking rewards + /// Compute both the individual reward adjustments and total reward adjustment for staking rewards. fun compute_reward_adjustments( mut slashed_validator_indices: vector, reward_slashing_rate: u64, @@ -1109,7 +1109,7 @@ module iota_system::validator_set { } else { validator_reward.destroy_zero(); }; - + // Add rewards to stake staking pool to auto compound for stakers. validator.deposit_stake_rewards(staker_reward); i = i + 1; From 8a2c07ab32e711b50c9478a1ebf0f5f955dcd7bb Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Fri, 5 Jul 2024 11:12:18 +0300 Subject: [PATCH 18/50] fix(iota-framework): returned storage_fund_reinvestment into SystemEpochInfoEvent --- .../docs/iota-system/iota_system_state_inner.md | 10 ++++++++-- .../iota-framework/docs/iota-system/validator_set.md | 2 +- .../iota-system/sources/iota_system_state_inner.move | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 3be88ef72b6..1ed1255d9b2 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -560,6 +560,12 @@ the epoch advancement transaction.
+
+
+storage_fund_reinvestment: u64 +
+
+
storage_charge: u64 @@ -2153,8 +2159,7 @@ gas coins. // Derive the reference gas price for the new epoch self.reference_gas_price = self.validators.derive_reference_gas_price(); // Because of precision issues with integer divisions, we expect that there will be some - // remaining balance in `storage_fund_reward` and `computation_reward`. - // All of these go to the storage fund. + // remaining balance in `computation_reward`. let leftover_staking_rewards = computation_reward; let leftover_storage_fund_inflow = leftover_staking_rewards.value(); @@ -2176,6 +2181,7 @@ gas coins. reference_gas_price: self.reference_gas_price, total_stake: new_total_stake, storage_charge, + storage_fund_reinvestment: 0, storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), stake_subsidy_amount, diff --git a/crates/iota-framework/docs/iota-system/validator_set.md b/crates/iota-framework/docs/iota-system/validator_set.md index 00efabf245e..23073a338f0 100644 --- a/crates/iota-framework/docs/iota-system/validator_set.md +++ b/crates/iota-framework/docs/iota-system/validator_set.md @@ -2364,7 +2364,7 @@ Process the pending stake changes for each validator. ## Function `compute_reward_adjustments` -Compute both the individual reward adjustments and total reward adjustment for staking rewards +Compute both the individual reward adjustments and total reward adjustment for staking rewards.
fun compute_reward_adjustments(slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>): (u64, vec_map::VecMap<u64, u64>)
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index f566a148166..3a48b8e8a80 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -207,6 +207,7 @@ module iota_system::iota_system_state_inner {
         protocol_version: u64,
         reference_gas_price: u64,
         total_stake: u64,
+        storage_fund_reinvestment: u64,
         storage_charge: u64,
         storage_rebate: u64,
         storage_fund_balance: u64,
@@ -918,6 +919,7 @@ module iota_system::iota_system_state_inner {
                 reference_gas_price: self.reference_gas_price,
                 total_stake: new_total_stake,
                 storage_charge,
+                storage_fund_reinvestment: 0,
                 storage_rebate: storage_rebate_amount,
                 storage_fund_balance: self.storage_fund.total_balance(),
                 stake_subsidy_amount,

From 0a9847cfa1c82ed1611137c2b6f83433e3e029cf Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Fri, 5 Jul 2024 21:35:21 +0300
Subject: [PATCH 19/50] fix(iota-framework): fixed delegation and reward
 distribution tests

---
 .../iota-system/tests/delegation_tests.move   | 42 ++++++++++---------
 .../tests/rewards_distribution_tests.move     | 19 ++++-----
 .../tests/timelocked_delegation_tests.move    | 42 ++++++++++---------
 3 files changed, 53 insertions(+), 50 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move
index 5cd1118b95f..15ee319bdf1 100644
--- a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move
@@ -232,7 +232,7 @@ module iota_system::stake_tests {
         );
 
         if (should_distribute_rewards) {
-            // Each validator pool gets 30 MICROS and each validator gets an additional 10 MICROS.
+            // Each validator pool gets 40 IOTA.
             advance_epoch_with_reward_amounts(0, 80, scenario);
         } else {
             advance_epoch(scenario);
@@ -242,8 +242,7 @@ module iota_system::stake_tests {
 
         advance_epoch(scenario);
 
-        let reward_amt = if (should_distribute_rewards) 15 * MICROS_PER_IOTA else 0;
-        let validator_reward_amt = if (should_distribute_rewards) 10 * MICROS_PER_IOTA else 0;
+        let reward_amt = if (should_distribute_rewards) 20 * MICROS_PER_IOTA else 0;
 
         // Make sure stake withdrawal happens
         scenario.next_tx(STAKER_ADDR_1);
@@ -270,10 +269,9 @@ module iota_system::stake_tests {
         // Validator unstakes now.
         assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 0);
         unstake(VALIDATOR_ADDR_1, 0, scenario);
-        if (should_distribute_rewards) unstake(VALIDATOR_ADDR_1, 0, scenario);
 
         // Make sure have all of their stake. NB there is no epoch change. This is immediate.
-        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt + validator_reward_amt);
+        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt);
 
         scenario_val.end();
     }
@@ -294,10 +292,8 @@ module iota_system::stake_tests {
         // this epoch, they should get the rewards from this epoch.
         advance_epoch_with_reward_amounts(0, 80, scenario);
 
-        // Each validator pool gets 30 MICROS and validators shares the 20 MICROS from the storage fund
-        // so validator gets another 10 MICROS.
-        let reward_amt = 15 * MICROS_PER_IOTA;
-        let validator_reward_amt = 10 * MICROS_PER_IOTA;
+        // Each validator pool gets 40 IOTA.
+        let reward_amt = 20 * MICROS_PER_IOTA;
 
         // Make sure stake withdrawal happens
         scenario.next_tx(STAKER_ADDR_1);
@@ -322,10 +318,9 @@ module iota_system::stake_tests {
         // Validator unstakes now.
         assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 0);
         unstake(VALIDATOR_ADDR_1, 0, scenario);
-        unstake(VALIDATOR_ADDR_1, 0, scenario);
 
         // Make sure have all of their stake. NB there is no epoch change. This is immediate.
-        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt + validator_reward_amt);
+        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt);
 
         scenario_val.end();
     }
@@ -407,14 +402,19 @@ module iota_system::stake_tests {
         set_up_iota_system_state_with_storage_fund();
         let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1);
         let scenario = &mut scenario_val;
+        // At this point we got the following distribution of stake:
+        // V1: 100, V2: 100, storage fund: 100
 
         add_validator_candidate(NEW_VALIDATOR_ADDR, b"name3", b"/ip4/127.0.0.1/udp/83", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario);
 
         // Delegate 100 IOTA to the preactive validator
         stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario);
+        // At this point we got the following distribution of stake:
+        // V1: 100, V2: 100, V3: 100, storage fund: 100
+    
         advance_epoch_with_reward_amounts(0, 300, scenario);
         // At this point we got the following distribution of stake:
-        // V1: 250, V2: 250, storage fund: 100
+        // V1: 250, V2: 250, V3: 100, storage fund: 100
 
         stake_with(STAKER_ADDR_2, NEW_VALIDATOR_ADDR, 50, scenario);
         stake_with(STAKER_ADDR_3, NEW_VALIDATOR_ADDR, 100, scenario);
@@ -422,26 +422,28 @@ module iota_system::stake_tests {
         // Now the preactive becomes active
         add_validator(NEW_VALIDATOR_ADDR, scenario);
         advance_epoch(scenario);
-
         // At this point we got the following distribution of stake:
         // V1: 250, V2: 250, V3: 250, storage fund: 100
 
         advance_epoch_with_reward_amounts(0, 85, scenario);
+        // At this point we got the following distribution of stake:
+        // V1: 278_330_500_000, V2: 278_330_500_000, V3: 278_339_000_000, storage fund: 100
 
-        // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 IOTA each.
+        // staker 1 and 3 unstake from the validator and earns about 2/5 * 85 * 1/3 = 11.33 IOTA each.
         // Although they stake in different epochs, they earn the same rewards as long as they unstake
         // in the same epoch because the validator was preactive when they staked.
-        // So they will both get slightly more than 110 IOTA in total balance.
+        // So they will both get slightly more than 111 IOTA in total balance.
         unstake(STAKER_ADDR_1, 0, scenario);
-        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 110002000000);
+        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 111_335_600_000);
         unstake(STAKER_ADDR_3, 0, scenario);
-        assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 110002000000);
+        assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 111_335_600_000);
 
         advance_epoch_with_reward_amounts(0, 85, scenario);
         unstake(STAKER_ADDR_2, 0, scenario);
-        // staker 2 earns about 5 IOTA from the previous epoch and 24-ish from this one
-        // so in total she has about 50 + 5 + 24 = 79 IOTA.
-        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 78862939078);
+        // staker 2 earns about 1/5 * 85 * 1/3 = 5.66 IOTA from the previous epoch
+        // and 85 * 1/3 = 28.33 from this one
+        // so in total she has about 50 + 5.66 + 28.33 = 83.99 IOTA.
+        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 84_006_800_000);
 
         scenario_val.end();
     }
diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
index f05f30f2dd3..f8ac84ffe9d 100644
--- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
@@ -286,21 +286,20 @@ module iota_system::rewards_distribution_tests {
             1000, 1500, 2000, scenario
         );
 
-        // Each unslashed validator staking pool gets 300 IOTA of computation rewards + 75 IOTA of storage fund rewards +
-        // 20 IOTA (1/3) of validator 4's slashed computation reward and 5 IOTA (1/3) of validator 4's slashed
-        // storage fund reward, so in total it gets 400 IOTA of rewards.
-        // Validator 3 has a delegator with her so she gets 320 * 3/4 + 75 + 5 = 320 IOTA of rewards.
-        // Validator 4's should get 300 * 4/5 * (1 - 20%) = 192 in computation rewards and 75 * (1 - 20%) = 60 in storage rewards.
-        assert_validator_self_stake_amounts(validator_addrs(), vector[500 * MICROS_PER_IOTA, 600 * MICROS_PER_IOTA, 620 * MICROS_PER_IOTA, 652 * MICROS_PER_IOTA], scenario);
+        // Each unslashed validator staking pool gets 375 IOTA of computation rewards + 25 IOTA (1/3) of validator 4's slashed computation reward,
+        // so in total it gets 400 IOTA of rewards.
+        // Validator 3's should get (375 + 25) * 3/4 = 300 in computation rewards.
+        // Validator 4's should get (375 - 75) * 4/5 = 240 in computation rewards.
+        assert_validator_self_stake_amounts(validator_addrs(), vector[500 * MICROS_PER_IOTA, 600 * MICROS_PER_IOTA, 600 * MICROS_PER_IOTA, 640 * MICROS_PER_IOTA], scenario);
 
         // Unstake so we can check the stake rewards as well.
         unstake(STAKER_ADDR_1, 0, scenario);
         unstake(STAKER_ADDR_2, 0, scenario);
 
-        // Staker 1 gets 320 * 1/4 = 80 IOTA of rewards.
-        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), (100 + 80) * MICROS_PER_IOTA);
-        // Staker 2 gets 300 * 1/5 * (1 - 20%) = 48 IOTA of rewards.
-        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), (100 + 48) * MICROS_PER_IOTA);
+        // Staker 1 gets (375 + 25) * 1/4 = 100 IOTA of rewards.
+        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), (100 + 100) * MICROS_PER_IOTA);
+        // Staker 2 gets (375 - 75) * 1/5 = 60 IOTA of rewards.
+        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), (100 + 60) * MICROS_PER_IOTA);
 
         scenario_val.end();
     }
diff --git a/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move b/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move
index 9fc4ccdfed5..9b7c7630da1 100644
--- a/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move
+++ b/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move
@@ -603,15 +603,14 @@ module timelock::timelocked_stake_tests {
             scenario
         );
 
-        // Each validator pool gets 30 MICROS and each validator gets an additional 10 MICROS.
+        // Each validator pool gets 40 IOTA.
         advance_epoch_with_reward_amounts(0, 80, scenario);
 
         remove_validator(VALIDATOR_ADDR_1, scenario);
 
         advance_epoch(scenario);
 
-        let reward_amt = 15 * MICROS_PER_IOTA;
-        let validator_reward_amt = 10 * MICROS_PER_IOTA;
+        let reward_amt = 20 * MICROS_PER_IOTA;
 
         // Make sure stake withdrawal happens
         scenario.next_tx(STAKER_ADDR_1);
@@ -639,10 +638,9 @@ module timelock::timelocked_stake_tests {
         // Validator unstakes now.
         assert!(!has_iota_coins(VALIDATOR_ADDR_1, scenario), 2);
         unstake(VALIDATOR_ADDR_1, 0, scenario);
-        unstake(VALIDATOR_ADDR_1, 0, scenario);
 
         // Make sure have all of their stake. NB there is no epoch change. This is immediate.
-        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt + validator_reward_amt);
+        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt);
 
         scenario_val.end();
     }
@@ -663,10 +661,8 @@ module timelock::timelocked_stake_tests {
         // this epoch, they should get the rewards from this epoch.
         advance_epoch_with_reward_amounts(0, 80, scenario);
 
-        // Each validator pool gets 30 MICROS and validators shares the 20 MICROS from the storage fund
-        // so validator gets another 10 MICROS.
-        let reward_amt = 15 * MICROS_PER_IOTA;
-        let validator_reward_amt = 10 * MICROS_PER_IOTA;
+        // Each validator pool gets 40 IOTA.
+        let reward_amt = 20 * MICROS_PER_IOTA;
 
         // Make sure stake withdrawal happens
         scenario.next_tx(STAKER_ADDR_1);
@@ -693,10 +689,9 @@ module timelock::timelocked_stake_tests {
         // Validator unstakes now.
         assert!(!has_iota_coins(VALIDATOR_ADDR_1, scenario), 2);
         unstake(VALIDATOR_ADDR_1, 0, scenario);
-        unstake(VALIDATOR_ADDR_1, 0, scenario);
 
         // Make sure have all of their stake. NB there is no epoch change. This is immediate.
-        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt + validator_reward_amt);
+        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), 100 * MICROS_PER_IOTA + reward_amt);
 
         scenario_val.end();
     }
@@ -779,14 +774,19 @@ module timelock::timelocked_stake_tests {
         set_up_iota_system_state_with_storage_fund();
         let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1);
         let scenario = &mut scenario_val;
+        // At this point we got the following distribution of stake:
+        // V1: 100, V2: 100, storage fund: 100
 
         add_validator_candidate(NEW_VALIDATOR_ADDR, b"name3", b"/ip4/127.0.0.1/udp/83", NEW_VALIDATOR_PUBKEY, NEW_VALIDATOR_POP, scenario);
 
         // Delegate 100 IOTA to the preactive validator
         stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, scenario);
+        // At this point we got the following distribution of stake:
+        // V1: 100, V2: 100, V3: 100, storage fund: 100
+
         advance_epoch_with_reward_amounts(0, 300, scenario);
         // At this point we got the following distribution of stake:
-        // V1: 250, V2: 250, storage fund: 100
+        // V1: 250, V2: 250, V3: 100, storage fund: 100
 
         stake_timelocked_with(STAKER_ADDR_2, NEW_VALIDATOR_ADDR, 50, 10, scenario);
         stake_timelocked_with(STAKER_ADDR_3, NEW_VALIDATOR_ADDR, 100, 10, scenario);
@@ -794,31 +794,33 @@ module timelock::timelocked_stake_tests {
         // Now the preactive becomes active
         add_validator(NEW_VALIDATOR_ADDR, scenario);
         advance_epoch(scenario);
-
         // At this point we got the following distribution of stake:
         // V1: 250, V2: 250, V3: 250, storage fund: 100
 
         advance_epoch_with_reward_amounts(0, 85, scenario);
+        // At this point we got the following distribution of stake:
+        // V1: 278_330_500_000, V2: 278_330_500_000, V3: 278_339_000_000, storage fund: 100
 
-        // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 IOTA each.
+        // staker 1 and 3 unstake from the validator and earns about 2/5 * 85 * 1/3 = 11.33 IOTA each.
         // Although they stake in different epochs, they earn the same rewards as long as they unstake
         // in the same epoch because the validator was preactive when they staked.
-        // So they will both get slightly more than 110 IOTA in total balance.
+        // So they will both get slightly more than 111 IOTA in total balance.
         unstake_timelocked(STAKER_ADDR_1, 0, scenario);
         assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA);
-        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 10_002_000_000);
+        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 11_335_600_000);
 
         unstake_timelocked(STAKER_ADDR_3, 0, scenario);
         assert_eq(total_timelocked_iota_balance(STAKER_ADDR_3, scenario), 100 * MICROS_PER_IOTA);
-        assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 10_002_000_000);
+        assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 11_335_600_000);
 
         advance_epoch_with_reward_amounts(0, 85, scenario);
 
         unstake_timelocked(STAKER_ADDR_2, 0, scenario);
-        // staker 2 earns about 5 IOTA from the previous epoch and 24-ish from this one
-        // so in total she has about 50 + 5 + 24 = 79 IOTA.
+        // staker 2 earns about 1/5 * 85 * 1/3 = 5.66 IOTA from the previous epoch
+        // and 85 * 1/3 = 28.33 from this one
+        // so in total she has about 50 + 5.66 + 28.33 = 83.99 IOTA.
         assert_eq(total_timelocked_iota_balance(STAKER_ADDR_2, scenario), 50 * MICROS_PER_IOTA);
-        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 28_862_939_078);
+        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 34_006_800_000);
 
         scenario_val.end();
     }

From ac97a4ab3aa65f2c04124711f34a4b76270d2ea2 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Tue, 9 Jul 2024 11:33:09 +0200
Subject: [PATCH 20/50] feat: Add validator commission with staking test

---
 .../tests/rewards_distribution_tests.move     | 45 ++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
index 294430f11ad..f05ae2739d4 100644
--- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
@@ -63,6 +63,7 @@ module iota_system::rewards_distribution_tests {
             vector[150 * MICROS_PER_IOTA, 970 * MICROS_PER_IOTA, 350 * MICROS_PER_IOTA, 450 * MICROS_PER_IOTA],
             scenario
         );
+
         scenario_val.end();
     }
 
@@ -219,7 +220,7 @@ module iota_system::rewards_distribution_tests {
         advance_epoch(scenario);
         // V1: 200, V2: 300, V3: 300, V4: 400
 
-        set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_2, 2000, scenario); // 50% commission
+        set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_2, 2000, scenario); // 20% commission
         advance_epoch_with_reward_amounts(0, 120, scenario);
         // V1: 230, V2: 330, V3: 330, V4: 430
         // 2 IOTA, or 20 % of staker_2's rewards, goes to validator_2
@@ -242,6 +243,48 @@ module iota_system::rewards_distribution_tests {
         scenario_val.end();
     }
 
+    #[test]
+    fun test_validator_commission_with_staking() {
+        set_up_iota_system_state();
+        let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1);
+        let scenario = &mut scenario_val;
+
+        stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario);
+        advance_epoch(scenario);
+        // V1: 200, V2: 200, V3: 300, V4: 400
+
+        // Validator 1: 10% commission.
+        set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_1, 1000, scenario);
+
+        advance_epoch_with_reward_amounts(0, 800, scenario);
+
+        // Each validator pool gets 25% of the voting power and thus gets 25% of the reward (200 IOTA).
+        assert_validator_total_stake_amounts(
+          validator_addrs(),
+          vector[
+            (200 + 200) * MICROS_PER_IOTA,
+            (200 + 200) * MICROS_PER_IOTA,
+            (300 + 200) * MICROS_PER_IOTA,
+            (400 + 200) * MICROS_PER_IOTA,
+          ],
+          scenario
+        );
+
+        // Unstakes the initially created StakedIota of value 100 IOTA.
+        unstake(VALIDATOR_ADDR_1, 0, scenario);
+        // The validator should have received a 10% commission on the reward of 200 IOTA (= 20 IOTA)
+        // in the form of a StakedIota.
+        unstake(VALIDATOR_ADDR_1, 0, scenario);
+        unstake(STAKER_ADDR_1, 0, scenario);
+
+        // The remaining 200 - 20 = 180 should be distributed equally between validator
+        // and staker since both have equivalent stake.
+        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), (100+90+20) * MICROS_PER_IOTA);
+        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), (100+90) * MICROS_PER_IOTA);
+
+        scenario_val.end();
+    }
+
     #[test]
     fun test_rewards_slashing() {
         set_up_iota_system_state();

From 133465a27103a204fd078b53884dd8a1b51f8efc Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Tue, 9 Jul 2024 13:24:35 +0200
Subject: [PATCH 21/50] feat: Add rewards test with minting & burning

---
 .../tests/rewards_distribution_tests.move     | 64 +++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
index f05ae2739d4..07ae4e378e1 100644
--- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
@@ -145,6 +145,70 @@ module iota_system::rewards_distribution_tests {
         scenario_val.end();
     }
 
+    #[test]
+    fun test_validator_target_reward_higher_than_computation_reward() {
+        set_up_iota_system_state();
+        let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1);
+        let scenario = &mut scenario_val;
+
+        advance_epoch(scenario);
+        // V1: 100, V2: 200, V3: 300, V4: 400
+
+        advance_epoch_with_target_reward_amounts(800, 0, 400, scenario);
+
+        // The computation reward is lower than the target reward, but an additional 400 IOTA should be minted.
+        // Each validator pool gets 25% of the voting power and thus gets 25% of the reward (200 IOTA).
+        assert_validator_total_stake_amounts(
+          validator_addrs(),
+          vector[
+            (100 + 200) * MICROS_PER_IOTA,
+            (200 + 200) * MICROS_PER_IOTA,
+            (300 + 200) * MICROS_PER_IOTA,
+            (400 + 200) * MICROS_PER_IOTA,
+          ],
+          scenario
+        );
+
+        unstake(VALIDATOR_ADDR_1, 0, scenario);
+
+        // Validator should get the entire reward of 200 plus its initially staked 100 IOTA.
+        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), (100+200) * MICROS_PER_IOTA);
+
+        scenario_val.end();
+    }
+
+    #[test]
+    fun test_validator_target_reward_lower_than_computation_reward() {
+        set_up_iota_system_state();
+        let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1);
+        let scenario = &mut scenario_val;
+
+        advance_epoch(scenario);
+        // V1: 100, V2: 200, V3: 300, V4: 400
+
+        advance_epoch_with_target_reward_amounts(800, 0, 1000, scenario);
+
+        // The computation reward is higher than the target reward, so 200 IOTA should be burned.
+        // Each validator pool gets 25% of the voting power and thus gets 25% of the reward (200 IOTA).
+        assert_validator_total_stake_amounts(
+          validator_addrs(),
+          vector[
+            (100 + 200) * MICROS_PER_IOTA,
+            (200 + 200) * MICROS_PER_IOTA,
+            (300 + 200) * MICROS_PER_IOTA,
+            (400 + 200) * MICROS_PER_IOTA,
+          ],
+          scenario
+        );
+
+        unstake(VALIDATOR_ADDR_1, 0, scenario);
+
+        // Validator should get the entire reward of 200 plus its initially staked 100 IOTA.
+        assert_eq(total_iota_balance(VALIDATOR_ADDR_1, scenario), (100+200) * MICROS_PER_IOTA);
+
+        scenario_val.end();
+    }
+
     #[test]
     fun test_stake_rewards() {
         set_up_iota_system_state();

From c8ec1cf05d10f1b882b5a5f008acccdefb2b1aff Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Tue, 9 Jul 2024 15:00:14 +0200
Subject: [PATCH 22/50] feat: Add timelocked minting & burning tests

---
 .../tests/timelocked_delegation_tests.move    | 84 ++++++++++++++++++-
 1 file changed, 83 insertions(+), 1 deletion(-)

diff --git a/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move b/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move
index 9b7c7630da1..99fe1e89fdf 100644
--- a/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move
+++ b/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move
@@ -21,6 +21,7 @@ module timelock::timelocked_stake_tests {
         add_validator_candidate,
         advance_epoch,
         advance_epoch_with_reward_amounts,
+        advance_epoch_with_target_reward_amounts,
         assert_validator_total_stake_amounts,
         create_validator_for_testing,
         create_iota_system_state_for_testing,
@@ -909,6 +910,83 @@ module timelock::timelocked_stake_tests {
         scenario_val.end();
     }
 
+    #[test]
+    fun test_timelock_validator_target_reward_higher_than_computation_reward() {
+        set_up_iota_system_state();
+        let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1);
+        let scenario = &mut scenario_val;
+
+        stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 60, scenario);
+        stake_timelocked_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 100, 60, scenario);
+        advance_epoch(scenario);
+        // V1: 200, V2: 200
+
+        advance_epoch_with_target_reward_amounts(800, 0, 400, scenario);
+
+        // The computation reward is lower than the target reward, so 400 IOTA should be minted.
+        // Each validator pool has 50% of the voting power and thus gets 50% of the reward (400 IOTA).
+        assert_validator_total_stake_amounts(
+          validator_addrs(),
+          vector[
+            (200 + 400) * MICROS_PER_IOTA,
+            (200 + 400) * MICROS_PER_IOTA,
+          ],
+          scenario
+        );
+
+        unstake_timelocked(STAKER_ADDR_1, 0, scenario);
+        unstake_timelocked(STAKER_ADDR_2, 0, scenario);
+
+        // Both stakers should get half the reward (= 200).
+        // Both should still have their original timelocked 100 IOTA that they staked.
+        assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA);
+        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 200 * MICROS_PER_IOTA);
+
+        assert_eq(total_timelocked_iota_balance(STAKER_ADDR_2, scenario), 100 * MICROS_PER_IOTA);
+        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 200 * MICROS_PER_IOTA);
+
+        scenario_val.end();
+    }
+
+    #[test]
+    fun test_timelock_validator_target_reward_lower_than_computation_reward() {
+        set_up_iota_system_state();
+        let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1);
+        let scenario = &mut scenario_val;
+
+        stake_timelocked_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, 60, scenario);
+        stake_timelocked_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 150, 60, scenario);
+        advance_epoch(scenario);
+        // V1: 200, V2: 250
+
+        advance_epoch_with_target_reward_amounts(800, 0, 1000, scenario);
+
+        // The computation reward is higher than the target reward, so 200 IOTA should be burned.
+        // Each validator pool has 50% of the voting power and thus gets 50% of the reward (400 IOTA).
+        assert_validator_total_stake_amounts(
+          validator_addrs(),
+          vector[
+            (200 + 400) * MICROS_PER_IOTA,
+            (250 + 400) * MICROS_PER_IOTA,
+          ],
+          scenario
+        );
+
+        unstake_timelocked(STAKER_ADDR_1, 0, scenario);
+        unstake_timelocked(STAKER_ADDR_2, 0, scenario);
+
+        // Both stakers should have their original timelocked IOTA that they staked.
+        // Staker 1 should get half the reward (= 200) of its staking pool.
+        assert_eq(total_timelocked_iota_balance(STAKER_ADDR_1, scenario), 100 * MICROS_PER_IOTA);
+        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 200 * MICROS_PER_IOTA);
+
+        // Staker 1 should get 150 / 250 * 400 of the reward (= 240) of its staking pool.
+        assert_eq(total_timelocked_iota_balance(STAKER_ADDR_2, scenario), 150 * MICROS_PER_IOTA);
+        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 240 * MICROS_PER_IOTA);
+
+        scenario_val.end();
+    }
+
     fun assert_exchange_rate_eq(
         rates: &Table, epoch: u64, iota_amount: u64, pool_token_amount: u64
     ) {
@@ -917,6 +995,10 @@ module timelock::timelocked_stake_tests {
         assert_eq(rate.pool_token_amount(), pool_token_amount * MICROS_PER_IOTA);
     }
 
+    fun validator_addrs() : vector
{ + vector[VALIDATOR_ADDR_1, VALIDATOR_ADDR_2] + } + fun set_up_iota_system_state() { let mut scenario_val = test_scenario::begin(@0x0); let scenario = &mut scenario_val; @@ -926,7 +1008,7 @@ module timelock::timelocked_stake_tests { create_validator_for_testing(VALIDATOR_ADDR_1, 100, ctx), create_validator_for_testing(VALIDATOR_ADDR_2, 100, ctx) ]; - create_iota_system_state_for_testing(validators, 0, 0, ctx); + create_iota_system_state_for_testing(validators, 500, 0, ctx); scenario_val.end(); } From 3cc14b717cdd5a4e4dbeba97833e547e83c0209a Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 9 Jul 2024 15:00:43 +0200 Subject: [PATCH 23/50] fix: description of minting & burning tests --- .../iota-system/tests/rewards_distribution_tests.move | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move index 07ae4e378e1..8270d5284a1 100644 --- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -156,8 +156,8 @@ module iota_system::rewards_distribution_tests { advance_epoch_with_target_reward_amounts(800, 0, 400, scenario); - // The computation reward is lower than the target reward, but an additional 400 IOTA should be minted. - // Each validator pool gets 25% of the voting power and thus gets 25% of the reward (200 IOTA). + // The computation reward is lower than the target reward, so 400 IOTA should be minted. + // Each validator pool has 25% of the voting power and thus gets 25% of the reward (200 IOTA). assert_validator_total_stake_amounts( validator_addrs(), vector[ @@ -189,7 +189,7 @@ module iota_system::rewards_distribution_tests { advance_epoch_with_target_reward_amounts(800, 0, 1000, scenario); // The computation reward is higher than the target reward, so 200 IOTA should be burned. - // Each validator pool gets 25% of the voting power and thus gets 25% of the reward (200 IOTA). + // Each validator pool has 25% of the voting power and thus gets 25% of the reward (200 IOTA). assert_validator_total_stake_amounts( validator_addrs(), vector[ From 92285cebe4efb8dbaffbe78d3743bd1dfd1931da Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 10 Jul 2024 08:34:54 +0200 Subject: [PATCH 24/50] fix: indentation --- .../tests/rewards_distribution_tests.move | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move index 8270d5284a1..88401ba0012 100644 --- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -159,14 +159,14 @@ module iota_system::rewards_distribution_tests { // The computation reward is lower than the target reward, so 400 IOTA should be minted. // Each validator pool has 25% of the voting power and thus gets 25% of the reward (200 IOTA). assert_validator_total_stake_amounts( - validator_addrs(), - vector[ - (100 + 200) * MICROS_PER_IOTA, - (200 + 200) * MICROS_PER_IOTA, - (300 + 200) * MICROS_PER_IOTA, - (400 + 200) * MICROS_PER_IOTA, - ], - scenario + validator_addrs(), + vector[ + (100 + 200) * MICROS_PER_IOTA, + (200 + 200) * MICROS_PER_IOTA, + (300 + 200) * MICROS_PER_IOTA, + (400 + 200) * MICROS_PER_IOTA, + ], + scenario ); unstake(VALIDATOR_ADDR_1, 0, scenario); @@ -191,14 +191,14 @@ module iota_system::rewards_distribution_tests { // The computation reward is higher than the target reward, so 200 IOTA should be burned. // Each validator pool has 25% of the voting power and thus gets 25% of the reward (200 IOTA). assert_validator_total_stake_amounts( - validator_addrs(), - vector[ - (100 + 200) * MICROS_PER_IOTA, - (200 + 200) * MICROS_PER_IOTA, - (300 + 200) * MICROS_PER_IOTA, - (400 + 200) * MICROS_PER_IOTA, - ], - scenario + validator_addrs(), + vector[ + (100 + 200) * MICROS_PER_IOTA, + (200 + 200) * MICROS_PER_IOTA, + (300 + 200) * MICROS_PER_IOTA, + (400 + 200) * MICROS_PER_IOTA, + ], + scenario ); unstake(VALIDATOR_ADDR_1, 0, scenario); @@ -324,14 +324,14 @@ module iota_system::rewards_distribution_tests { // Each validator pool gets 25% of the voting power and thus gets 25% of the reward (200 IOTA). assert_validator_total_stake_amounts( - validator_addrs(), - vector[ - (200 + 200) * MICROS_PER_IOTA, - (200 + 200) * MICROS_PER_IOTA, - (300 + 200) * MICROS_PER_IOTA, - (400 + 200) * MICROS_PER_IOTA, - ], - scenario + validator_addrs(), + vector[ + (200 + 200) * MICROS_PER_IOTA, + (200 + 200) * MICROS_PER_IOTA, + (300 + 200) * MICROS_PER_IOTA, + (400 + 200) * MICROS_PER_IOTA, + ], + scenario ); // Unstakes the initially created StakedIota of value 100 IOTA. From 7c3614fa049df59f0f6feda8271874805d5f56e2 Mon Sep 17 00:00:00 2001 From: Pavlo Botnar Date: Wed, 10 Jul 2024 11:31:23 +0300 Subject: [PATCH 25/50] fix(iota-framework/tests): add tests checking leftovers burning (#1098) * fix(iota-framework/tests): add tests checking leftovers burning --- .../tests/rewards_distribution_tests.move | 90 ++++++++++++++++--- 1 file changed, 77 insertions(+), 13 deletions(-) diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move index 294430f11ad..e5d1e79a4f7 100644 --- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -10,6 +10,7 @@ module iota_system::rewards_distribution_tests { use iota_system::governance_test_utils::{ advance_epoch, advance_epoch_with_reward_amounts, + advance_epoch_with_reward_amounts_return_rebate, advance_epoch_with_reward_amounts_and_slashing_rates, advance_epoch_with_target_reward_amounts, assert_validator_total_stake_amounts, @@ -21,7 +22,7 @@ module iota_system::rewards_distribution_tests { total_iota_balance, total_supply, unstake }; - use iota::test_utils::assert_eq; + use iota::test_utils::{assert_eq, destroy}; use iota::address; const VALIDATOR_ADDR_1: address = @0x1; @@ -378,18 +379,7 @@ module iota_system::rewards_distribution_tests { let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); let scenario = &mut scenario_val; - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_4, scenario); - report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_4, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_4, scenario); - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_3, scenario); - report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_3, scenario); - report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_3, scenario); - report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_2, scenario); - report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_1, scenario); - report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_1, scenario); - report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_1, scenario); + slash_all_validators(scenario); advance_epoch_with_reward_amounts_and_slashing_rates( 1000, 500, 10_000, scenario @@ -506,6 +496,65 @@ module iota_system::rewards_distribution_tests { scenario_val.end(); } + #[test] + fun test_slashed_validators_leftover_burning() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + // To get the leftover, we have to slash every validator. This way, the computation reward will remain as leftover. + slash_all_validators(scenario); + + // Pass 700 IOTA as computation reward(for an instance). + advance_epoch_with_reward_amounts_and_slashing_rates( + 1000, 700, 10_000, scenario + ); + + scenario.next_tx(@0x0); + // The total supply of 1000 IOTA should be reduced by 700 IOTA because the 700 IOTA becomes leftover and should be burned. + assert_eq(total_supply(scenario), 300 * MICROS_PER_IOTA); + + scenario_val.end(); + } + + #[test] + #[expected_failure(abort_code = iota::balance::EOverflow)] + fun test_leftover_is_larger_than_supply() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + // To get the leftover, we have to slash every validator. This way, the computation reward will remain as leftover. + slash_all_validators(scenario); + + // Pass 1700 IOTA as computation reward which is larger than the total supply of 1000 IOTA. + advance_epoch_with_reward_amounts_and_slashing_rates( + 1000, 1700, 10_000, scenario + ); + + scenario_val.end(); + } + + #[test] + fun test_leftover_burning_after_reward_distribution() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + + // The leftover comes from the unequal distribution of rewards to validators. + // As example 1_000_000_000_1 cannot be splitted into equal parts, so it cause leftover. + let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(1_000_000_000_1, 1_000_000_000_000, 1_000_000_000_1, 0, 0, scenario); + destroy(storage_rebate); + + scenario.next_tx(@0x0); + + // Total supply after leftover has burned. + // The 999,999,999,999 is obtained by subtracting the leftover from the total supply: 1,000,000,000,000 - 1 = 999,999,999,999. + assert_eq(total_supply(scenario), 999_999_999_999); + + scenario_val.end(); + } + fun set_up_iota_system_state() { let mut scenario_val = test_scenario::begin(@0x0); let scenario = &mut scenario_val; @@ -557,4 +606,19 @@ module iota_system::rewards_distribution_tests { scenario.return_to_sender(cap); test_scenario::return_shared(system_state); } + + fun slash_all_validators(scenario: &mut Scenario) { + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_4, scenario); + report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_4, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_4, scenario); + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_3, scenario); + report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_3, scenario); + report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_3, scenario); + report_validator(VALIDATOR_ADDR_1, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_2, scenario); + report_validator(VALIDATOR_ADDR_2, VALIDATOR_ADDR_1, scenario); + report_validator(VALIDATOR_ADDR_3, VALIDATOR_ADDR_1, scenario); + report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_1, scenario); + } } From 636ba680b510b8b6a9614258d42e538d432cc417 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 10 Jul 2024 11:19:00 +0200 Subject: [PATCH 26/50] fix: Add comment on disabled stake subsidy fund --- .../iota-framework/docs/iota-system/iota_system_state_inner.md | 3 ++- .../packages/iota-system/sources/iota_system_state_inner.move | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 10424f406c3..b8e9019b2fa 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -2131,10 +2131,11 @@ gas coins. balance::zero() }; + // The stake subsidy fund is disabled through parameter choices in GenesisCeremonyParameters, + // so it is always a zero balance now. It will be fully removed in a later step. let stake_subsidy_amount = stake_subsidy.value(); computation_reward.join(stake_subsidy); - let mut computation_reward = match_computation_reward_to_target_reward( validator_target_reward, computation_reward, diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index ac848593f66..455581e391c 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -868,10 +868,11 @@ module iota_system::iota_system_state_inner { balance::zero() }; + // The stake subsidy fund is disabled through parameter choices in GenesisCeremonyParameters, + // so it is always a zero balance now. It will be fully removed in a later step. let stake_subsidy_amount = stake_subsidy.value(); computation_reward.join(stake_subsidy); - let mut computation_reward = match_computation_reward_to_target_reward( validator_target_reward, computation_reward, From 7b303ec2db2cd982c4606f31742439bc28f2a2e4 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 10 Jul 2024 11:25:39 +0200 Subject: [PATCH 27/50] feat: Make `get_total_iota_supply` fun public --- .../docs/iota-system/iota_system.md | 27 +++++++++++++++++++ .../iota-system/iota_system_state_inner.md | 26 ++++++++++++++++++ .../iota-system/sources/iota_system.move | 3 +-- .../sources/iota_system_state_inner.move | 1 - .../tests/governance_test_utils.move | 2 +- 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md index a9c9298c430..b17934d66b0 100644 --- a/crates/iota-framework/docs/iota-system/iota_system.md +++ b/crates/iota-framework/docs/iota-system/iota_system.md @@ -83,6 +83,7 @@ the IotaSystemStateInner version, or vice versa. - [Function `load_system_state`](#0x3_iota_system_load_system_state) - [Function `load_system_state_mut`](#0x3_iota_system_load_system_state_mut) - [Function `load_inner_maybe_upgrade`](#0x3_iota_system_load_inner_maybe_upgrade) +- [Function `get_total_iota_supply`](#0x3_iota_system_get_total_iota_supply)
use 0x1::option;
@@ -1490,4 +1491,30 @@ gas coins.
 
 
 
+
+
+
+
+## Function `get_total_iota_supply`
+
+Returns the total iota supply.
+
+
+
public fun get_total_iota_supply(wrapper: &mut iota_system::IotaSystemState): u64
+
+ + + +
+Implementation + + +
public fun get_total_iota_supply(wrapper: &mut IotaSystemState): u64 {
+    let self = load_system_state(wrapper);
+    self.get_total_iota_supply()
+}
+
+ + +
diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index b8e9019b2fa..41f69669ec8 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -57,6 +57,7 @@ title: Module `0x3::iota_system_state_inner` - [Function `validator_stake_amount`](#0x3_iota_system_state_inner_validator_stake_amount) - [Function `validator_staking_pool_id`](#0x3_iota_system_state_inner_validator_staking_pool_id) - [Function `validator_staking_pool_mappings`](#0x3_iota_system_state_inner_validator_staking_pool_mappings) +- [Function `get_total_iota_supply`](#0x3_iota_system_state_inner_get_total_iota_supply) - [Function `get_reporters_of`](#0x3_iota_system_state_inner_get_reporters_of) - [Function `get_storage_fund_total_balance`](#0x3_iota_system_state_inner_get_storage_fund_total_balance) - [Function `get_storage_fund_object_rebates`](#0x3_iota_system_state_inner_get_storage_fund_object_rebates) @@ -2461,6 +2462,31 @@ Returns reference to the staking pool mappings that map pool ids to active valid + + + + +## Function `get_total_iota_supply` + +Returns the total iota supply. + + +
public(friend) fun get_total_iota_supply(self: &iota_system_state_inner::IotaSystemStateInnerV2): u64
+
+ + + +
+Implementation + + +
public(package) fun get_total_iota_supply(self: &IotaSystemStateInnerV2): u64 {
+    self.iota_treasury_cap.total_supply()
+}
+
+ + +
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move index 07fc5916f06..4c9a6f2885b 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move @@ -697,9 +697,8 @@ module iota_system::iota_system { self.get_stake_subsidy_distribution_counter() } - #[test_only] /// Returns the total iota supply. - public fun get_iota_supply(wrapper: &mut IotaSystemState): u64 { + public fun get_total_iota_supply(wrapper: &mut IotaSystemState): u64 { let self = load_system_state(wrapper); self.get_total_iota_supply() } diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 455581e391c..b40be4f1b63 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -1015,7 +1015,6 @@ module iota_system::iota_system_state_inner { self.validators.staking_pool_mappings() } - #[test_only] /// Returns the total iota supply. public(package) fun get_total_iota_supply(self: &IotaSystemStateInnerV2): u64 { self.iota_treasury_cap.total_supply() diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move index 616ed81edf1..f6685e3e0b6 100644 --- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move +++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move @@ -366,7 +366,7 @@ module iota_system::governance_test_utils { /// Returns the total IOTA supply in the system state. public fun total_supply(scenario: &mut Scenario): u64 { let mut system_state = scenario.take_shared(); - let total_supply = system_state.get_iota_supply(); + let total_supply = system_state.get_total_iota_supply(); test_scenario::return_shared(system_state); total_supply } From 83bc0535fedd232c136d8f389ea29cd03d2e667b Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 10 Jul 2024 11:36:18 +0200 Subject: [PATCH 28/50] refactor: Rename computation reward to validator rewards --- .../docs/iota-system/iota_system_state_inner.md | 16 ++++++++-------- .../docs/iota-system/validator_set.md | 8 ++++---- .../sources/iota_system_state_inner.move | 16 ++++++++-------- .../iota-system/sources/validator_set.move | 6 +++--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 41f69669ec8..272515d6d02 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -2137,7 +2137,7 @@ gas coins. let stake_subsidy_amount = stake_subsidy.value(); computation_reward.join(stake_subsidy); - let mut computation_reward = match_computation_reward_to_target_reward( + let mut total_validator_rewards = match_computation_reward_to_target_reward( validator_target_reward, computation_reward, &mut self.iota_treasury_cap, @@ -2148,10 +2148,10 @@ gas coins. // Sanity check to make sure we are advancing to the right epoch. assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch); - let computation_reward_amount_before_distribution = computation_reward.value(); + let total_validator_rewards_amount_before_distribution = total_validator_rewards.value(); self.validators.advance_epoch( - &mut computation_reward, + &mut total_validator_rewards, &mut self.validator_report_records, reward_slashing_rate, self.parameters.validator_low_stake_threshold, @@ -2162,16 +2162,16 @@ gas coins. let new_total_stake = self.validators.total_stake(); - let computation_reward_amount_after_distribution = computation_reward.value(); - let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; + let total_validator_rewards_amount_after_distribution = total_validator_rewards.value(); + let total_validator_rewards_distributed = total_validator_rewards_amount_before_distribution - total_validator_rewards_amount_after_distribution; self.protocol_version = next_protocol_version; // Derive the reference gas price for the new epoch self.reference_gas_price = self.validators.derive_reference_gas_price(); // Because of precision issues with integer divisions, we expect that there will be some - // remaining balance in `computation_reward`. - let leftover_staking_rewards = computation_reward; + // remaining balance in `total_validator_rewards`. + let leftover_staking_rewards = total_validator_rewards; let leftover_storage_fund_inflow = leftover_staking_rewards.value(); // Burning leftover rewards @@ -2197,7 +2197,7 @@ gas coins. storage_fund_balance: self.storage_fund.total_balance(), stake_subsidy_amount, total_gas_fees: computation_charge, - total_stake_rewards_distributed: computation_reward_distributed, + total_stake_rewards_distributed: total_validator_rewards_distributed, leftover_storage_fund_inflow, } ); diff --git a/crates/iota-framework/docs/iota-system/validator_set.md b/crates/iota-framework/docs/iota-system/validator_set.md index 23073a338f0..f2016ad9fdd 100644 --- a/crates/iota-framework/docs/iota-system/validator_set.md +++ b/crates/iota-framework/docs/iota-system/validator_set.md @@ -980,7 +980,7 @@ It does the following things: 5. At the end, we calculate the total stake for the new epoch. -
public(friend) fun advance_epoch(self: &mut validator_set::ValidatorSet, computation_reward: &mut balance::Balance<iota::IOTA>, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, reward_slashing_rate: u64, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, ctx: &mut tx_context::TxContext)
+
public(friend) fun advance_epoch(self: &mut validator_set::ValidatorSet, total_validator_rewards: &mut balance::Balance<iota::IOTA>, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, reward_slashing_rate: u64, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, ctx: &mut tx_context::TxContext)
 
@@ -991,7 +991,7 @@ It does the following things:
public(package) fun advance_epoch(
     self: &mut ValidatorSet,
-    computation_reward: &mut Balance<IOTA>,
+    total_validator_rewards: &mut Balance<IOTA>,
     validator_report_records: &mut VecMap<address, VecSet<address>>,
     reward_slashing_rate: u64,
     low_stake_threshold: u64,
@@ -1006,7 +1006,7 @@ It does the following things:
     let unadjusted_staking_reward_amounts = compute_unadjusted_reward_distribution(
         &self.active_validators,
         total_voting_power,
-        computation_reward.value(),
+        total_validator_rewards.value(),
     );
 
     // Use the tallying rule report records for the epoch to compute validators that will be
@@ -1042,7 +1042,7 @@ It does the following things:
     distribute_reward(
         &mut self.active_validators,
         &adjusted_staking_reward_amounts,
-        computation_reward,
+        total_validator_rewards,
         ctx
     );
 
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index b40be4f1b63..72a69588111 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -873,7 +873,7 @@ module iota_system::iota_system_state_inner {
         let stake_subsidy_amount = stake_subsidy.value();
         computation_reward.join(stake_subsidy);
 
-        let mut computation_reward = match_computation_reward_to_target_reward(
+        let mut total_validator_rewards = match_computation_reward_to_target_reward(
             validator_target_reward,
             computation_reward,
             &mut self.iota_treasury_cap,
@@ -884,10 +884,10 @@ module iota_system::iota_system_state_inner {
         // Sanity check to make sure we are advancing to the right epoch.
         assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch);
 
-        let computation_reward_amount_before_distribution = computation_reward.value();
+        let total_validator_rewards_amount_before_distribution = total_validator_rewards.value();
 
         self.validators.advance_epoch(
-            &mut computation_reward,
+            &mut total_validator_rewards,
             &mut self.validator_report_records,
             reward_slashing_rate,
             self.parameters.validator_low_stake_threshold,
@@ -898,16 +898,16 @@ module iota_system::iota_system_state_inner {
 
         let new_total_stake = self.validators.total_stake();
 
-        let computation_reward_amount_after_distribution = computation_reward.value();
-        let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution;
+        let total_validator_rewards_amount_after_distribution = total_validator_rewards.value();
+        let total_validator_rewards_distributed = total_validator_rewards_amount_before_distribution - total_validator_rewards_amount_after_distribution;
 
         self.protocol_version = next_protocol_version;
 
         // Derive the reference gas price for the new epoch
         self.reference_gas_price = self.validators.derive_reference_gas_price();
         // Because of precision issues with integer divisions, we expect that there will be some
-        // remaining balance in `computation_reward`.
-        let leftover_staking_rewards = computation_reward;
+        // remaining balance in `total_validator_rewards`.
+        let leftover_staking_rewards = total_validator_rewards;
         let leftover_storage_fund_inflow = leftover_staking_rewards.value();
 
         // Burning leftover rewards
@@ -933,7 +933,7 @@ module iota_system::iota_system_state_inner {
                 storage_fund_balance: self.storage_fund.total_balance(),
                 stake_subsidy_amount,
                 total_gas_fees: computation_charge,
-                total_stake_rewards_distributed: computation_reward_distributed,
+                total_stake_rewards_distributed: total_validator_rewards_distributed,
                 leftover_storage_fund_inflow,
             }
         );
diff --git a/crates/iota-framework/packages/iota-system/sources/validator_set.move b/crates/iota-framework/packages/iota-system/sources/validator_set.move
index 4eb268359f4..cc2e8f6a34d 100644
--- a/crates/iota-framework/packages/iota-system/sources/validator_set.move
+++ b/crates/iota-framework/packages/iota-system/sources/validator_set.move
@@ -341,7 +341,7 @@ module iota_system::validator_set {
     ///   5. At the end, we calculate the total stake for the new epoch.
     public(package) fun advance_epoch(
         self: &mut ValidatorSet,
-        computation_reward: &mut Balance,
+        total_validator_rewards: &mut Balance,
         validator_report_records: &mut VecMap>,
         reward_slashing_rate: u64,
         low_stake_threshold: u64,
@@ -356,7 +356,7 @@ module iota_system::validator_set {
         let unadjusted_staking_reward_amounts = compute_unadjusted_reward_distribution(
             &self.active_validators,
             total_voting_power,
-            computation_reward.value(),
+            total_validator_rewards.value(),
         );
 
         // Use the tallying rule report records for the epoch to compute validators that will be
@@ -392,7 +392,7 @@ module iota_system::validator_set {
         distribute_reward(
             &mut self.active_validators,
             &adjusted_staking_reward_amounts,
-            computation_reward,
+            total_validator_rewards,
             ctx
         );
 

From 93c11ca7dec44740fc1248f97d8195772f3b95b6 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Thu, 11 Jul 2024 08:54:14 +0200
Subject: [PATCH 29/50] feat: Add minting test with commission

---
 .../tests/rewards_distribution_tests.move     | 41 +++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
index 0beec554216..ac9830501a4 100644
--- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
@@ -210,6 +210,47 @@ module iota_system::rewards_distribution_tests {
         scenario_val.end();
     }
 
+    #[test]
+    fun test_validator_target_reward_higher_than_computation_reward_with_commission() {
+        set_up_iota_system_state();
+        let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1);
+        let scenario = &mut scenario_val;
+
+        stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 100, scenario);
+        stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_2, 50, scenario);
+        advance_epoch(scenario);
+        // V1: 200, V2: 250, V3: 300, V4: 400
+
+        set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_1, 500, scenario); // 5% commission
+
+        advance_epoch_with_target_reward_amounts(800, 0, 400, scenario);
+
+        // The computation reward is lower than the target reward, so 400 IOTA should be minted.
+        // Each validator pool has 25% of the voting power and thus gets 25% of the reward (200 IOTA each).
+        assert_validator_total_stake_amounts(
+          validator_addrs(),
+          vector[
+            (200 + 200) * MICROS_PER_IOTA,
+            (250 + 200) * MICROS_PER_IOTA,
+            (300 + 200) * MICROS_PER_IOTA,
+            (400 + 200) * MICROS_PER_IOTA,
+          ],
+          scenario
+        );
+
+        unstake(STAKER_ADDR_1, 0, scenario);
+        unstake(STAKER_ADDR_2, 0, scenario);
+
+        // Staker 1 should have its original 100 staked IOTA and get half the pool reward (100)
+        // minus the validator's commission (100 * 0.05 = 5), so 95.
+        assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), (100 + 95) * MICROS_PER_IOTA);
+
+        // Staker 2 should get 50/250 = 1/5 of the pool reward, which is 40.
+        assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), (50 + 40) * MICROS_PER_IOTA);
+
+        scenario_val.end();
+    }
+
     #[test]
     fun test_stake_rewards() {
         set_up_iota_system_state();

From 13b6ae624f7790ad2106abc8d999db46a41489da Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Thu, 11 Jul 2024 11:08:17 +0300
Subject: [PATCH 30/50] fix(iota-framework): removed the iota supply constants

---
 .../docs/iota-framework/iota.md               | 31 -------------------
 .../packages/iota-framework/sources/iota.move | 13 --------
 2 files changed, 44 deletions(-)

diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md
index 40578216259..4df1ecd2d27 100644
--- a/crates/iota-framework/docs/iota-framework/iota.md
+++ b/crates/iota-framework/docs/iota-framework/iota.md
@@ -110,37 +110,6 @@ Sender is not @0x0 the system address.
 
 
 
-
-
-The amount of Micros per Iota token based on the fact that micros is
-10^-9 of a Iota token
-
-
-
const MICROS_PER_IOTA: u64 = 1000000000;
-
- - - - - -The total supply of Iota denominated in whole Iota tokens (10 Billion) - - -
const TOTAL_SUPPLY_IOTA: u64 = 10000000000;
-
- - - - - -The total supply of Iota denominated in Micros (10 Billion * 10^9) - - -
const TOTAL_SUPPLY_MICROS: u64 = 10000000000000000000;
-
- - - ## Function `new` diff --git a/crates/iota-framework/packages/iota-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move index 716da1f68c8..e48bee9d562 100644 --- a/crates/iota-framework/packages/iota-framework/sources/iota.move +++ b/crates/iota-framework/packages/iota-framework/sources/iota.move @@ -12,19 +12,6 @@ module iota::iota { /// Sender is not @0x0 the system address. const ENotSystemAddress: u64 = 1; - #[allow(unused_const)] - /// The amount of Micros per Iota token based on the fact that micros is - /// 10^-9 of a Iota token - const MICROS_PER_IOTA: u64 = 1_000_000_000; - - #[allow(unused_const)] - /// The total supply of Iota denominated in whole Iota tokens (10 Billion) - const TOTAL_SUPPLY_IOTA: u64 = 10_000_000_000; - - #[allow(unused_const)] - /// The total supply of Iota denominated in Micros (10 Billion * 10^9) - const TOTAL_SUPPLY_MICROS: u64 = 10_000_000_000_000_000_000; - /// Name of the coin public struct IOTA has drop {} From 777c96881155b2f8bd8e07c4f1aff6b4afd1f1e9 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 12 Jul 2024 10:31:26 +0200 Subject: [PATCH 31/50] fix: advance_epoch comments --- crates/iota-framework/docs/iota-system/iota_system.md | 9 ++++++--- .../docs/iota-system/iota_system_state_inner.md | 9 ++++++--- .../packages/iota-system/sources/iota_system.move | 9 ++++++--- .../iota-system/sources/iota_system_state_inner.move | 9 ++++++--- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md index b17934d66b0..b676b51ece5 100644 --- a/crates/iota-framework/docs/iota-system/iota_system.md +++ b/crates/iota-framework/docs/iota-system/iota_system.md @@ -1356,11 +1356,14 @@ Getter returning addresses of the currently active validators. This function should be called at the end of an epoch, and advances the system to the next epoch. It does the following things: -1. Add storage charge to the storage fund. +1. Add storage reward to the storage fund. 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's gas coins. -3. Distribute computation charge to validator stake. -4. Update all validators. +3. Mint or burn IOTA tokens depending on whether the validator target reward is greater +or smaller than the computation reward. +4. Distribute the target reward to the validators. +5. Burn any leftover rewards. +6. Update all validators.
fun advance_epoch(validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index 272515d6d02..46631e41dfd 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -2071,11 +2071,14 @@ Update candidate validator's public key of network key.
 
 This function should be called at the end of an epoch, and advances the system to the next epoch.
 It does the following things:
-1. Add storage charge to the storage fund.
+1. Add storage reward to the storage fund.
 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's
 gas coins.
-3. Distribute computation charge to validator stake.
-4. Update all validators.
+3. Mint or burn IOTA tokens depending on whether the validator target reward is greater
+or smaller than the computation reward.
+4. Distribute the target reward to the validators.
+5. Burn any leftover rewards.
+6. Update all validators.
 
 
 
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move
index 4c9a6f2885b..1fdf2867f56 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move
@@ -532,11 +532,14 @@ module iota_system::iota_system {
     #[allow(unused_function)]
     /// This function should be called at the end of an epoch, and advances the system to the next epoch.
     /// It does the following things:
-    /// 1. Add storage charge to the storage fund.
+    /// 1. Add storage reward to the storage fund.
     /// 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's
     ///    gas coins.
-    /// 3. Distribute computation charge to validator stake.
-    /// 4. Update all validators.
+    /// 3. Mint or burn IOTA tokens depending on whether the validator target reward is greater
+    /// or smaller than the computation reward.
+    /// 4. Distribute the target reward to the validators.
+    /// 5. Burn any leftover rewards.
+    /// 6. Update all validators.
     fun advance_epoch(
         validator_target_reward: u64,
         storage_reward: Balance,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index 72a69588111..5fce2d9ce93 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -818,11 +818,14 @@ module iota_system::iota_system_state_inner {
 
     /// This function should be called at the end of an epoch, and advances the system to the next epoch.
     /// It does the following things:
-    /// 1. Add storage charge to the storage fund.
+    /// 1. Add storage reward to the storage fund.
     /// 2. Burn the storage rebates from the storage fund. These are already refunded to transaction sender's
     ///    gas coins.
-    /// 3. Distribute computation charge to validator stake.
-    /// 4. Update all validators.
+    /// 3. Mint or burn IOTA tokens depending on whether the validator target reward is greater
+    /// or smaller than the computation reward.
+    /// 4. Distribute the target reward to the validators.
+    /// 5. Burn any leftover rewards.
+    /// 6. Update all validators.
     public(package) fun advance_epoch(
         self: &mut IotaSystemStateInnerV2,
         new_epoch: u64,

From cf2b3d35357533243ed0ff7c7876809ce7a06dc3 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 12 Jul 2024 10:40:16 +0200
Subject: [PATCH 32/50] fix: Improve post distribution validator reward
 variable name

---
 .../docs/iota-system/iota_system_state_inner.md               | 4 ++--
 .../packages/iota-system/sources/iota_system_state_inner.move | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index 46631e41dfd..9d7a5f3d229 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -2165,8 +2165,8 @@ or smaller than the computation reward.
 
     let new_total_stake = self.validators.total_stake();
 
-    let total_validator_rewards_amount_after_distribution = total_validator_rewards.value();
-    let total_validator_rewards_distributed = total_validator_rewards_amount_before_distribution - total_validator_rewards_amount_after_distribution;
+    let remaining_validator_rewards_amount_after_distribution = total_validator_rewards.value();
+    let total_validator_rewards_distributed = total_validator_rewards_amount_before_distribution - remaining_validator_rewards_amount_after_distribution;
 
     self.protocol_version = next_protocol_version;
 
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index 5fce2d9ce93..4fefa63d98a 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -901,8 +901,8 @@ module iota_system::iota_system_state_inner {
 
         let new_total_stake = self.validators.total_stake();
 
-        let total_validator_rewards_amount_after_distribution = total_validator_rewards.value();
-        let total_validator_rewards_distributed = total_validator_rewards_amount_before_distribution - total_validator_rewards_amount_after_distribution;
+        let remaining_validator_rewards_amount_after_distribution = total_validator_rewards.value();
+        let total_validator_rewards_distributed = total_validator_rewards_amount_before_distribution - remaining_validator_rewards_amount_after_distribution;
 
         self.protocol_version = next_protocol_version;
 

From 11bbd8342f37d9087fa80565489cf4eeff67ce6e Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 12 Jul 2024 10:40:59 +0200
Subject: [PATCH 33/50] fix: Comment on IOTA treasury cap creation

---
 crates/iota-genesis-builder/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs
index 7fb3e265c20..5ab76116c30 100644
--- a/crates/iota-genesis-builder/src/lib.rs
+++ b/crates/iota-genesis-builder/src/lib.rs
@@ -1215,7 +1215,7 @@ pub fn generate_genesis_system_object(
             )?;
         }
 
-        // Step 4: Create the IOTA Coin.
+        // Step 4: Create the IOTA Coin Treasury Cap.
         let iota_treasury_cap = builder.programmable_move_call(
             IOTA_FRAMEWORK_PACKAGE_ID,
             ident_str!("iota").to_owned(),

From bb391facb3bc846f4d794185f00491659b8d77bd Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 12 Jul 2024 11:40:21 +0200
Subject: [PATCH 34/50] feat: Match subsidy fund params in test to genesis
 config

---
 .../iota-system/tests/governance_test_utils.move      | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
index 169e8c39860..31118abc210 100644
--- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
+++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
@@ -64,7 +64,7 @@ module iota_system::governance_test_utils {
     ) {
         let system_parameters = iota_system_state_inner::create_system_parameters(
             42,  // epoch_duration_ms, doesn't matter what number we put here
-            0,   // stake_subsidy_start_epoch
+            18446744073709551615,   // stake_subsidy_start_epoch
 
             150, // max_validator_count
             1,   // min_validator_joining_stake
@@ -76,15 +76,18 @@ module iota_system::governance_test_utils {
 
         let mut iota_treasury_cap = iota::create_for_testing(ctx);
 
-        let stake_subsidy_balance = iota_treasury_cap.mint_balance(
+        // We mint the given amount so the system appears to have a total supply of iota_supply_amount,
+        // but we don't put it in the subsidy fund.
+        let iota_total_supply_balance = iota_treasury_cap.mint_balance(
             iota_supply_amount * MICROS_PER_IOTA,
             ctx,
         );
+        iota_total_supply_balance.destroy_for_testing();
 
         let stake_subsidy = stake_subsidy::create(
-            stake_subsidy_balance,
+            balance::zero(),
             0,  // stake subsidy initial distribution amount
-            10, // stake_subsidy_period_length
+            18446744073709551615, // stake_subsidy_period_length
             0,  // stake_subsidy_decrease_rate
             ctx,
         );

From b498ee9fc2c0566615e344ee6dae63d3856f7e4a Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 12 Jul 2024 11:40:56 +0200
Subject: [PATCH 35/50] fix: Remove stake subsidy fund test

---
 .../iota-system/tests/iota_system_tests.move  | 30 -------------------
 1 file changed, 30 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
index 43107d246d5..c6b80810b2e 100644
--- a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
@@ -973,34 +973,4 @@ module iota_system::iota_system_tests {
         test_scenario::return_shared(system_state);
         scenario_val.end();
     }
-
-    #[test]
-    fun test_skip_stake_subsidy() {
-        let mut scenario_val = test_scenario::begin(@0x0);
-        let scenario = &mut scenario_val;
-        // Epoch duration is set to be 42 here.
-        set_up_iota_system_state(vector[@0x1, @0x2]);
-
-        // If the epoch length is less than 42 then the stake subsidy distribution counter should not be incremented. Otherwise it should.
-        advance_epoch_and_check_distribution_counter(scenario, 42, true);
-        advance_epoch_and_check_distribution_counter(scenario, 32, false);
-        advance_epoch_and_check_distribution_counter(scenario, 52, true);
-        scenario_val.end();
-    }
-
-    fun advance_epoch_and_check_distribution_counter(scenario: &mut Scenario, epoch_length: u64, should_increment_counter: bool) {
-        scenario.next_tx(@0x0);
-        let new_epoch = scenario.ctx().epoch() + 1;
-        let mut system_state = scenario.take_shared();
-        let prev_epoch_time = system_state.epoch_start_timestamp_ms();
-        let prev_counter = system_state.get_stake_subsidy_distribution_counter();
-
-        let rebate = system_state.advance_epoch_for_testing(
-            new_epoch, 1, 0, 0, 0, 0, 0, 0, prev_epoch_time + epoch_length, scenario.ctx()
-        );
-        destroy(rebate);
-        assert_eq(system_state.get_stake_subsidy_distribution_counter(), prev_counter + (if (should_increment_counter) 1 else 0));
-        test_scenario::return_shared(system_state);
-        scenario.next_epoch(@0x0);
-    }
 }

From 456b768169d6442b48935eb86b97ec604bba4ff7 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 12 Jul 2024 13:10:52 +0200
Subject: [PATCH 36/50] fix: Remove unused import

---
 .../packages/iota-system/tests/iota_system_tests.move           | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
index c6b80810b2e..94534f5984e 100644
--- a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move
@@ -17,7 +17,7 @@ module iota_system::iota_system_tests {
     use iota_system::validator_set;
     use iota_system::validator_cap::UnverifiedValidatorOperationCap;
     use iota::balance;
-    use iota::test_utils::{assert_eq, destroy};
+    use iota::test_utils::assert_eq;
     use iota::url;
 
     #[test]

From 9657f240d907b9283fe6665336ea4067f464133a Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Fri, 12 Jul 2024 13:23:04 +0200
Subject: [PATCH 37/50] refactor: Remove `mint_genesis_supply` function

---
 .../docs/iota-framework/iota.md               | 29 -------------------
 .../packages/iota-framework/sources/iota.move |  9 ------
 2 files changed, 38 deletions(-)

diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md
index adba8d4ef2c..66992fcce8b 100644
--- a/crates/iota-framework/docs/iota-framework/iota.md
+++ b/crates/iota-framework/docs/iota-framework/iota.md
@@ -16,7 +16,6 @@ It has 9 decimals, and the smallest unit (10^-9) is called "nano".
 -  [Function `burn`](#0x2_iota_burn)
 -  [Function `burn_balance`](#0x2_iota_burn_balance)
 -  [Function `total_supply`](#0x2_iota_total_supply)
--  [Function `mint_genesis_supply`](#0x2_iota_mint_genesis_supply)
 
 
 
use 0x1::option;
@@ -309,32 +308,4 @@ Return the total number of IOTA's in circulation.
 
 
 
-
-
-
-
-## Function `mint_genesis_supply`
-
-Increase the IOTA supply.
-This should be called only once during genesis creation.
-
-
-
fun mint_genesis_supply(cap: &mut iota::IotaTreasuryCap, value: u64, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
-
- - - -
-Implementation - - -
fun mint_genesis_supply(cap: &mut IotaTreasuryCap, value: u64, ctx: &TxContext): Balance<IOTA> {
-    assert!(ctx.epoch() == 0, EAlreadyMinted);
-
-    cap.mint_balance(value, ctx)
-}
-
- - -
diff --git a/crates/iota-framework/packages/iota-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move index bc1ec10b7d6..d05e0e7e02a 100644 --- a/crates/iota-framework/packages/iota-framework/sources/iota.move +++ b/crates/iota-framework/packages/iota-framework/sources/iota.move @@ -84,15 +84,6 @@ module iota::iota { cap.inner.total_supply() } - #[allow(unused_function)] - /// Increase the IOTA supply. - /// This should be called only once during genesis creation. - fun mint_genesis_supply(cap: &mut IotaTreasuryCap, value: u64, ctx: &TxContext): Balance { - assert!(ctx.epoch() == 0, EAlreadyMinted); - - cap.mint_balance(value, ctx) - } - #[test_only] public fun create_for_testing(ctx: &mut TxContext): IotaTreasuryCap { // The `new` function must be called here to be sure that the test function From 09ee91dbc242df88a7529530ddce5b8ebe595d5a Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 12 Jul 2024 13:23:55 +0200 Subject: [PATCH 38/50] feat: Call `mint_balance` on genesis instead --- crates/iota-genesis-builder/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs index 5ab76116c30..934a8b19953 100644 --- a/crates/iota-genesis-builder/src/lib.rs +++ b/crates/iota-genesis-builder/src/lib.rs @@ -1231,7 +1231,7 @@ pub fn generate_genesis_system_object( let total_iota = builder.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, ident_str!("iota").to_owned(), - ident_str!("mint_genesis_supply").to_owned(), + ident_str!("mint_balance").to_owned(), vec![], vec![iota_treasury_cap, total_iota_supply], ); From 5021e387b459f6150aaa39d60159535ac9ff230a Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Fri, 12 Jul 2024 16:23:54 +0300 Subject: [PATCH 39/50] feat: iota-genesis-builder was corrected according to inflation mechanism --- .../docs/iota-framework/balance.md | 41 +++++++++++++++++++ .../docs/iota-system/genesis.md | 35 +++++++++------- .../iota-framework/sources/balance.move | 13 ++++++ .../packages/iota-system/sources/genesis.move | 27 ++++++------ crates/iota-genesis-builder/src/lib.rs | 30 ++++++++++---- crates/iota-genesis-builder/src/stake.rs | 13 ++---- 6 files changed, 114 insertions(+), 45 deletions(-) diff --git a/crates/iota-framework/docs/iota-framework/balance.md b/crates/iota-framework/docs/iota-framework/balance.md index f5165ce736a..56af65c9736 100644 --- a/crates/iota-framework/docs/iota-framework/balance.md +++ b/crates/iota-framework/docs/iota-framework/balance.md @@ -22,6 +22,7 @@ custom coins with + +Epoch is not 0 the genesis epoch. + + +
const ENotGenesisEpoch: u64 = 4;
+
+ + + For when an overflow is happening on Supply operations. @@ -448,6 +459,36 @@ and nowhere else. + + + + +## Function `destroy_genesis_supply` + +CAUTION: this function destroys a Balance without decreasing the supply. +It should only be called by the genesis txn to destroy IOTA supply +which created during the migration and nowhere else. + + +
fun destroy_genesis_supply<T>(self: balance::Balance<T>, ctx: &tx_context::TxContext)
+
+ + + +
+Implementation + + +
fun destroy_genesis_supply<T>(self: Balance<T>, ctx: &TxContext) {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+    assert!(ctx.epoch() == 0, ENotGenesisEpoch);
+
+    let Balance { value: _ } = self;
+}
+
+ + +
diff --git a/crates/iota-framework/docs/iota-system/genesis.md b/crates/iota-framework/docs/iota-system/genesis.md index 50704b20cab..2333313c018 100644 --- a/crates/iota-framework/docs/iota-system/genesis.md +++ b/crates/iota-framework/docs/iota-system/genesis.md @@ -254,7 +254,7 @@ title: Module `0x3::genesis`
-stake_subsidy_fund_nanos: u64 +pre_minted_supply: u64
@@ -341,6 +341,16 @@ The create function was called with duplicate validators. + + +The create function was called with wrong pre-mined supply. + + +
const EWrongPreMintedSupply: u64 = 2;
+
+ + + ## Function `create` @@ -350,7 +360,7 @@ It will create a singleton IotaSystemState object, which contains all the information we need in the system. -
fun create(iota_system_state_id: object::UID, iota_treasury_cap: iota::IotaTreasuryCap, iota_supply: balance::Balance<iota::IOTA>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, timelock_genesis_label: option::Option<string::String>, system_timelock_cap: timelock::SystemTimelockCap, ctx: &mut tx_context::TxContext)
+
fun create(iota_system_state_id: object::UID, iota_treasury_cap: iota::IotaTreasuryCap, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, timelock_genesis_label: option::Option<string::String>, system_timelock_cap: timelock::SystemTimelockCap, ctx: &mut tx_context::TxContext)
 
@@ -361,8 +371,7 @@ all the information we need in the system.
fun create(
     iota_system_state_id: UID,
-    iota_treasury_cap: IotaTreasuryCap,
-    mut iota_supply: Balance<IOTA>,
+    mut iota_treasury_cap: IotaTreasuryCap,
     genesis_chain_parameters: GenesisChainParameters,
     genesis_validators: vector<GenesisValidatorMetadata>,
     token_distribution_schedule: TokenDistributionSchedule,
@@ -374,11 +383,13 @@ all the information we need in the system.
     assert!(ctx.epoch() == 0, ENotCalledAtGenesis);
 
     let TokenDistributionSchedule {
-        stake_subsidy_fund_nanos,
+        pre_minted_supply,
         allocations,
     } = token_distribution_schedule;
 
-    let subsidy_fund = iota_supply.split(stake_subsidy_fund_nanos);
+    assert!(iota_treasury_cap.total_supply() == pre_minted_supply, EWrongPreMintedSupply);
+
+    let subsidy_fund = balance::zero();
     let storage_fund = balance::zero();
 
     // Create all the `Validator` structs
@@ -436,7 +447,7 @@ all the information we need in the system.
 
     // Allocate tokens and staking operations
     allocate_tokens(
-        iota_supply,
+        &mut iota_treasury_cap,
         allocations,
         &mut validators,
         timelock_genesis_label,
@@ -493,7 +504,7 @@ all the information we need in the system.
 
 
 
-
fun allocate_tokens(iota_supply: balance::Balance<iota::IOTA>, allocations: vector<genesis::TokenAllocation>, validators: &mut vector<validator::Validator>, timelock_genesis_label: option::Option<string::String>, ctx: &mut tx_context::TxContext)
+
fun allocate_tokens(iota_treasury_cap: &mut iota::IotaTreasuryCap, allocations: vector<genesis::TokenAllocation>, validators: &mut vector<validator::Validator>, timelock_genesis_label: option::Option<string::String>, ctx: &mut tx_context::TxContext)
 
@@ -503,7 +514,7 @@ all the information we need in the system.
fun allocate_tokens(
-    mut iota_supply: Balance<IOTA>,
+    iota_treasury_cap: &mut IotaTreasuryCap,
     mut allocations: vector<TokenAllocation>,
     validators: &mut vector<Validator>,
     timelock_genesis_label: Option<String>,
@@ -518,7 +529,7 @@ all the information we need in the system.
             staked_with_timelock_expiration,
         } = allocations.pop_back();
 
-        let allocation_balance = iota_supply.split(amount_nanos);
+        let allocation_balance = iota_treasury_cap.mint_balance(amount_nanos, ctx);
 
         if (staked_with_validator.is_some()) {
             let validator_address = staked_with_validator.destroy_some();
@@ -550,10 +561,6 @@ all the information we need in the system.
         };
     };
     allocations.destroy_empty();
-
-    // Provided allocations must fully allocate the iota_supply and there
-    // should be none left at this point.
-    iota_supply.destroy_zero();
 }
 
diff --git a/crates/iota-framework/packages/iota-framework/sources/balance.move b/crates/iota-framework/packages/iota-framework/sources/balance.move index 456e4eef3f0..fe0645fa84a 100644 --- a/crates/iota-framework/packages/iota-framework/sources/balance.move +++ b/crates/iota-framework/packages/iota-framework/sources/balance.move @@ -20,6 +20,8 @@ module iota::balance { const ENotEnough: u64 = 2; /// Sender is not @0x0 the system address. const ENotSystemAddress: u64 = 3; + /// Epoch is not 0 the genesis epoch. + const ENotGenesisEpoch: u64 = 4; /// A Supply of T. Used for minting and burning. /// Wrapped into a `TreasuryCap` in the `Coin` module. @@ -112,6 +114,17 @@ module iota::balance { let Balance { value: _ } = self; } + #[allow(unused_function)] + /// CAUTION: this function destroys a `Balance` without decreasing the supply. + /// It should only be called by the genesis txn to destroy IOTA supply + /// which created during the migration and nowhere else. + fun destroy_genesis_supply(self: Balance, ctx: &TxContext) { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + assert!(ctx.epoch() == 0, ENotGenesisEpoch); + + let Balance { value: _ } = self; + } + /// Destroy a `Supply` preventing any further minting and burning. public(package) fun destroy_supply(self: Supply): u64 { let Supply { value } = self; diff --git a/crates/iota-framework/packages/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move index d17941df0e5..af2a6e05d28 100644 --- a/crates/iota-framework/packages/iota-system/sources/genesis.move +++ b/crates/iota-framework/packages/iota-system/sources/genesis.move @@ -6,8 +6,8 @@ module iota_system::genesis { use std::string::String; - use iota::balance::{Self, Balance}; - use iota::iota::{Self, IOTA, IotaTreasuryCap}; + use iota::balance; + use iota::iota::{Self, IotaTreasuryCap}; use iota::timelock::SystemTimelockCap; use iota_system::iota_system; use iota_system::validator::{Self, Validator}; @@ -59,7 +59,7 @@ module iota_system::genesis { } public struct TokenDistributionSchedule { - stake_subsidy_fund_nanos: u64, + pre_minted_supply: u64, allocations: vector, } @@ -79,6 +79,8 @@ module iota_system::genesis { const ENotCalledAtGenesis: u64 = 0; /// The `create` function was called with duplicate validators. const EDuplicateValidator: u64 = 1; + /// The `create` function was called with wrong pre-mined supply. + const EWrongPreMintedSupply: u64 = 2; #[allow(unused_function)] /// This function will be explicitly called once at genesis. @@ -86,8 +88,7 @@ module iota_system::genesis { /// all the information we need in the system. fun create( iota_system_state_id: UID, - iota_treasury_cap: IotaTreasuryCap, - mut iota_supply: Balance, + mut iota_treasury_cap: IotaTreasuryCap, genesis_chain_parameters: GenesisChainParameters, genesis_validators: vector, token_distribution_schedule: TokenDistributionSchedule, @@ -99,11 +100,13 @@ module iota_system::genesis { assert!(ctx.epoch() == 0, ENotCalledAtGenesis); let TokenDistributionSchedule { - stake_subsidy_fund_nanos, + pre_minted_supply, allocations, } = token_distribution_schedule; - let subsidy_fund = iota_supply.split(stake_subsidy_fund_nanos); + assert!(iota_treasury_cap.total_supply() == pre_minted_supply, EWrongPreMintedSupply); + + let subsidy_fund = balance::zero(); let storage_fund = balance::zero(); // Create all the `Validator` structs @@ -161,7 +164,7 @@ module iota_system::genesis { // Allocate tokens and staking operations allocate_tokens( - iota_supply, + &mut iota_treasury_cap, allocations, &mut validators, timelock_genesis_label, @@ -208,7 +211,7 @@ module iota_system::genesis { } fun allocate_tokens( - mut iota_supply: Balance, + iota_treasury_cap: &mut IotaTreasuryCap, mut allocations: vector, validators: &mut vector, timelock_genesis_label: Option, @@ -223,7 +226,7 @@ module iota_system::genesis { staked_with_timelock_expiration, } = allocations.pop_back(); - let allocation_balance = iota_supply.split(amount_nanos); + let allocation_balance = iota_treasury_cap.mint_balance(amount_nanos, ctx); if (staked_with_validator.is_some()) { let validator_address = staked_with_validator.destroy_some(); @@ -255,10 +258,6 @@ module iota_system::genesis { }; }; allocations.destroy_empty(); - - // Provided allocations must fully allocate the iota_supply and there - // should be none left at this point. - iota_supply.destroy_zero(); } fun activate_validators(validators: &mut vector) { diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs index 934a8b19953..aa4d9cdd336 100644 --- a/crates/iota-genesis-builder/src/lib.rs +++ b/crates/iota-genesis-builder/src/lib.rs @@ -23,7 +23,7 @@ use iota_framework::{BuiltInFramework, SystemPackage}; use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion}; use iota_sdk::{types::block::address::Address, Url}; use iota_types::{ - balance::Balance, + balance::{Balance, BALANCE_MODULE_NAME}, base_types::{ ExecutionDigests, IotaAddress, ObjectID, ObjectRef, SequenceNumber, TransactionDigest, TxContext, @@ -38,7 +38,7 @@ use iota_types::{ effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, epoch_data::EpochData, gas::IotaGasStatus, - gas_coin::{GasCoin, GAS, TOTAL_SUPPLY_NANOS}, + gas_coin::{GasCoin, GAS}, governance::StakedIota, in_memory_storage::InMemoryStorage, inner_temporary_store::InnerTemporaryStore, @@ -564,9 +564,16 @@ impl Builder { // Check distribution is correct let token_distribution_schedule = self.token_distribution_schedule.clone().unwrap(); + + let allocations_amount: u64 = token_distribution_schedule + .allocations + .iter() + .map(|a| a.amount_nanos) + .sum(); + assert_eq!( - system_state.stake_subsidy.balance.value(), - token_distribution_schedule.stake_subsidy_fund_nanos + system_state.iota_treasury_cap.total_supply().value, + token_distribution_schedule.pre_minted_supply + allocations_amount ); let mut gas_objects: BTreeMap = unsigned_genesis @@ -1223,10 +1230,9 @@ pub fn generate_genesis_system_object( vec![], vec![], ); - // TODO: This is will need to be modified after the timelock staking changes and - // to account for the migration objects with pre-allocated funds. + let total_iota_supply = builder - .pure(&(TOTAL_SUPPLY_NANOS)) + .pure(&(token_distribution_schedule.pre_minted_supply)) .expect("serialization of u64 should succeed"); let total_iota = builder.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, @@ -1236,6 +1242,14 @@ pub fn generate_genesis_system_object( vec![iota_treasury_cap, total_iota_supply], ); + builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + BALANCE_MODULE_NAME.to_owned(), + ident_str!("destroy_genesis_supply").to_owned(), + vec![], + vec![total_iota], + ); + // Step 5: Create System Timelock Cap. let system_timelock_cap = builder.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, @@ -1248,7 +1262,7 @@ pub fn generate_genesis_system_object( // Step 6: Run genesis. // The first argument is the system state uid we got from step 1 and the second // one is the IOTA `TreasuryCap` we got from step 4. - let mut arguments = vec![iota_system_state_uid, iota_treasury_cap, total_iota]; + let mut arguments = vec![iota_system_state_uid, iota_treasury_cap]; let mut call_arg_arguments = vec![ CallArg::Pure(bcs::to_bytes(&genesis_chain_parameters).unwrap()), CallArg::Pure(bcs::to_bytes(&genesis_validators).unwrap()), diff --git a/crates/iota-genesis-builder/src/stake.rs b/crates/iota-genesis-builder/src/stake.rs index adca78eabf0..0f7772496be 100644 --- a/crates/iota-genesis-builder/src/stake.rs +++ b/crates/iota-genesis-builder/src/stake.rs @@ -52,18 +52,14 @@ impl GenesisStake { && self.timelocks_to_burn.is_empty() } - /// Calculate the total amount of token allocations. - pub fn sum_token_allocation(&self) -> u64 { - self.token_allocation - .iter() - .map(|allocation| allocation.amount_nanos) - .sum() - } - /// Create a new valid [`TokenDistributionSchedule`] from the /// inner token allocations. pub fn to_token_distribution_schedule(&self) -> TokenDistributionSchedule { let mut builder = TokenDistributionScheduleBuilder::new(); + + // TODO: calculate/store the pre-minted supply and call the + // `add_pre_minted_supply` function. + for allocation in self.token_allocation.clone() { builder.add_allocation(allocation); } @@ -83,7 +79,6 @@ impl GenesisStake { vanilla_schedule .allocations .extend(self.token_allocation.clone()); - vanilla_schedule.stake_subsidy_fund_nanos -= self.sum_token_allocation(); vanilla_schedule.validate(); vanilla_schedule } From 614fe2927b219feba420caf5db82bdf3c2beb047 Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Fri, 12 Jul 2024 16:57:40 +0300 Subject: [PATCH 40/50] fix(iota-genesis-builder): the destroy_genesis_supply function call was corrected --- crates/iota-genesis-builder/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs index aa4d9cdd336..b239e2140c2 100644 --- a/crates/iota-genesis-builder/src/lib.rs +++ b/crates/iota-genesis-builder/src/lib.rs @@ -1231,23 +1231,23 @@ pub fn generate_genesis_system_object( vec![], ); - let total_iota_supply = builder + let pre_minted_supply_amount = builder .pure(&(token_distribution_schedule.pre_minted_supply)) .expect("serialization of u64 should succeed"); - let total_iota = builder.programmable_move_call( + let pre_minted_supply = builder.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, ident_str!("iota").to_owned(), ident_str!("mint_balance").to_owned(), vec![], - vec![iota_treasury_cap, total_iota_supply], + vec![iota_treasury_cap, pre_minted_supply_amount], ); builder.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, BALANCE_MODULE_NAME.to_owned(), ident_str!("destroy_genesis_supply").to_owned(), - vec![], - vec![total_iota], + vec![GAS::type_tag()], + vec![pre_minted_supply], ); // Step 5: Create System Timelock Cap. From 7fee06f858924ab24df7b6d49eecc8632d4290bf Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Mon, 15 Jul 2024 10:44:51 +0300 Subject: [PATCH 41/50] fix(iota-genesis-builder): integrated pre-minted supply into GenesisStake --- crates/iota-genesis-builder/src/stake.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crates/iota-genesis-builder/src/stake.rs b/crates/iota-genesis-builder/src/stake.rs index 0f7772496be..28d85216ea7 100644 --- a/crates/iota-genesis-builder/src/stake.rs +++ b/crates/iota-genesis-builder/src/stake.rs @@ -7,6 +7,7 @@ use iota_config::genesis::{ }; use iota_types::{ base_types::{IotaAddress, ObjectRef}, + gas_coin::TOTAL_SUPPLY_NANOS, object::Object, stardust::coin_kind::get_gas_balance_maybe, }; @@ -52,13 +53,20 @@ impl GenesisStake { && self.timelocks_to_burn.is_empty() } + /// Calculate the total amount of token allocations. + pub fn sum_token_allocation(&self) -> u64 { + self.token_allocation + .iter() + .map(|allocation| allocation.amount_nanos) + .sum() + } + /// Create a new valid [`TokenDistributionSchedule`] from the /// inner token allocations. pub fn to_token_distribution_schedule(&self) -> TokenDistributionSchedule { let mut builder = TokenDistributionScheduleBuilder::new(); - // TODO: calculate/store the pre-minted supply and call the - // `add_pre_minted_supply` function. + builder.add_pre_minted_supply(TOTAL_SUPPLY_NANOS - self.sum_token_allocation()); for allocation in self.token_allocation.clone() { builder.add_allocation(allocation); From ddae20a36cbc10112dda73d9c507344d0f7b1f9c Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Mon, 15 Jul 2024 10:55:16 +0300 Subject: [PATCH 42/50] fix: typos and documentation --- crates/iota-framework/docs/iota-framework/balance.md | 6 +++--- crates/iota-framework/docs/iota-system/genesis.md | 2 +- .../packages/iota-framework/sources/balance.move | 6 +++--- .../packages/iota-system/sources/genesis.move | 2 +- crates/iota-genesis-builder/src/lib.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/iota-framework/docs/iota-framework/balance.md b/crates/iota-framework/docs/iota-framework/balance.md index 56af65c9736..abfa50a683f 100644 --- a/crates/iota-framework/docs/iota-framework/balance.md +++ b/crates/iota-framework/docs/iota-framework/balance.md @@ -126,7 +126,7 @@ For when trying to withdraw more than there is. -Epoch is not 0 the genesis epoch. +Epoch is not 0 (the genesis epoch).
const ENotGenesisEpoch: u64 = 4;
@@ -466,8 +466,8 @@ and nowhere else.
 ## Function `destroy_genesis_supply`
 
 CAUTION: this function destroys a Balance without decreasing the supply.
-It should only be called by the genesis txn to destroy IOTA supply
-which created during the migration and nowhere else.
+It should only be called by the genesis txn to destroy parts of the IOTA supply
+which was created during the migration and for no other reason.
 
 
 
fun destroy_genesis_supply<T>(self: balance::Balance<T>, ctx: &tx_context::TxContext)
diff --git a/crates/iota-framework/docs/iota-system/genesis.md b/crates/iota-framework/docs/iota-system/genesis.md
index 2333313c018..49d4da43e41 100644
--- a/crates/iota-framework/docs/iota-system/genesis.md
+++ b/crates/iota-framework/docs/iota-system/genesis.md
@@ -343,7 +343,7 @@ The create function was called with duplicate validators.
 
 
 
-The create function was called with wrong pre-mined supply.
+The create function was called with wrong pre-minted supply.
 
 
 
const EWrongPreMintedSupply: u64 = 2;
diff --git a/crates/iota-framework/packages/iota-framework/sources/balance.move b/crates/iota-framework/packages/iota-framework/sources/balance.move
index fe0645fa84a..b40939c956e 100644
--- a/crates/iota-framework/packages/iota-framework/sources/balance.move
+++ b/crates/iota-framework/packages/iota-framework/sources/balance.move
@@ -20,7 +20,7 @@ module iota::balance {
     const ENotEnough: u64 = 2;
     /// Sender is not @0x0 the system address.
     const ENotSystemAddress: u64 = 3;
-    /// Epoch is not 0 the genesis epoch.
+    /// Epoch is not 0 (the genesis epoch).
     const ENotGenesisEpoch: u64 = 4;
 
     /// A Supply of T. Used for minting and burning.
@@ -116,8 +116,8 @@ module iota::balance {
 
     #[allow(unused_function)]
     /// CAUTION: this function destroys a `Balance` without decreasing the supply.
-    /// It should only be called by the genesis txn to destroy IOTA supply
-    /// which created during the migration and nowhere else.
+    /// It should only be called by the genesis txn to destroy parts of the IOTA supply
+    /// which was created during the migration and for no other reason.
     fun destroy_genesis_supply(self: Balance, ctx: &TxContext) {
         assert!(ctx.sender() == @0x0, ENotSystemAddress);
         assert!(ctx.epoch() == 0, ENotGenesisEpoch);
diff --git a/crates/iota-framework/packages/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move
index af2a6e05d28..fd0260adc15 100644
--- a/crates/iota-framework/packages/iota-system/sources/genesis.move
+++ b/crates/iota-framework/packages/iota-system/sources/genesis.move
@@ -79,7 +79,7 @@ module iota_system::genesis {
     const ENotCalledAtGenesis: u64 = 0;
     /// The `create` function was called with duplicate validators.
     const EDuplicateValidator: u64 = 1;
-    /// The `create` function was called with wrong pre-mined supply.
+    /// The `create` function was called with wrong pre-minted supply.
     const EWrongPreMintedSupply: u64 = 2;
 
     #[allow(unused_function)]
diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs
index b239e2140c2..b3188b6677a 100644
--- a/crates/iota-genesis-builder/src/lib.rs
+++ b/crates/iota-genesis-builder/src/lib.rs
@@ -568,7 +568,7 @@ impl Builder {
         let allocations_amount: u64 = token_distribution_schedule
             .allocations
             .iter()
-            .map(|a| a.amount_nanos)
+            .map(|allocation| allocation.amount_nanos)
             .sum();
 
         assert_eq!(

From 51b687623929067ce848fdedb4dcbe1fdbed8eed Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Mon, 15 Jul 2024 11:56:32 +0300
Subject: [PATCH 43/50] fix: changed naming
 TokenDistributionScheduleBuilder::add_pre_minted_supply ->
 TokenDistributionScheduleBuilder::set_pre_minted_supply

---
 crates/iota-genesis-builder/src/stake.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/iota-genesis-builder/src/stake.rs b/crates/iota-genesis-builder/src/stake.rs
index 28d85216ea7..710193bea5d 100644
--- a/crates/iota-genesis-builder/src/stake.rs
+++ b/crates/iota-genesis-builder/src/stake.rs
@@ -66,7 +66,7 @@ impl GenesisStake {
     pub fn to_token_distribution_schedule(&self) -> TokenDistributionSchedule {
         let mut builder = TokenDistributionScheduleBuilder::new();
 
-        builder.add_pre_minted_supply(TOTAL_SUPPLY_NANOS - self.sum_token_allocation());
+        builder.set_pre_minted_supply(TOTAL_SUPPLY_NANOS - self.sum_token_allocation());
 
         for allocation in self.token_allocation.clone() {
             builder.add_allocation(allocation);

From 5d9ca75196315422683114306830e7b655ffd28a Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Mon, 15 Jul 2024 11:58:00 +0300
Subject: [PATCH 44/50] fix(iota-genesis-builder): integrated pre-minted IOTA
 supply into vanilla tokens distribution

---
 crates/iota-genesis-builder/src/stake.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/crates/iota-genesis-builder/src/stake.rs b/crates/iota-genesis-builder/src/stake.rs
index 710193bea5d..e56561d2094 100644
--- a/crates/iota-genesis-builder/src/stake.rs
+++ b/crates/iota-genesis-builder/src/stake.rs
@@ -87,6 +87,7 @@ impl GenesisStake {
         vanilla_schedule
             .allocations
             .extend(self.token_allocation.clone());
+        vanilla_schedule.pre_minted_supply = TOTAL_SUPPLY_NANOS - self.sum_token_allocation();
         vanilla_schedule.validate();
         vanilla_schedule
     }

From c8297bf0ae1837ccdc97e3b2b4598f49c8aa7e9c Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Mon, 15 Jul 2024 13:08:01 +0300
Subject: [PATCH 45/50] refactor(iota-genesis-builder): added
 calculate_pre_minted_supply function

---
 crates/iota-genesis-builder/src/stake.rs | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/crates/iota-genesis-builder/src/stake.rs b/crates/iota-genesis-builder/src/stake.rs
index e56561d2094..96f5394d53c 100644
--- a/crates/iota-genesis-builder/src/stake.rs
+++ b/crates/iota-genesis-builder/src/stake.rs
@@ -66,7 +66,9 @@ impl GenesisStake {
     pub fn to_token_distribution_schedule(&self) -> TokenDistributionSchedule {
         let mut builder = TokenDistributionScheduleBuilder::new();
 
-        builder.set_pre_minted_supply(TOTAL_SUPPLY_NANOS - self.sum_token_allocation());
+        let pre_minted_supply = self.calculate_pre_minted_supply();
+
+        builder.set_pre_minted_supply(pre_minted_supply);
 
         for allocation in self.token_allocation.clone() {
             builder.add_allocation(allocation);
@@ -87,10 +89,14 @@ impl GenesisStake {
         vanilla_schedule
             .allocations
             .extend(self.token_allocation.clone());
-        vanilla_schedule.pre_minted_supply = TOTAL_SUPPLY_NANOS - self.sum_token_allocation();
+        vanilla_schedule.pre_minted_supply = self.calculate_pre_minted_supply();
         vanilla_schedule.validate();
         vanilla_schedule
     }
+
+    fn calculate_pre_minted_supply(&self) -> u64 {
+        TOTAL_SUPPLY_NANOS - self.sum_token_allocation()
+    }
 }
 
 /// The objects picked for token allocation during genesis

From dc66fc240821a2ca25cd173f98397e195e4d8237 Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Mon, 15 Jul 2024 13:50:49 +0300
Subject: [PATCH 46/50] fix(iota-genesis-builder): added documentation

---
 crates/iota-genesis-builder/src/stake.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/crates/iota-genesis-builder/src/stake.rs b/crates/iota-genesis-builder/src/stake.rs
index 96f5394d53c..0f5da374efe 100644
--- a/crates/iota-genesis-builder/src/stake.rs
+++ b/crates/iota-genesis-builder/src/stake.rs
@@ -94,6 +94,7 @@ impl GenesisStake {
         vanilla_schedule
     }
 
+    /// Calculates the part of the IOTA supply that is pre-minted.
     fn calculate_pre_minted_supply(&self) -> u64 {
         TOTAL_SUPPLY_NANOS - self.sum_token_allocation()
     }

From bcff305bee31302446bc7c996a4f37bd2fa572c6 Mon Sep 17 00:00:00 2001
From: Philipp Gackstatter 
Date: Tue, 16 Jul 2024 10:18:55 +0200
Subject: [PATCH 47/50] fix: Remove outstanding burn tokens TODO

---
 crates/iota-genesis-builder/src/lib.rs | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs
index 4135bc7f1f9..2fcc52fd882 100644
--- a/crates/iota-genesis-builder/src/lib.rs
+++ b/crates/iota-genesis-builder/src/lib.rs
@@ -274,17 +274,6 @@ impl Builder {
         let mut objects = self.migration_objects.take_objects();
         objects.extend(self.objects.values().cloned());
 
-        // Use stake_subsidy_start_epoch to mimic the burn of newly minted IOTA coins
-        if !self.is_vanilla() {
-            // Because we set the `stake_subsidy_fund` as non-zero
-            // we need to effectively disable subsidy rewards
-            // to avoid the respective inflation effects.
-            //
-            // TODO: Handle properly during new tokenomics
-            // implementation.
-            self.parameters.stake_subsidy_start_epoch = u64::MAX;
-        }
-
         // Finally build the genesis data
         self.built_genesis = Some(build_unsigned_genesis_data(
             &self.parameters,

From 5fcf18beca2732b9214a27e77887f74dcc1af846 Mon Sep 17 00:00:00 2001
From: Pavlo Botnar 
Date: Fri, 19 Jul 2024 16:51:13 +0300
Subject: [PATCH 48/50] fix(iota-core): Fix CI after inflation introduction 
 (#1196)

* fix(iota-core): fixing non_refundable_storage_fee related tests
cargo clippy fixes
cargo fmt
broken tests ignoring
---
 crates/iota-genesis-builder/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs
index 22bb4c22cc4..4ed73cd039a 100644
--- a/crates/iota-genesis-builder/src/lib.rs
+++ b/crates/iota-genesis-builder/src/lib.rs
@@ -1265,7 +1265,7 @@ pub fn generate_genesis_system_object(
         );
 
         let pre_minted_supply_amount = builder
-            .pure(&(token_distribution_schedule.pre_minted_supply))
+            .pure(token_distribution_schedule.pre_minted_supply)
             .expect("serialization of u64 should succeed");
         let pre_minted_supply = builder.programmable_move_call(
             IOTA_FRAMEWORK_PACKAGE_ID,

From 554f9f8200d99140e52387f6a218afce6b0d82ad Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Mon, 22 Jul 2024 14:53:07 +0300
Subject: [PATCH 49/50] fix: spelling mistakes

---
 .../packages/iota-system/tests/rewards_distribution_tests.move  | 2 +-
 crates/iota-genesis-builder/src/stardust/test_outputs/mod.rs    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
index ac9830501a4..3f5d4bfaa05 100644
--- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
+++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move
@@ -690,7 +690,7 @@ module iota_system::rewards_distribution_tests {
         let scenario = &mut scenario_val;
 
         // The leftover comes from the unequal distribution of rewards to validators.
-        // As example 1_000_000_000_1 cannot be splitted into equal parts, so it cause leftover.
+        // As example 1_000_000_000_1 cannot be split into equal parts, so it cause leftover.
         let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(1_000_000_000_1, 1_000_000_000_000, 1_000_000_000_1, 0, 0, scenario);
         destroy(storage_rebate);
 
diff --git a/crates/iota-genesis-builder/src/stardust/test_outputs/mod.rs b/crates/iota-genesis-builder/src/stardust/test_outputs/mod.rs
index da893f18ccb..0a66a4b4b84 100644
--- a/crates/iota-genesis-builder/src/stardust/test_outputs/mod.rs
+++ b/crates/iota-genesis-builder/src/stardust/test_outputs/mod.rs
@@ -184,7 +184,7 @@ fn add_only_test_outputs(
     Ok(new_outputs)
 }
 
-/// Get samples of the previous Hornet shapshot without timelocks and with a
+/// Get samples of the previous Hornet snapshot without timelocks and with a
 /// certain probability of picking basic outputs.
 fn with_sampling(
     parser: &mut HornetSnapshotParser,

From 4a2b693722191c1791c4a538268eb13d3d637a51 Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Mon, 22 Jul 2024 17:49:00 +0300
Subject: [PATCH 50/50] fix(iota-framework): cargo fmt

---
 crates/iota-framework/build.rs | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/crates/iota-framework/build.rs b/crates/iota-framework/build.rs
index 425ebcca1d1..4b6dbedec15 100644
--- a/crates/iota-framework/build.rs
+++ b/crates/iota-framework/build.rs
@@ -234,9 +234,9 @@ fn build_packages_with_move_config(
 /// * Replace html tags and use Docusaurus components where needed.
 fn relocate_docs(prefix: &str, files: &[(String, String)], output: &mut BTreeMap) {
     // Turn on multi-line mode so that `.` matches newlines, consume from the start
-    // of the file to beginning of the heading, then capture the heading as three different parts and
-    // replace with the yaml tag for docusaurus, add the Link import and the title anchor,
-    // so the tile can be linked to. E.g., ```
+    // of the file to beginning of the heading, then capture the heading as three
+    // different parts and replace with the yaml tag for docusaurus, add the
+    // Link import and the title anchor, so the tile can be linked to. E.g., ```
     // -
     // -
     // -# Module `0x2::display`
@@ -267,10 +267,13 @@ fn relocate_docs(prefix: &str, files: &[(String, String)], output: &mut BTreeMap
             new_path.to_string_lossy().to_string()
         };
 
-        // Replace a-tags with Link to register anchors in Docusaurus (we have to use the `id` attribute as `name` is deprecated and not existing in Link component)
+        // Replace a-tags with Link to register anchors in Docusaurus (we have to use
+        // the `id` attribute as `name` is deprecated and not existing in Link
+        // component)
         let content = link_from_regex.replace_all(&file_content, r#""#);
 
-        // Replace a-tags with href for Link tags to enable link and anchor checking. We need to make sure that `to` path don't contain extensions in a later step.
+        // Replace a-tags with href for Link tags to enable link and anchor checking. We
+        // need to make sure that `to` path don't contain extensions in a later step.
         let content = link_to_regex.replace_all(&content, r#"$2"#);
 
         // Escape `{` in  and add new lines as this is a requirement from mdx