diff --git a/src/book_manager.cairo b/src/book_manager.cairo index ac8dc8d..c939565 100644 --- a/src/book_manager.cairo +++ b/src/book_manager.cairo @@ -10,7 +10,6 @@ pub mod BookManager { use clober_cairo::interfaces::book_manager::IBookManager; use clober_cairo::interfaces::locker::{ILockerDispatcher, ILockerDispatcherTrait}; use clober_cairo::interfaces::params::{MakeParams, TakeParams, CancelParams, OrderInfo}; - use clober_cairo::components::lockers::LockersComponent; use clober_cairo::libraries::i257::{i257, I257Trait}; use clober_cairo::libraries::book_key::{BookKey, BookKeyTrait}; use clober_cairo::libraries::book::Book::{Book, BookTrait, Order}; @@ -19,8 +18,8 @@ pub mod BookManager { use clober_cairo::libraries::tick::{Tick, TickTrait}; use clober_cairo::libraries::hooks::{Hooks, HooksTrait}; use clober_cairo::libraries::hooks_caller::{HooksCaller, HooksCallerTrait}; + use clober_cairo::libraries::lockers::{Lockers, LockersTrait}; - component!(path: LockersComponent, storage: lockers, event: LockersEvent); component!(path: ERC721Component, storage: erc721, event: ERC721Event); component!(path: SRC5Component, storage: src5, event: SRC5Event); component!(path: OwnableComponent, storage: ownable, event: OwnableEvent); @@ -47,10 +46,6 @@ pub mod BookManager { #[abi(embed_v0)] impl SRC5Impl = SRC5Component::SRC5Impl; - #[abi(embed_v0)] - impl LockersImpl = LockersComponent::LockersImpl; - impl LockersInternalImpl = LockersComponent::InternalImpl; - #[storage] struct Storage { #[substorage(v0)] @@ -59,8 +54,7 @@ pub mod BookManager { erc721: ERC721Component::Storage, #[substorage(v0)] src5: SRC5Component::Storage, - #[substorage(v0)] - lockers: LockersComponent::Storage, + lockers: Lockers, hooks_caller: HooksCaller, currency_delta: Map<(ContractAddress, ContractAddress), i257>, contract_uri: ByteArray, @@ -80,8 +74,6 @@ pub mod BookManager { ERC721Event: ERC721Component::Event, #[flat] SRC5Event: SRC5Component::Event, - #[flat] - LockersEvent: LockersComponent::Event, Open: Open, Make: Make, Take: Take, @@ -201,7 +193,7 @@ pub mod BookManager { impl InternalImpl of InternalTrait { fn _check_locker(self: @ContractState) { let caller = get_caller_address(); - let locker = self.lockers.get_current_locker(); + let locker = self.lockers.read().get_current_locker(); let hook = self.hooks_caller.read().get_current_hook(); assert(caller == locker || caller == hook, Errors::INVALID_LOCKER); } @@ -211,14 +203,15 @@ pub mod BookManager { return; } - let locker = self.lockers.get_current_locker(); + let mut lockers = self.lockers.read(); + let locker = lockers.get_current_locker(); let next = self.currency_delta.read((locker, currency)) + delta; self.currency_delta.write((locker, currency), next); if (next.is_zero()) { - self.lockers.decrement_nonzero_delta_count(); + lockers.decrement_nonzero_delta_count(); } else if (next == delta) { - self.lockers.increment_nonzero_delta_count(); + lockers.increment_nonzero_delta_count(); } } @@ -268,6 +261,14 @@ pub mod BookManager { self.token_owed.read((owner, currency)) } + fn get_lock(self: @ContractState, i: u32) -> (ContractAddress, ContractAddress) { + self.lockers.read().get_lock(i) + } + + fn get_lock_data(self: @ContractState) -> (u32, u128) { + self.lockers.read().lock_data() + } + fn get_current_hook(self: @ContractState) -> ContractAddress { self.hooks_caller.read().get_current_hook() } @@ -370,7 +371,8 @@ pub mod BookManager { ) -> Span { // Add the locker to the stack let lock_caller = get_caller_address(); - self.lockers.push(locker, lock_caller); + let mut lockers = self.lockers.read(); + lockers.push(locker, lock_caller); // The locker does everything in this callback, including paying what they owe via calls // to settle @@ -378,9 +380,9 @@ pub mod BookManager { let result = locker_dispatcher.lock_acquired(lock_caller, data); // Remove the locker from the stack - self.lockers.pop(); + lockers.pop(); - let (length, nonzero_delta_count) = self.lockers.lock_data(); + let (length, nonzero_delta_count) = lockers.lock_data(); // @dev The locker must settle all currency balances to zero. assert(length > 0 || nonzero_delta_count == 0, Errors::CURRENCY_NOT_SETTLED); result diff --git a/src/components/lockers.cairo b/src/components/lockers.cairo deleted file mode 100644 index 8fee928..0000000 --- a/src/components/lockers.cairo +++ /dev/null @@ -1,102 +0,0 @@ -#[starknet::component] -pub mod LockersComponent { - use clober_cairo::utils::constants::ZERO_ADDRESS; - use clober_cairo::interfaces::lockers::ILockers; - use starknet::ContractAddress; - use starknet::storage::Map; - - #[storage] - struct Storage { - lockers: Map, // use Array, - lock_callers: Map, - length: u128, - non_zero_delta_count: u128 - } - - #[embeddable_as(LockersImpl)] - pub impl Lockers< - TContractState, +HasComponent - > of ILockers> { - fn get_lock( - self: @ComponentState, i: u128 - ) -> (ContractAddress, ContractAddress) { - (self.get_locker(i), self.get_lock_caller(i)) - } - - fn get_lock_data(self: @ComponentState) -> (u128, u128) { - self.lock_data() - } - } - - #[generate_trait] - pub impl InternalImpl< - TContractState, +HasComponent - > of InternalTrait { - fn push( - ref self: ComponentState, - locker: ContractAddress, - lock_caller: ContractAddress - ) { - let length = self.length.read(); - self.lockers.write(length, locker); - self.lock_callers.write(length, locker); - self.length.write(length + 1); - } - - fn pop(ref self: ComponentState) { - let length = self.length.read() - 1; - // assert(length > 0, 'LOCKER_POP_FAILED'); - - self.lockers.write(length, ZERO_ADDRESS()); - self.lock_callers.write(length, ZERO_ADDRESS()); - self.length.write(length); - } - - fn lock_data(self: @ComponentState) -> (u128, u128) { - let length = self.length.read(); - let non_zero_delta_count = self.non_zero_delta_count.read(); - (length, non_zero_delta_count) - } - - fn length(self: @ComponentState) -> u128 { - self.length.read() - } - - fn get_locker(self: @ComponentState, index: u128) -> ContractAddress { - self.lockers.read(index) - } - - fn get_lock_caller(self: @ComponentState, index: u128) -> ContractAddress { - self.lock_callers.read(index) - } - - fn get_current_locker(self: @ComponentState) -> ContractAddress { - let length = self.length.read(); - if length == 0 { - ZERO_ADDRESS() - } else { - self.lockers.read(length - 1) - } - } - - fn get_current_lock_caller(self: @ComponentState) -> ContractAddress { - let length = self.length.read(); - if length == 0 { - ZERO_ADDRESS() - } else { - self.lock_callers.read(length - 1) - } - } - - fn increment_nonzero_delta_count(ref self: ComponentState) { - let non_zero_delta_count = self.non_zero_delta_count.read(); - self.non_zero_delta_count.write(non_zero_delta_count + 1); - } - - fn decrement_nonzero_delta_count(ref self: ComponentState) { - let non_zero_delta_count = self.non_zero_delta_count.read(); - // assert(non_zero_delta_count > 0, 'NON_ZERO_DELTA_COUNT_DECREMENT_FAILED'); - self.non_zero_delta_count.write(non_zero_delta_count - 1); - } - } -} diff --git a/src/interfaces/book_manager.cairo b/src/interfaces/book_manager.cairo index 55f1a0b..cdca9da 100644 --- a/src/interfaces/book_manager.cairo +++ b/src/interfaces/book_manager.cairo @@ -17,6 +17,8 @@ pub trait IBookManager { fn token_owed( self: @TContractState, owner: ContractAddress, currency: ContractAddress, token_id: felt252 ) -> u256; + fn get_lock(self: @TContractState, i: u32) -> (ContractAddress, ContractAddress); + fn get_lock_data(self: @TContractState) -> (u32, u128); fn get_current_hook(self: @TContractState) -> ContractAddress; fn get_hook(self: @TContractState, i: u32) -> ContractAddress; fn get_book_key(self: @TContractState, book_id: felt252) -> BookKey; diff --git a/src/lib.cairo b/src/lib.cairo index 913a7d1..0b9acd2 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -1,7 +1,3 @@ -pub mod components { - pub mod lockers; -} - pub mod interfaces { pub mod book_manager; pub mod locker; @@ -13,15 +9,16 @@ pub mod libraries { pub mod book_key; pub mod book; pub mod fee_policy; - pub mod hooks; pub mod hooks_caller; + pub mod hooks; + pub mod i257; + pub mod lockers; pub mod order_id; - pub mod tick; - pub mod tick_bitmap; pub mod segmented_segment_tree; pub mod storage_map; + pub mod tick_bitmap; + pub mod tick; pub mod total_claimable_map; - pub mod i257; } pub mod utils { diff --git a/src/libraries/lockers.cairo b/src/libraries/lockers.cairo new file mode 100644 index 0000000..6e5124c --- /dev/null +++ b/src/libraries/lockers.cairo @@ -0,0 +1,126 @@ +use starknet::{ContractAddress, Store, SyscallResultTrait, SyscallResult}; +use starknet::storage::Map; +use starknet::storage_access::{ + StorageBaseAddress, storage_address_from_base, storage_base_address_from_felt252 +}; +use clober_cairo::utils::constants::{ZERO_ADDRESS, TWO_POW_32}; +use clober_cairo::interfaces::lockers::ILockers; +use clober_cairo::libraries::storage_map::{Felt252Map, Felt252MapTrait}; + +const NOT_IMPLEMENTED: felt252 = 'Not implemented'; + +#[derive(Copy, Drop)] +pub struct Lockers { + lockers: Felt252Map<(ContractAddress, ContractAddress)> +} + +impl StoreLockers of Store { + #[inline(always)] + fn read(address_domain: u32, base: StorageBaseAddress) -> SyscallResult { + SyscallResult::Ok(Lockers { lockers: Felt252MapTrait::fetch(address_domain, base), }) + } + + #[inline(always)] + fn write(address_domain: u32, base: StorageBaseAddress, value: Lockers) -> SyscallResult<()> { + SyscallResult::Err(array![NOT_IMPLEMENTED]) + } + + #[inline(always)] + fn read_at_offset( + address_domain: u32, base: StorageBaseAddress, offset: u8 + ) -> SyscallResult { + SyscallResult::Err(array![NOT_IMPLEMENTED]) + } + + #[inline(always)] + fn write_at_offset( + address_domain: u32, base: StorageBaseAddress, offset: u8, value: Lockers + ) -> SyscallResult<()> { + SyscallResult::Err(array![NOT_IMPLEMENTED]) + } + + #[inline(always)] + fn size() -> u8 { + 1_u8 + } +} + +#[generate_trait] +pub impl LockersImpl of LockersTrait { + fn update_data(ref self: Lockers, length: u32, non_zero_delta_count: u128) { + let packed: u256 = (non_zero_delta_count * TWO_POW_32.into() + length.into()).into(); + let (address_domain, base) = self.lockers.get_base_storage_address(); + Store::write(address_domain, base, packed.into()).unwrap_syscall(); + } + + fn push(ref self: Lockers, locker: ContractAddress, lock_caller: ContractAddress) { + let (length, non_zero_delta_count) = self.lock_data(); + self.lockers.write_at(length.into(), (locker, lock_caller)); + self.update_data(length + 1, non_zero_delta_count); + } + + fn pop(ref self: Lockers) { + let (length, non_zero_delta_count) = self.lock_data(); + assert(length > 0, 'LOCKER_POP_FAILED'); + + let new_length = length - 1; + self.lockers.write_at(new_length.into(), (ZERO_ADDRESS(), ZERO_ADDRESS())); + self.update_data(new_length, non_zero_delta_count); + } + + fn lock_data(self: @Lockers) -> (u32, u128) { + let (address_domain, base) = self.lockers.get_base_storage_address(); + let packed: felt252 = Store::read(address_domain, base).unwrap_syscall(); + let packed_u256: u256 = packed.into(); + let length: u32 = (packed_u256 & TWO_POW_32.into() - 1).try_into().unwrap(); + let non_zero_delta_count: u128 = (packed_u256 / TWO_POW_32.into()).try_into().unwrap(); + (length, non_zero_delta_count) + } + + fn length(self: @Lockers) -> u32 { + let (length, _) = self.lock_data(); + length + } + + fn get_lock(self: @Lockers, index: u32) -> (ContractAddress, ContractAddress) { + self.lockers.read_at(index.into()) + } + + fn get_locker(self: @Lockers, index: u32) -> ContractAddress { + let (locker, _) = self.lockers.read_at(index.into()); + locker + } + + fn get_lock_caller(self: @Lockers, index: u32) -> ContractAddress { + let (_, locker_caller) = self.lockers.read_at(index.into()); + locker_caller + } + + fn get_current_locker(self: @Lockers) -> ContractAddress { + let length = self.length(); + if length == 0 { + ZERO_ADDRESS() + } else { + self.get_locker(length - 1) + } + } + + fn get_current_lock_caller(self: @Lockers) -> ContractAddress { + let length = self.length(); + if length == 0 { + ZERO_ADDRESS() + } else { + self.get_lock_caller(length - 1) + } + } + + fn increment_nonzero_delta_count(ref self: Lockers) { + let (length, non_zero_delta_count) = self.lock_data(); + self.update_data(length, non_zero_delta_count + 1); + } + + fn decrement_nonzero_delta_count(ref self: Lockers) { + let (length, non_zero_delta_count) = self.lock_data(); + self.update_data(length, non_zero_delta_count - 1); + } +}