Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 24 additions & 11 deletions src/flow_test/utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ use staking::pool::interface_v0::{IPoolV0Dispatcher, IPoolV0DispatcherTrait, Poo
use staking::reward_supplier::interface::{
IRewardSupplierDispatcher, IRewardSupplierDispatcherTrait,
};
use staking::reward_supplier::reward_supplier::RewardSupplier::{
DEFAULT_AVG_BLOCK_DURATION, DEFAULT_BLOCK_DURATION_CONFIG,
};
use staking::staking::interface::{
CommissionCommitment, IStakingConfigDispatcher, IStakingConfigDispatcherTrait,
IStakingConsensusDispatcher, IStakingConsensusSafeDispatcher, IStakingDispatcher,
Expand Down Expand Up @@ -61,10 +64,10 @@ use staking::test_utils::constants::{
STARTING_BLOCK_OFFSET, TESTING_C_NUM, TEST_BTC_DECIMALS, UPGRADE_GOVERNOR,
};
use staking::test_utils::{
StakingInitConfig, approve, calculate_block_offset, custom_decimals_token,
declare_pool_contract, declare_pool_eic_contract, declare_staking_contract,
declare_staking_eic_contract, deploy_mock_erc20_decimals_contract, fund, load_from_simple_map,
upgrade_implementation,
StakingInitConfig, advance_blocks, approve, calculate_block_offset, custom_decimals_token,
declare_pool_contract, declare_pool_eic_contract, declare_reward_supplier_contract,
declare_reward_supplier_eic_contract, declare_staking_contract, declare_staking_eic_contract,
deploy_mock_erc20_decimals_contract, fund, load_from_simple_map, upgrade_implementation,
};
use staking::types::{
Amount, BlockNumber, Commission, Epoch, Index, Inflation, InternalPoolMemberInfoLatest,
Expand Down Expand Up @@ -1245,7 +1248,10 @@ pub(crate) impl SystemImpl of SystemTrait {
let current_block = get_block_number();
let epoch_start_block = self.staking.get_epoch_info().current_epoch_starting_block();
let block_offset = block_offset_from_epoch_start - (current_block - epoch_start_block);
advance_block_number_global(blocks: block_offset + MIN_ATTESTATION_WINDOW.into());
advance_blocks(
blocks: block_offset + MIN_ATTESTATION_WINDOW.into(),
block_duration: AVG_BLOCK_DURATION,
);
}

fn deploy_second_btc_token(self: SystemState) -> Token {
Expand Down Expand Up @@ -2056,10 +2062,21 @@ pub(crate) impl SystemReplaceabilityV3Impl of SystemReplaceabilityV3Trait {
);
}

/// Upgrades the reward supplier contract in the system state with a local implementation.
/// Upgrades the staking contract in the system state with a local implementation.
fn upgrade_reward_supplier_implementation_v3(self: SystemState) {
let eic_data = EICData {
eic_hash: declare_reward_supplier_eic_contract(),
eic_init_data: array![
DEFAULT_AVG_BLOCK_DURATION.into(),
DEFAULT_BLOCK_DURATION_CONFIG.min_block_duration.into(),
DEFAULT_BLOCK_DURATION_CONFIG.max_block_duration.into(),
]
.span(),
};
let implementation_data = ImplementationData {
impl_hash: declare_reward_supplier_contract(), eic_data: Option::None, final: false,
impl_hash: declare_reward_supplier_contract(),
eic_data: Option::Some(eic_data),
final: false,
};
upgrade_implementation(
contract_address: self.reward_supplier.address,
Expand All @@ -2069,10 +2086,6 @@ pub(crate) impl SystemReplaceabilityV3Impl of SystemReplaceabilityV3Trait {
}
}

fn declare_reward_supplier_contract() -> ClassHash {
*snforge_std::declare("RewardSupplier").unwrap().contract_class().class_hash
}

fn declare_minting_curve_contract() -> ClassHash {
*snforge_std::declare("MintingCurve").unwrap().contract_class().class_hash
}
Expand Down
1 change: 1 addition & 0 deletions src/reward_supplier.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod eic;
pub mod errors;
pub mod interface;
pub mod reward_supplier;
Expand Down
44 changes: 44 additions & 0 deletions src/reward_supplier/eic.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/// An External Initializer Contract to upgrade a reward supplier contract.
/// This EIC is used to upgrade the reward supplier contract from V2 (BTC) to V3.
#[starknet::contract]
mod RewardSupplierEIC {
use staking::reward_supplier::errors::Error;
use staking::reward_supplier::interface::BlockDurationConfig;
use starknet::storage::StoragePointerWriteAccess;
use starkware_utils::components::replaceability::interface::IEICInitializable;

#[storage]
struct Storage {
// --- New fields ---
/// Average block duration in units of 1 / BLOCK_DURATION_SCALE seconds.
avg_block_duration: u64,
/// Configuration for block duration calculation.
block_duration_config: BlockDurationConfig,
}

/// Expected data : [avg_block_duration, min_block_duration, max_block_duration]
#[abi(embed_v0)]
impl EICInitializable of IEICInitializable<ContractState> {
fn eic_initialize(ref self: ContractState, eic_init_data: Span<felt252>) {
assert(eic_init_data.len() == 3, 'EXPECTED_DATA_LENGTH_3');
let avg_block_duration: u64 = (*eic_init_data[0]).try_into().unwrap();
let min_block_duration: u64 = (*eic_init_data[1]).try_into().unwrap();
let max_block_duration: u64 = (*eic_init_data[2]).try_into().unwrap();

// Validate values.
assert!(
min_block_duration <= avg_block_duration
&& avg_block_duration <= max_block_duration,
"{}",
'INVALID_AVG_BLOCK_DURATION',
);
assert!(min_block_duration > 0, "{}", Error::INVALID_MIN_MAX_BLOCK_DURATION);

// Set values.
self.avg_block_duration.write(avg_block_duration);
self
.block_duration_config
.write(BlockDurationConfig { min_block_duration, max_block_duration });
}
}
}
2 changes: 0 additions & 2 deletions src/reward_supplier/reward_supplier.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,13 @@ pub mod RewardSupplier {
/// Token bridge address.
starkgate_address: ContractAddress,
/// Average block duration in units of 1 / BLOCK_DURATION_SCALE seconds.
// TODO: Initial in EIC.
// TODO: Setter.
// TODO: View?
avg_block_duration: u64,
/// The latest block data used for average block duration calculation.
/// Updated at the start of each epoch.
block_snapshot: (BlockNumber, Timestamp),
/// Configuration for block duration calculation.
// TODO: Initial in EIC.
block_duration_config: BlockDurationConfig,
}

Expand Down
197 changes: 196 additions & 1 deletion src/reward_supplier/test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use staking::test_utils::constants::{
};
use staking::types::{Amount, BlockNumber};
use starknet::{ContractAddress, Store};
use starkware_utils::components::replaceability::interface::{EICData, ImplementationData};
use starkware_utils::errors::{Describable, OptionAuxTrait};
use starkware_utils::math::utils::{ceil_of_division, mul_wide_and_div};
use starkware_utils::time::time::{Time, TimeDelta, Timestamp};
Expand All @@ -41,8 +42,10 @@ use starkware_utils_testing::test_utils::{
};
use test_utils::{
StakingInitConfig, advance_epoch_global, advance_epoch_global_custom_time,
advance_k_epochs_global, advance_time_global, fund, general_contract_system_deployment,
advance_k_epochs_global, advance_time_global, declare_reward_supplier_contract,
declare_reward_supplier_eic_contract, fund, general_contract_system_deployment,
initialize_reward_supplier_state_from_cfg, load_one_felt, stake_for_testing_using_dispatcher,
upgrade_implementation,
};

#[test]
Expand Down Expand Up @@ -688,3 +691,195 @@ fn test_update_current_epoch_block_rewards_with_adjustments() {
assert!(strk_rewards == expected_strk_rewards);
assert!(btc_rewards == expected_btc_rewards);
}

#[test]
fn test_reward_supplier_eic() {
let mut cfg: StakingInitConfig = Default::default();
general_contract_system_deployment(ref :cfg);
let reward_supplier = cfg.staking_contract_info.reward_supplier;
let reward_supplier_dispatcher = IRewardSupplierDispatcher {
contract_address: reward_supplier,
};
let upgrade_governor = cfg.test_info.upgrade_governor;
let avg_block_duration = load_one_felt(
target: reward_supplier, storage_address: selector!("avg_block_duration"),
)
.try_into()
.unwrap();
assert!(avg_block_duration == DEFAULT_AVG_BLOCK_DURATION);
assert!(
reward_supplier_dispatcher.get_block_duration_config() == DEFAULT_BLOCK_DURATION_CONFIG,
);

// Upgrade.
let avg_block_duration = DEFAULT_AVG_BLOCK_DURATION - 10;
let min_block_duration = DEFAULT_BLOCK_DURATION_CONFIG.min_block_duration - 10;
let max_block_duration = DEFAULT_BLOCK_DURATION_CONFIG.max_block_duration - 10;
let eic_data = EICData {
eic_hash: declare_reward_supplier_eic_contract(),
eic_init_data: [
avg_block_duration.into(), min_block_duration.into(), max_block_duration.into(),
]
.span(),
};
let implementation_data = ImplementationData {
impl_hash: declare_reward_supplier_contract(),
eic_data: Option::Some(eic_data),
final: false,
};
start_cheat_block_timestamp_global(
block_timestamp: Time::now().add(delta: Time::days(count: 1)).into(),
);
upgrade_implementation(
contract_address: reward_supplier, :implementation_data, :upgrade_governor,
);

// Test.
let new_avg_block_duration = load_one_felt(
target: reward_supplier, storage_address: selector!("avg_block_duration"),
)
.try_into()
.unwrap();
assert!(new_avg_block_duration == avg_block_duration);
assert!(
reward_supplier_dispatcher
.get_block_duration_config() == BlockDurationConfig {
min_block_duration, max_block_duration,
},
);
}

#[test]
#[should_panic(expected: "EIC_LIB_CALL_FAILED")]
fn test_reward_supplier_eic_with_wrong_number_of_data_elements() {
let mut cfg: StakingInitConfig = Default::default();
general_contract_system_deployment(ref :cfg);
let reward_supplier = cfg.staking_contract_info.reward_supplier;
let upgrade_governor = cfg.test_info.upgrade_governor;
let eic_data = EICData {
eic_hash: declare_reward_supplier_eic_contract(), eic_init_data: [].span(),
};
let implementation_data = ImplementationData {
impl_hash: declare_reward_supplier_contract(),
eic_data: Option::Some(eic_data),
final: false,
};
start_cheat_block_timestamp_global(
block_timestamp: Time::now().add(delta: Time::days(count: 1)).into(),
);
upgrade_implementation(
contract_address: reward_supplier, :implementation_data, :upgrade_governor,
);
}

#[test]
#[should_panic(expected: "EIC_LIB_CALL_FAILED")]
fn test_reward_supplier_eic_invalid_avg_block_duration_less_than_min() {
let mut cfg: StakingInitConfig = Default::default();
general_contract_system_deployment(ref :cfg);
let reward_supplier = cfg.staking_contract_info.reward_supplier;
let upgrade_governor = cfg.test_info.upgrade_governor;
let avg_block_duration = 4;
let min_block_time = 5;
let max_block_time = 10;
let eic_data = EICData {
eic_hash: declare_reward_supplier_eic_contract(),
eic_init_data: [avg_block_duration.into(), min_block_time.into(), max_block_time.into()]
.span(),
Comment thread
cursor[bot] marked this conversation as resolved.
};
let implementation_data = ImplementationData {
impl_hash: declare_reward_supplier_contract(),
eic_data: Option::Some(eic_data),
final: false,
};
start_cheat_block_timestamp_global(
block_timestamp: Time::now().add(delta: Time::days(count: 1)).into(),
);
upgrade_implementation(
contract_address: reward_supplier, :implementation_data, :upgrade_governor,
);
}

#[test]
#[should_panic(expected: "EIC_LIB_CALL_FAILED")]
fn test_reward_supplier_eic_invalid_avg_block_duration_greater_than_max() {
let mut cfg: StakingInitConfig = Default::default();
general_contract_system_deployment(ref :cfg);
let reward_supplier = cfg.staking_contract_info.reward_supplier;
let upgrade_governor = cfg.test_info.upgrade_governor;
let avg_block_duration = 14;
let min_block_time = 5;
let max_block_time = 10;
let eic_data = EICData {
eic_hash: declare_reward_supplier_eic_contract(),
eic_init_data: [avg_block_duration.into(), min_block_time.into(), max_block_time.into()]
.span(),
};
let implementation_data = ImplementationData {
impl_hash: declare_reward_supplier_contract(),
eic_data: Option::Some(eic_data),
final: false,
};
start_cheat_block_timestamp_global(
block_timestamp: Time::now().add(delta: Time::days(count: 1)).into(),
);
upgrade_implementation(
contract_address: reward_supplier, :implementation_data, :upgrade_governor,
);
}

#[test]
#[should_panic(expected: "EIC_LIB_CALL_FAILED")]
fn test_reward_supplier_eic_invalid_min_zero() {
let mut cfg: StakingInitConfig = Default::default();
general_contract_system_deployment(ref :cfg);
let reward_supplier = cfg.staking_contract_info.reward_supplier;
let upgrade_governor = cfg.test_info.upgrade_governor;
let avg_block_duration = 5;
let min_block_time = 0;
let max_block_time = 10;
let eic_data = EICData {
eic_hash: declare_reward_supplier_eic_contract(),
eic_init_data: [avg_block_duration.into(), min_block_time.into(), max_block_time.into()]
.span(),
};
let implementation_data = ImplementationData {
impl_hash: declare_reward_supplier_contract(),
eic_data: Option::Some(eic_data),
final: false,
};
start_cheat_block_timestamp_global(
block_timestamp: Time::now().add(delta: Time::days(count: 1)).into(),
);
upgrade_implementation(
contract_address: reward_supplier, :implementation_data, :upgrade_governor,
);
}

#[test]
#[should_panic(expected: "EIC_LIB_CALL_FAILED")]
fn test_reward_supplier_eic_invalid_min_max() {
let mut cfg: StakingInitConfig = Default::default();
general_contract_system_deployment(ref :cfg);
let reward_supplier = cfg.staking_contract_info.reward_supplier;
let upgrade_governor = cfg.test_info.upgrade_governor;
let avg_block_duration = 5;
let min_block_time = 10;
let max_block_time = 9;
let eic_data = EICData {
eic_hash: declare_reward_supplier_eic_contract(),
eic_init_data: [avg_block_duration.into(), min_block_time.into(), max_block_time.into()]
.span(),
};
let implementation_data = ImplementationData {
impl_hash: declare_reward_supplier_contract(),
eic_data: Option::Some(eic_data),
final: false,
};
start_cheat_block_timestamp_global(
block_timestamp: Time::now().add(delta: Time::days(count: 1)).into(),
);
upgrade_implementation(
contract_address: reward_supplier, :implementation_data, :upgrade_governor,
);
}
13 changes: 13 additions & 0 deletions src/test_utils.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,11 @@ pub(crate) fn deploy_reward_supplier_contract(cfg: StakingInitConfig) -> Contrac
account: cfg.test_info.app_governor,
app_role_admin: cfg.test_info.app_role_admin,
);
set_account_as_upgrade_governor(
contract: reward_supplier_contract_address,
account: cfg.test_info.upgrade_governor,
governance_admin: cfg.test_info.governance_admin,
);
reward_supplier_contract_address
}

Expand Down Expand Up @@ -424,6 +429,10 @@ pub(crate) fn declare_pool_contract() -> ClassHash {
*snforge_std::declare("Pool").unwrap().contract_class().class_hash
}

pub(crate) fn declare_reward_supplier_contract() -> ClassHash {
*snforge_std::declare("RewardSupplier").unwrap().contract_class().class_hash
}

pub(crate) fn declare_staking_eic_contract() -> ClassHash {
*snforge_std::declare("StakingEIC").unwrap().contract_class().class_hash
}
Expand All @@ -432,6 +441,10 @@ pub(crate) fn declare_pool_eic_contract() -> ClassHash {
*snforge_std::declare("PoolEIC").unwrap().contract_class().class_hash
}

pub(crate) fn declare_reward_supplier_eic_contract() -> ClassHash {
*snforge_std::declare("RewardSupplierEIC").unwrap().contract_class().class_hash
}

/// Upgrades implementation of the given contract.
pub(crate) fn upgrade_implementation(
contract_address: ContractAddress,
Expand Down
Loading