Skip to content

Commit ddb1d9e

Browse files
committed
chore: partial read for asset balances
1 parent 8254504 commit ddb1d9e

2 files changed

Lines changed: 132 additions & 9 deletions

File tree

workspace/apps/perpetuals/contracts/src/core/components/positions/positions.cairo

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ pub mod Positions {
2323
use perpetuals::core::types::balance::Balance;
2424
use perpetuals::core::types::funding::calculate_funding;
2525
use perpetuals::core::types::position::{
26-
AssetBalance, POSITION_VERSION, Position, PositionData, PositionDiff, PositionId,
27-
PositionMutableTrait, PositionTrait,
26+
AssetBalance, OptionAssetBalanceReadAccessTrait, POSITION_VERSION, Position, PositionData,
27+
PositionDiff, PositionId, PositionMutableTrait, PositionTrait,
2828
};
2929
use perpetuals::core::types::set_owner_account::SetOwnerAccountArgs;
3030
use perpetuals::core::types::set_public_key::SetPublicKeyArgs;
@@ -45,7 +45,8 @@ pub mod Positions {
4545
use starkware_utils::math::utils::have_same_sign;
4646
use starkware_utils::signature::stark::{PublicKey, Signature};
4747
use starkware_utils::storage::iterable_map::{
48-
IterableMapIntoIterImpl, IterableMapReadAccessImpl, IterableMapWriteAccessImpl,
48+
IterableMapIntoIterImpl, IterableMapReadAccessImpl, IterableMapTrait,
49+
IterableMapWriteAccessImpl,
4950
};
5051
use starkware_utils::storage::utils::AddToStorage;
5152
use starkware_utils::time::time::{Timestamp, validate_expiration};
@@ -514,10 +515,10 @@ pub mod Positions {
514515
position: StoragePath<Position>,
515516
synthetic_id: AssetId,
516517
) -> Balance {
517-
if let Option::Some(synthetic) = position.asset_balances.read(synthetic_id) {
518-
synthetic.balance
519-
} else {
520-
0_i64.into()
518+
let entry = position.asset_balances.pointer(synthetic_id);
519+
match OptionAssetBalanceReadAccessTrait::get_balance(:entry) {
520+
Option::None => 0_i64.into(),
521+
Option::Some(balance) => balance,
521522
}
522523
}
523524

workspace/apps/perpetuals/contracts/src/core/types/position.cairo

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ use perpetuals::core::types::asset::AssetId;
33
use perpetuals::core::types::asset::synthetic::{AssetBalanceDiffEnriched, AssetBalanceInfo};
44
use perpetuals::core::types::balance::{Balance, BalanceDiff};
55
use perpetuals::core::types::funding::FundingIndex;
6-
use starknet::ContractAddress;
7-
use starknet::storage::{Mutable, StoragePath, StoragePointerReadAccess};
6+
use starknet::storage::{Mutable, StoragePath, StoragePointer0Offset, StoragePointerReadAccess};
7+
use starknet::storage_access::storage_address_from_base_and_offset;
8+
use starknet::syscalls::storage_read_syscall;
9+
use starknet::{ContractAddress, SyscallResultTrait};
810
use starkware_utils::signature::stark::PublicKey;
911
use starkware_utils::storage::iterable_map::{
1012
IterableMap, IterableMapIntoIterImpl, IterableMapReadAccessImpl, IterableMapWriteAccessImpl,
1113
};
1214

15+
1316
pub const POSITION_VERSION: u8 = 1;
1417

1518
#[starknet::storage_node]
@@ -148,3 +151,122 @@ pub impl PositionMutableImpl of PositionMutableTrait {
148151
self.version.read()
149152
}
150153
}
154+
155+
#[generate_trait]
156+
pub impl OptionAssetBalanceReadAccessImpl of OptionAssetBalanceReadAccessTrait {
157+
/// Reads the Option<AssetBalance> from the storage.
158+
/// The offset is used to read specific fields of the struct.
159+
#[inline]
160+
fn read(
161+
entry: StoragePointer0Offset<Option<AssetBalance>>, offset: OptionAssetBalanceOffset,
162+
) -> felt252 {
163+
storage_read_syscall(
164+
0,
165+
storage_address_from_base_and_offset(entry.__storage_pointer_address__, offset.into()),
166+
)
167+
.unwrap_syscall()
168+
}
169+
170+
/// Reads the variant of the Option<AssetBalance>.
171+
/// The variant mark if the Option is Some or None.
172+
#[inline]
173+
fn read_variant(entry: StoragePointer0Offset<Option<AssetBalance>>) -> felt252 {
174+
Self::read(entry, OptionAssetBalanceOffset::VARIANT)
175+
}
176+
177+
/// Returns true if the Option is Some, false if None.
178+
/// At the storage 0 indicates None, 1 indicates Some.
179+
#[inline]
180+
fn is_some(entry: StoragePointer0Offset<Option<AssetBalance>>) -> bool {
181+
let variant = Self::read_variant(entry);
182+
variant == 1
183+
}
184+
185+
/// Returns true if the Option is None, false if Some.
186+
/// At the storage 0 indicates None, 1 indicates Some.
187+
#[inline]
188+
fn is_none(entry: StoragePointer0Offset<Option<AssetBalance>>) -> bool {
189+
let variant = Self::read_variant(entry);
190+
variant == 0
191+
}
192+
193+
/// Reads the funding index from the Option<AssetBalance>.
194+
/// This function does not check if the Option is Some or None.
195+
fn at_funding_index(entry: StoragePointer0Offset<Option<AssetBalance>>) -> FundingIndex {
196+
let funding_index = Self::read(entry, OptionAssetBalanceOffset::FUNDING_INDEX);
197+
let funding_index: i64 = funding_index.try_into().unwrap();
198+
funding_index.into()
199+
}
200+
201+
/// Gets the funding index from the Option<AssetBalance>.
202+
/// Returns None if the Option is None.
203+
fn get_funding_index(
204+
entry: StoragePointer0Offset<Option<AssetBalance>>,
205+
) -> Option<FundingIndex> {
206+
if Self::is_none(entry) {
207+
return Option::None;
208+
}
209+
Option::Some(Self::at_funding_index(entry))
210+
}
211+
212+
/// Reads the balance from the Option<AssetBalance>.
213+
/// This function does not check if the Option is Some or None.
214+
fn at_balance(entry: StoragePointer0Offset<Option<AssetBalance>>) -> Balance {
215+
let balance = Self::read(entry, OptionAssetBalanceOffset::BALANCE);
216+
let balance: i64 = balance.try_into().unwrap();
217+
balance.into()
218+
}
219+
220+
/// Gets the balance from the Option<AssetBalance>.
221+
/// Returns None if the Option is None.
222+
fn get_balance(entry: StoragePointer0Offset<Option<AssetBalance>>) -> Option<Balance> {
223+
if Self::is_none(entry) {
224+
return Option::None;
225+
}
226+
Option::Some(Self::at_balance(entry))
227+
}
228+
229+
/// Reads the version from the Option<AssetBalance>.
230+
/// This function does not check if the Option is Some or None.
231+
fn at_version(entry: StoragePointer0Offset<Option<AssetBalance>>) -> u8 {
232+
let version = Self::read(entry, OptionAssetBalanceOffset::VERSION);
233+
let version: u8 = version.try_into().unwrap();
234+
version
235+
}
236+
237+
/// Gets the version from the Option<AssetBalance>.
238+
/// Returns None if the Option is None.
239+
fn get_version(entry: StoragePointer0Offset<Option<AssetBalance>>) -> Option<u8> {
240+
if Self::is_none(entry) {
241+
return Option::None;
242+
}
243+
Option::Some(Self::at_version(entry))
244+
}
245+
}
246+
247+
/// In the storage, the Option<AssetBalance> is stored as a struct with the following layout:
248+
/// - variant: u8 (1 for Some, 0 for None)
249+
/// - version: u8
250+
/// - balance: i64
251+
/// - funding_index: i64
252+
/// The offsets are used to read specific fields of the struct.
253+
#[derive(Copy, Drop, Debug, PartialEq, Serde)]
254+
pub enum OptionAssetBalanceOffset {
255+
VARIANT,
256+
VERSION,
257+
BALANCE,
258+
FUNDING_INDEX,
259+
}
260+
261+
262+
/// Convert the enum to u8 for storage access.
263+
pub impl OptionAssetBalanceOffsetIntoU8 of Into<OptionAssetBalanceOffset, u8> {
264+
fn into(self: OptionAssetBalanceOffset) -> u8 {
265+
match self {
266+
OptionAssetBalanceOffset::VARIANT => 0_u8,
267+
OptionAssetBalanceOffset::VERSION => 1_u8,
268+
OptionAssetBalanceOffset::BALANCE => 2_u8,
269+
OptionAssetBalanceOffset::FUNDING_INDEX => 3_u8,
270+
}
271+
}
272+
}

0 commit comments

Comments
 (0)