diff --git a/Makefile b/Makefile index 22937f60b..1497e7874 100644 --- a/Makefile +++ b/Makefile @@ -224,6 +224,11 @@ test-integration-contracts: build-ts env-devnet-hardhat cd packages-ts/starknet/ && \ yarn test +.PHONY test-examples +test-examples: + cd ./examples/contracts/aggregator_consumer && \ + snforge test + .PHONY: test-integration-gauntlet # TODO: fix example # cd packages-ts/starknet-gauntlet-example/ && \ diff --git a/examples/contracts/aggregator_consumer/Scarb.lock b/examples/contracts/aggregator_consumer/Scarb.lock index 80cccaf0d..cd4104701 100644 --- a/examples/contracts/aggregator_consumer/Scarb.lock +++ b/examples/contracts/aggregator_consumer/Scarb.lock @@ -6,7 +6,6 @@ name = "aggregator_consumer" version = "0.1.0" dependencies = [ "chainlink", - "openzeppelin", "snforge_std", ] diff --git a/examples/contracts/aggregator_consumer/Scarb.toml b/examples/contracts/aggregator_consumer/Scarb.toml index 233211981..3e4b516d4 100644 --- a/examples/contracts/aggregator_consumer/Scarb.toml +++ b/examples/contracts/aggregator_consumer/Scarb.toml @@ -6,15 +6,16 @@ [package] name = "aggregator_consumer" version = "0.1.0" -edition = "2023_11" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html [dependencies] -openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.9.0" } snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.18.0" } chainlink = { path = "../../../contracts" } -starknet = "2.5.4" [[target.starknet-contract]] casm = true +build-external-contracts = [ + "chainlink::emergency::sequencer_uptime_feed::SequencerUptimeFeed", + "chainlink::ocr2::mocks::mock_aggregator::MockAggregator", +] diff --git a/examples/contracts/aggregator_consumer/src/emergency.cairo b/examples/contracts/aggregator_consumer/src/emergency.cairo deleted file mode 100644 index 870a7f708..000000000 --- a/examples/contracts/aggregator_consumer/src/emergency.cairo +++ /dev/null @@ -1 +0,0 @@ -pub mod sequencer_uptime_feed; diff --git a/examples/contracts/aggregator_consumer/src/emergency/sequencer_uptime_feed.cairo b/examples/contracts/aggregator_consumer/src/emergency/sequencer_uptime_feed.cairo deleted file mode 100644 index 7aebf16fc..000000000 --- a/examples/contracts/aggregator_consumer/src/emergency/sequencer_uptime_feed.cairo +++ /dev/null @@ -1,287 +0,0 @@ -use starknet::EthAddress; -#[starknet::interface] -pub trait ISequencerUptimeFeed { - fn l1_sender(self: @TContractState) -> EthAddress; - fn set_l1_sender(ref self: TContractState, address: EthAddress); -} - -#[starknet::contract] -mod SequencerUptimeFeed { - use starknet::EthAddress; - use starknet::ContractAddress; - use starknet::SyscallResult; - use starknet::syscalls::storage_read_syscall; - use starknet::syscalls::storage_write_syscall; - use starknet::storage_access::storage_address_from_base_and_offset; - use starknet::class_hash::ClassHash; - - use core::option::OptionTrait; - use core::traits::TryInto; - - use openzeppelin::access::ownable::ownable::OwnableComponent; - - use aggregator_consumer::libraries::access_control::{AccessControlComponent, IAccessController}; - use aggregator_consumer::libraries::access_control::AccessControlComponent::InternalTrait as AccessControlInternalTrait; - use chainlink::libraries::type_and_version::ITypeAndVersion; - use chainlink::ocr2::aggregator::Round; - use chainlink::ocr2::aggregator::IAggregator; - use chainlink::ocr2::aggregator::{Transmission}; - use chainlink::libraries::upgradeable::Upgradeable; - - component!(path: OwnableComponent, storage: ownable, event: OwnableEvent); - component!(path: AccessControlComponent, storage: access_control, event: AccessControlEvent); - - #[abi(embed_v0)] - impl OwnableImpl = OwnableComponent::OwnableTwoStepImpl; - impl OwnableInternalImpl = OwnableComponent::InternalImpl; - - #[abi(embed_v0)] - impl AccessControlImpl = - AccessControlComponent::AccessControlImpl; - impl AccessControlInternalImpl = AccessControlComponent::InternalImpl; - - #[storage] - struct Storage { - #[substorage(v0)] - ownable: OwnableComponent::Storage, - #[substorage(v0)] - access_control: AccessControlComponent::Storage, - // l1 sender is an starknet validator ethereum address - _l1_sender: felt252, - // maps round id to round transmission - _round_transmissions: LegacyMap, - _latest_round_id: u128, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - #[flat] - OwnableEvent: OwnableComponent::Event, - #[flat] - AccessControlEvent: AccessControlComponent::Event, - RoundUpdated: RoundUpdated, - NewRound: NewRound, - AnswerUpdated: AnswerUpdated, - UpdateIgnored: UpdateIgnored, - L1SenderTransferred: L1SenderTransferred, - } - - #[derive(Drop, starknet::Event)] - struct RoundUpdated { - status: u128, - updated_at: u64 - } - - #[derive(Drop, starknet::Event)] - struct NewRound { - round_id: u128, - started_by: ContractAddress, - started_at: u64 - } - - #[derive(Drop, starknet::Event)] - struct AnswerUpdated { - current: u128, - round_id: u128, - timestamp: u64 - } - - #[derive(Drop, starknet::Event)] - struct UpdateIgnored { - latest_status: u128, - latest_timestamp: u64, - incoming_status: u128, - incoming_timestamp: u64 - } - - #[derive(Drop, starknet::Event)] - struct L1SenderTransferred { - from_address: EthAddress, - to_address: EthAddress - } - - #[abi(embed_v0)] - impl TypeAndVersion of ITypeAndVersion { - fn type_and_version(self: @ContractState) -> felt252 { - 'SequencerUptimeFeed 1.0.0' - } - } - - #[abi(embed_v0)] - impl AggregatorImpl of IAggregator { - fn latest_round_data(self: @ContractState) -> Round { - self._require_read_access(); - let latest_round_id = self._latest_round_id.read(); - let round_transmission = self._round_transmissions.read(latest_round_id); - Round { - round_id: latest_round_id.into(), - answer: round_transmission.answer, - block_num: round_transmission.block_num, - started_at: round_transmission.observation_timestamp, - updated_at: round_transmission.transmission_timestamp, - } - } - - fn round_data(self: @ContractState, round_id: u128) -> Round { - self._require_read_access(); - assert(round_id < self._latest_round_id.read(), 'invalid round id'); - let round_transmission = self._round_transmissions.read(round_id); - Round { - round_id: round_id.into(), - answer: round_transmission.answer, - block_num: round_transmission.block_num, - started_at: round_transmission.observation_timestamp, - updated_at: round_transmission.transmission_timestamp, - } - } - - fn description(self: @ContractState) -> felt252 { - 'L2 Sequencer Uptime Status Feed' - } - - fn decimals(self: @ContractState) -> u8 { - 0_u8 - } - } - - #[constructor] - fn constructor(ref self: ContractState, initial_status: u128, owner_address: ContractAddress) { - self._initializer(initial_status, owner_address); - } - - #[l1_handler] - fn update_status(ref self: ContractState, from_address: felt252, status: u128, timestamp: u64) { - assert(self._l1_sender.read() == from_address, 'EXPECTED_FROM_BRIDGE_ONLY'); - - let latest_round_id = self._latest_round_id.read(); - let latest_round = self._round_transmissions.read(latest_round_id); - - if timestamp <= latest_round.observation_timestamp { - self - .emit( - Event::UpdateIgnored( - UpdateIgnored { - latest_status: latest_round.answer, - latest_timestamp: latest_round.transmission_timestamp, - incoming_status: status, - incoming_timestamp: timestamp - } - ) - ); - return (); - } - - if latest_round.answer == status { - self._update_round(latest_round_id, latest_round); - } else { - // only increment round when status flips - let round_id = latest_round_id + 1_u128; - self._record_round(round_id, status, timestamp); - } - } - - #[abi(embed_v0)] - impl SequencerUptimeFeedImpl of super::ISequencerUptimeFeed { - fn set_l1_sender(ref self: ContractState, address: EthAddress) { - self.ownable.assert_only_owner(); - - // TODO: - // assert(!address.is_zero(), '0 address not allowed'); - - let old_address = self._l1_sender.read(); - - if old_address != address.into() { - self._l1_sender.write(address.into()); - self - .emit( - Event::L1SenderTransferred( - L1SenderTransferred { - from_address: old_address.try_into().unwrap(), to_address: address - } - ) - ); - } - } - - fn l1_sender(self: @ContractState) -> EthAddress { - self._l1_sender.read().try_into().unwrap() - } - } - - /// - /// Upgradeable - /// - - #[abi(embed_v0)] - fn upgrade(ref self: ContractState, new_impl: ClassHash) { - self.ownable.assert_only_owner(); - Upgradeable::upgrade(new_impl) - } - - /// - /// Internals - /// - - #[generate_trait] - impl Internals of InternalTrait { - fn _require_read_access(self: @ContractState) { - let sender = starknet::get_caller_address(); - self.access_control.check_read_access(sender); - } - - fn _initializer( - ref self: ContractState, initial_status: u128, owner_address: ContractAddress - ) { - self.ownable.initializer(owner_address); - self.access_control.initializer(); - let round_id = 1_u128; - let timestamp = starknet::get_block_timestamp(); - self._record_round(round_id, initial_status, timestamp); - } - - fn _record_round(ref self: ContractState, round_id: u128, status: u128, timestamp: u64) { - self._latest_round_id.write(round_id); - let block_info = starknet::get_block_info().unbox(); - let block_number = block_info.block_number; - let block_timestamp = block_info.block_timestamp; - - let round = Transmission { - answer: status, - block_num: block_number, - observation_timestamp: timestamp, - transmission_timestamp: block_timestamp, - }; - self._round_transmissions.write(round_id, round); - - let sender = starknet::get_caller_address(); - - self - .emit( - Event::NewRound( - NewRound { round_id: round_id, started_by: sender, started_at: timestamp } - ) - ); - self - .emit( - Event::AnswerUpdated( - AnswerUpdated { current: status, round_id: round_id, timestamp: timestamp } - ) - ); - } - - fn _update_round(ref self: ContractState, round_id: u128, mut round: Transmission) { - round.transmission_timestamp = starknet::get_block_timestamp(); - self._round_transmissions.write(round_id, round); - - self - .emit( - Event::RoundUpdated( - RoundUpdated { - status: round.answer, updated_at: round.transmission_timestamp - } - ) - ); - } - } -} diff --git a/examples/contracts/aggregator_consumer/src/lib.cairo b/examples/contracts/aggregator_consumer/src/lib.cairo index cc02a54bd..ea174388f 100644 --- a/examples/contracts/aggregator_consumer/src/lib.cairo +++ b/examples/contracts/aggregator_consumer/src/lib.cairo @@ -1,5 +1,2 @@ -pub mod libraries; -pub mod emergency; -pub mod mocks; pub mod ocr2; diff --git a/examples/contracts/aggregator_consumer/src/libraries.cairo b/examples/contracts/aggregator_consumer/src/libraries.cairo deleted file mode 100644 index 18e237199..000000000 --- a/examples/contracts/aggregator_consumer/src/libraries.cairo +++ /dev/null @@ -1 +0,0 @@ -pub mod access_control; diff --git a/examples/contracts/aggregator_consumer/src/libraries/access_control.cairo b/examples/contracts/aggregator_consumer/src/libraries/access_control.cairo deleted file mode 100644 index a44fee769..000000000 --- a/examples/contracts/aggregator_consumer/src/libraries/access_control.cairo +++ /dev/null @@ -1,152 +0,0 @@ -use starknet::ContractAddress; -#[starknet::interface] -pub trait IAccessController { - fn has_access(self: @TContractState, user: ContractAddress, data: Array) -> bool; - fn has_read_access(self: @TContractState, user: ContractAddress, data: Array) -> bool; - fn add_access(ref self: TContractState, user: ContractAddress); - fn remove_access(ref self: TContractState, user: ContractAddress); - fn enable_access_check(ref self: TContractState); - fn disable_access_check(ref self: TContractState); -} - -// Requires Ownable subcomponent. -#[starknet::component] -pub mod AccessControlComponent { - use starknet::ContractAddress; - use starknet::class_hash::ClassHash; - - use openzeppelin::access::ownable::ownable::OwnableComponent; - - use OwnableComponent::InternalImpl as OwnableInternalImpl; - - #[storage] - struct Storage { - _check_enabled: bool, - _access_list: LegacyMap, - } - - #[event] - #[derive(Drop, starknet::Event)] - pub enum Event { - AddedAccess: AddedAccess, - RemovedAccess: RemovedAccess, - AccessControlEnabled: AccessControlEnabled, - AccessControlDisabled: AccessControlDisabled, - } - - #[derive(Drop, starknet::Event)] - struct AddedAccess { - user: ContractAddress - } - - #[derive(Drop, starknet::Event)] - struct RemovedAccess { - user: ContractAddress - } - - #[derive(Drop, starknet::Event)] - struct AccessControlEnabled {} - - #[derive(Drop, starknet::Event)] - struct AccessControlDisabled {} - - #[embeddable_as(AccessControlImpl)] - pub impl AccessControl< - TContractState, - +HasComponent, - impl Ownable: OwnableComponent::HasComponent, - +Drop, - > of super::IAccessController> { - fn has_access( - self: @ComponentState, user: ContractAddress, data: Array - ) -> bool { - let has_access = self._access_list.read(user); - if has_access { - return true; - } - - let check_enabled = self._check_enabled.read(); - if !check_enabled { - return true; - } - - false - } - - fn has_read_access( - self: @ComponentState, user: ContractAddress, data: Array - ) -> bool { - let _has_access = self.has_access(user, data); - if _has_access { - return true; - } - - // TODO: - // NOTICE: read access is granted to direct calls, to enable off-chain reads. - // if user.is_zero() { - // return true; - //} - - false - } - - fn add_access(ref self: ComponentState, user: ContractAddress) { - get_dep_component!(@self, Ownable).assert_only_owner(); - let has_access = self._access_list.read(user); - if !has_access { - self._access_list.write(user, true); - self.emit(Event::AddedAccess(AddedAccess { user: user })); - } - } - - fn remove_access(ref self: ComponentState, user: ContractAddress) { - get_dep_component!(@self, Ownable).assert_only_owner(); - let has_access = self._access_list.read(user); - if has_access { - self._access_list.write(user, false); - self.emit(Event::RemovedAccess(RemovedAccess { user: user })); - } - } - - fn enable_access_check(ref self: ComponentState) { - get_dep_component!(@self, Ownable).assert_only_owner(); - let check_enabled = self._check_enabled.read(); - if !check_enabled { - self._check_enabled.write(true); - self.emit(Event::AccessControlEnabled(AccessControlEnabled {})); - } - } - - fn disable_access_check(ref self: ComponentState) { - get_dep_component!(@self, Ownable).assert_only_owner(); - let check_enabled = self._check_enabled.read(); - if check_enabled { - self._check_enabled.write(false); - self.emit(Event::AccessControlDisabled(AccessControlDisabled {})); - } - } - } - - #[generate_trait] - pub impl InternalImpl< - TContractState, - +HasComponent, - impl Ownable: OwnableComponent::HasComponent, - +Drop, - > of InternalTrait { - fn initializer(ref self: ComponentState) { - self._check_enabled.write(true); - self.emit(Event::AccessControlEnabled(AccessControlEnabled {})); - } - - fn check_access(self: @ComponentState, user: ContractAddress) { - let allowed = AccessControl::has_access(self, user, ArrayTrait::new()); - assert(allowed, 'user does not have access'); - } - - fn check_read_access(self: @ComponentState, user: ContractAddress) { - let allowed = AccessControl::has_read_access(self, user, ArrayTrait::new()); - assert(allowed, 'user does not have read access'); - } - } -} diff --git a/examples/contracts/aggregator_consumer/src/mocks.cairo b/examples/contracts/aggregator_consumer/src/mocks.cairo deleted file mode 100644 index b42bbb0d5..000000000 --- a/examples/contracts/aggregator_consumer/src/mocks.cairo +++ /dev/null @@ -1 +0,0 @@ -pub mod mock_aggregator; diff --git a/examples/contracts/aggregator_consumer/src/mocks/mock_aggregator.cairo b/examples/contracts/aggregator_consumer/src/mocks/mock_aggregator.cairo deleted file mode 100644 index 36b220181..000000000 --- a/examples/contracts/aggregator_consumer/src/mocks/mock_aggregator.cairo +++ /dev/null @@ -1,121 +0,0 @@ -#[starknet::interface] -pub trait IMockAggregator { - fn set_latest_round_data( - ref self: TContractState, - answer: u128, - block_num: u64, - observation_timestamp: u64, - transmission_timestamp: u64 - ); -} - -#[starknet::contract] -mod MockAggregator { - use starknet::contract_address_const; - use core::panic_with_felt252; - - use chainlink::libraries::type_and_version::ITypeAndVersion; - - use chainlink::ocr2::aggregator::Aggregator::{Transmission, NewTransmission}; - use chainlink::ocr2::aggregator::IAggregator; - use chainlink::ocr2::aggregator::Round; - - #[event] - use chainlink::ocr2::aggregator::Aggregator::Event; - - #[storage] - struct Storage { - _transmissions: LegacyMap, - _latest_aggregator_round_id: u128, - _decimals: u8 - } - - #[constructor] - fn constructor(ref self: ContractState, decimals: u8) { - self._decimals.write(decimals); - } - - #[abi(embed_v0)] - impl MockImpl of super::IMockAggregator { - fn set_latest_round_data( - ref self: ContractState, - answer: u128, - block_num: u64, - observation_timestamp: u64, - transmission_timestamp: u64 - ) { - let new_round_id = self._latest_aggregator_round_id.read() + 1_u128; - self - ._transmissions - .write( - new_round_id, - Transmission { - answer: answer, - block_num: block_num, - observation_timestamp: observation_timestamp, - transmission_timestamp: transmission_timestamp - } - ); - - let mut observations = ArrayTrait::new(); - observations.append(2_u128); - observations.append(3_u128); - - self._latest_aggregator_round_id.write(new_round_id); - - self - .emit( - Event::NewTransmission( - NewTransmission { - round_id: new_round_id, - answer: answer, - transmitter: contract_address_const::<42>(), - observation_timestamp: observation_timestamp, - observers: 3, - observations: observations, - juels_per_fee_coin: 18_u128, - gas_price: 1_u128, - config_digest: 777, - epoch_and_round: 20_u64, - reimbursement: 100_u128 - } - ) - ); - } - } - - #[abi(embed_v0)] - impl TypeAndVersionImpl of ITypeAndVersion { - fn type_and_version(self: @ContractState) -> felt252 { - 'mock_aggregator.cairo 1.0.0' - } - } - - #[abi(embed_v0)] - impl Aggregator of IAggregator { - fn round_data(self: @ContractState, round_id: u128) -> Round { - panic_with_felt252('unimplemented') - } - - fn latest_round_data(self: @ContractState) -> Round { - let latest_round_id = self._latest_aggregator_round_id.read(); - let transmission = self._transmissions.read(latest_round_id); - - Round { - round_id: latest_round_id.into(), - answer: transmission.answer, - block_num: transmission.block_num, - started_at: transmission.observation_timestamp, - updated_at: transmission.transmission_timestamp - } - } - - fn decimals(self: @ContractState) -> u8 { - self._decimals.read() - } - - fn description(self: @ContractState) -> felt252 { - 'mock' - } - } -} diff --git a/examples/contracts/aggregator_consumer/src/ocr2/consumer.cairo b/examples/contracts/aggregator_consumer/src/ocr2/consumer.cairo index f0448b309..bf67f2a3c 100644 --- a/examples/contracts/aggregator_consumer/src/ocr2/consumer.cairo +++ b/examples/contracts/aggregator_consumer/src/ocr2/consumer.cairo @@ -6,12 +6,14 @@ pub trait IAggregatorConsumer { #[starknet::contract] mod AggregatorConsumer { - use chainlink::ocr2::aggregator_proxy::IAggregatorDispatcherTrait; - use chainlink::ocr2::aggregator_proxy::IAggregatorDispatcher; - use chainlink::ocr2::aggregator_proxy::IAggregator; - use chainlink::ocr2::aggregator::Round; use starknet::ContractAddress; + use chainlink::ocr2::aggregator::Round; + + use chainlink::ocr2::aggregator_proxy::IAggregator; + use chainlink::ocr2::aggregator_proxy::IAggregatorDispatcher; + use chainlink::ocr2::aggregator_proxy::IAggregatorDispatcherTrait; + #[storage] struct Storage { _ocr_address: ContractAddress, diff --git a/examples/contracts/aggregator_consumer/src/ocr2/price_consumer.cairo b/examples/contracts/aggregator_consumer/src/ocr2/price_consumer.cairo index ca8c5cec5..9f2d2e381 100644 --- a/examples/contracts/aggregator_consumer/src/ocr2/price_consumer.cairo +++ b/examples/contracts/aggregator_consumer/src/ocr2/price_consumer.cairo @@ -5,10 +5,10 @@ pub trait IAggregatorPriceConsumer { #[starknet::contract] mod AggregatorPriceConsumer { - use core::starknet::ContractAddress; - use core::starknet::get_block_info; - use core::box::BoxTrait; - use core::traits::Into; + use box::BoxTrait; + use starknet::ContractAddress; + use zeroable::Zeroable; + use traits::Into; use chainlink::ocr2::aggregator::Round; use chainlink::ocr2::aggregator_proxy::IAggregator; @@ -30,6 +30,8 @@ mod AggregatorPriceConsumer { uptime_feed_address: ContractAddress, aggregator_address: ContractAddress ) { + assert(!uptime_feed_address.is_zero(), 'uptime feed is 0'); + assert(!aggregator_address.is_zero(), 'aggregator is 0'); self._uptime_feed_address.write(uptime_feed_address); self._aggregator_address.write(aggregator_address); } @@ -48,7 +50,7 @@ mod AggregatorPriceConsumer { fn assert_sequencer_healthy(self: @ContractState) { let round = IAggregatorDispatcher { contract_address: self._uptime_feed_address.read() } .latest_round_data(); - let timestamp = get_block_info().unbox().block_timestamp; + let timestamp = starknet::get_block_info().unbox().block_timestamp; // After 60 sec the report is considered stale let report_stale = timestamp - round.updated_at > 60_u64; diff --git a/examples/contracts/aggregator_consumer/tests/test_consumer.cairo b/examples/contracts/aggregator_consumer/tests/test_consumer.cairo index 47d48b9fa..1bb3b4fe4 100644 --- a/examples/contracts/aggregator_consumer/tests/test_consumer.cairo +++ b/examples/contracts/aggregator_consumer/tests/test_consumer.cairo @@ -1,7 +1,8 @@ use snforge_std::{declare, ContractClassTrait}; -use aggregator_consumer::mocks::mock_aggregator::IMockAggregatorDispatcherTrait; -use aggregator_consumer::mocks::mock_aggregator::IMockAggregatorDispatcher; +use chainlink::ocr2::mocks::mock_aggregator::IMockAggregatorDispatcherTrait; +use chainlink::ocr2::mocks::mock_aggregator::IMockAggregatorDispatcher; + use aggregator_consumer::ocr2::consumer::IAggregatorConsumerDispatcherTrait; use aggregator_consumer::ocr2::consumer::IAggregatorConsumerDispatcher; diff --git a/examples/contracts/aggregator_consumer/tests/test_price_consumer_with_sequencer.cairo b/examples/contracts/aggregator_consumer/tests/test_price_consumer_with_sequencer.cairo index 17de9dd35..cd61f77fc 100644 --- a/examples/contracts/aggregator_consumer/tests/test_price_consumer_with_sequencer.cairo +++ b/examples/contracts/aggregator_consumer/tests/test_price_consumer_with_sequencer.cairo @@ -1,13 +1,14 @@ use snforge_std::{declare, ContractClassTrait, start_prank, stop_prank, CheatTarget}; -use aggregator_consumer::emergency::sequencer_uptime_feed::ISequencerUptimeFeedDispatcherTrait; -use aggregator_consumer::emergency::sequencer_uptime_feed::ISequencerUptimeFeedDispatcher; +use chainlink::emergency::sequencer_uptime_feed::ISequencerUptimeFeedDispatcherTrait; +use chainlink::emergency::sequencer_uptime_feed::ISequencerUptimeFeedDispatcher; +use chainlink::libraries::access_control::IAccessControllerDispatcherTrait; +use chainlink::libraries::access_control::IAccessControllerDispatcher; +use chainlink::ocr2::mocks::mock_aggregator::IMockAggregatorDispatcherTrait; +use chainlink::ocr2::mocks::mock_aggregator::IMockAggregatorDispatcher; + use aggregator_consumer::ocr2::price_consumer::IAggregatorPriceConsumerDispatcherTrait; use aggregator_consumer::ocr2::price_consumer::IAggregatorPriceConsumerDispatcher; -use aggregator_consumer::libraries::access_control::IAccessControllerDispatcherTrait; -use aggregator_consumer::libraries::access_control::IAccessControllerDispatcher; -use aggregator_consumer::mocks::mock_aggregator::IMockAggregatorDispatcherTrait; -use aggregator_consumer::mocks::mock_aggregator::IMockAggregatorDispatcher; use starknet::contract_address_const; use starknet::get_caller_address;