@@ -179,7 +179,6 @@ access(all) contract FlowCreditMarket {
179179 /// Note that this entitlement provides access to all positions in the pool,
180180 /// not just individual position owners' positions.
181181 access (all ) entitlement EPosition
182- access (all ) entitlement ERebalance
183182
184183 /// EGovernance
185184 ///
@@ -3422,6 +3421,22 @@ access(all) contract FlowCreditMarket {
34223421 self ._unlockPosition (pid )
34233422 }
34243423
3424+ /// Attempts to rebalance a position toward its configured `targetHealth` without acquiring
3425+ /// or releasing the position lock. This function performs *best-effort* rebalancing and may
3426+ /// partially rebalance or no-op depending on available sinks/sources and their capacity.
3427+ ///
3428+ /// This helper is intentionally "no-lock" and "effects-only" with respect to orchestration.
3429+ /// Callers are responsible for acquiring and releasing the position lock and for enforcing
3430+ /// any higher-level invariants.
3431+ access (self ) fun _rebalancePositionNoLock (pid : UInt64 , force : Bool ) {
3432+ post {
3433+ self .positionLock [pid ] == nil : " Position is not unlocked"
3434+ }
3435+ self ._lockPosition (pid )
3436+ self ._rebalancePositionNoLock (pid : pid , force : force )
3437+ self ._unlockPosition (pid )
3438+ }
3439+
34253440 /// Attempts to rebalance a position toward its configured `targetHealth` without acquiring
34263441 /// or releasing the position lock. This function performs *best-effort* rebalancing and may
34273442 /// partially rebalance or no-op depending on available sinks/sources and their capacity.
@@ -3853,7 +3868,7 @@ access(all) contract FlowCreditMarket {
38533868 /// The unique ID of the Position used to track deposits and withdrawals to the Pool
38543869 access (all ) let id : UInt64
38553870
3856- /// An authorized Capability to which the Position was opened
3871+ /// An authorized Capability to the Pool for which this Position was opened.
38573872 access (self ) let pool : Capability <auth (EPosition ) &Pool >
38583873
38593874 init (
@@ -4132,7 +4147,62 @@ access(all) contract FlowCreditMarket {
41324147 access (all ) fun getPositionIDs (): [UInt64 ] {
41334148 return self .positions .keys
41344149 }
4150+ }
4151+
4152+ /// Creates and returns a new PositionManager resource
4153+ access (all ) fun createPositionManager (): @PositionManager {
4154+ return <- create PositionManager ()
4155+ }
4156+
4157+ /// PositionManager
4158+ ///
4159+ /// A collection resource that manages multiple Position resources for an account.
4160+ /// This allows users to have multiple positions while using a single, constant storage path.
4161+ ///
4162+ access (all ) resource PositionManager {
4163+
4164+ /// Dictionary storing all positions owned by this manager, keyed by position ID
4165+ access (self ) let positions : @{UInt64 : Position }
4166+
4167+ init () {
4168+ self .positions <- {}
4169+ }
41354170
4171+ /// Adds a new position to the manager.
4172+ access (EPositionAdmin ) fun addPosition (position : @Position ) {
4173+ let pid = position .id
4174+ let old <- self .positions [pid ] <- position
4175+ if old ! = nil {
4176+ panic (" Cannot add position with same pid (\( pid ) ) as existing position: must explicitly remove existing position first" )
4177+ }
4178+ destroy old
4179+ }
4180+
4181+ /// Removes and returns a position from the manager.
4182+ access (EPositionAdmin ) fun removePosition (pid : UInt64 ): @Position {
4183+ if let position <- self .positions .remove (key : pid ) {
4184+ return <- position
4185+ }
4186+ panic (" Position with pid=\( pid ) not found in PositionManager" )
4187+ }
4188+
4189+ /// Internal method that returns a reference to a position authorized with all entitlements.
4190+ /// Callers who wish to provide a partially authorized reference can downcast the result as needed.
4191+ access (EPositionAdmin ) fun borrowAuthorizedPosition (pid : UInt64 ): auth (FungibleToken.Withdraw , EPositionAdmin ) &Position {
4192+ return (&self .positions [pid ] as auth (FungibleToken.Withdraw , EPositionAdmin ) &Position ? )
4193+ ?? panic (" Position with pid=\( pid ) not found in PositionManager" )
4194+ }
4195+
4196+ /// Returns a public reference to a position with no entitlements.
4197+ access (all ) fun borrowPosition (pid : UInt64 ): &Position {
4198+ return (&self .positions [pid ] as &Position ? )
4199+ ?? panic (" Position with pid=\( pid ) not found in PositionManager" )
4200+ }
4201+
4202+ /// Returns the IDs of all positions in this manager
4203+ access (all ) fun getPositionIDs (): [UInt64 ] {
4204+ return self .positions .keys
4205+ }
41364206 }
41374207
41384208 /// Creates and returns a new PositionManager resource
0 commit comments