Smart Contract

FlowVaultsAutoBalancers

A.b1d63873c3cc9f79.FlowVaultsAutoBalancers

Valid From

132,675,644

Deployed

1w ago
Feb 19, 2026, 10:35:24 AM UTC

Dependents

1 imports
1// standards
2import Burner from 0xf233dcee88fe0abe
3import FungibleToken from 0xf233dcee88fe0abe
4// DeFiActions
5import DeFiActions from 0x6d888f175c158410
6import FlowTransactionScheduler from 0xe467b9dd11fa00df
7
8/// FlowVaultsAutoBalancers
9///
10/// This contract deals with the storage, retrieval and cleanup of DeFiActions AutoBalancers as they are used in
11/// FlowVaults defined Strategies.
12///
13/// AutoBalancers are stored in contract account storage at paths derived by their related DeFiActions.UniqueIdentifier.id
14/// which identifies all DeFiActions components in the stack related to their composite Strategy.
15///
16/// When a Tide and necessarily the related Strategy is closed & burned, the related AutoBalancer and its Capabilities
17/// are destroyed and deleted
18///
19access(all) contract FlowVaultsAutoBalancers {
20
21    /// The path prefix used for StoragePath & PublicPath derivations
22    access(all) let pathPrefix: String
23
24    /* --- PUBLIC METHODS --- */
25
26    /// Returns the path (StoragePath or PublicPath) at which an AutoBalancer is stored with the associated
27    /// UniqueIdentifier.id.
28    access(all) view fun deriveAutoBalancerPath(id: UInt64, storage: Bool): Path {
29        return storage ? StoragePath(identifier: "\(self.pathPrefix)\(id)")! : PublicPath(identifier: "\(self.pathPrefix)\(id)")!
30    }
31
32    /// Returns an unauthorized reference to an AutoBalancer with the given UniqueIdentifier.id value. If none is
33    /// configured, `nil` will be returned.
34    access(all) fun borrowAutoBalancer(id: UInt64): &DeFiActions.AutoBalancer? {
35        let publicPath = self.deriveAutoBalancerPath(id: id, storage: false) as! PublicPath
36        return self.account.capabilities.borrow<&DeFiActions.AutoBalancer>(publicPath)
37    }
38
39    /* --- INTERNAL METHODS --- */
40
41    /// Configures a new AutoBalancer in storage, configures its public Capability, and sets its inner authorized
42    /// Capability. If an AutoBalancer is stored with an associated UniqueID value, the operation reverts.
43    access(account) fun _initNewAutoBalancer(
44        oracle: {DeFiActions.PriceOracle},
45        vaultType: Type,
46        lowerThreshold: UFix64,
47        upperThreshold: UFix64,
48        rebalanceSink: {DeFiActions.Sink}?,
49        rebalanceSource: {DeFiActions.Source}?,
50        uniqueID: DeFiActions.UniqueIdentifier
51    ): auth(DeFiActions.Auto, DeFiActions.Set, DeFiActions.Get, FungibleToken.Withdraw) &DeFiActions.AutoBalancer {
52
53        // derive paths & prevent collision
54        let storagePath = self.deriveAutoBalancerPath(id: uniqueID.id, storage: true) as! StoragePath
55        let publicPath = self.deriveAutoBalancerPath(id: uniqueID.id, storage: false) as! PublicPath
56        var storedType = self.account.storage.type(at: storagePath)
57        var publishedCap = self.account.capabilities.exists(publicPath)
58        assert(storedType == nil,
59            message: "Storage collision when creating AutoBalancer for UniqueIdentifier.id \(uniqueID.id) at path \(storagePath)")
60        assert(!publishedCap,
61            message: "Published Capability collision found when publishing AutoBalancer for UniqueIdentifier.id \(uniqueID.id) at path \(publicPath)")
62
63        // create & save AutoBalancer
64        let autoBalancer <- DeFiActions.createAutoBalancer(
65                oracle: oracle,
66                vaultType: vaultType,
67                lowerThreshold: lowerThreshold,
68                upperThreshold: upperThreshold,
69                rebalanceSink: rebalanceSink,
70                rebalanceSource: rebalanceSource,
71                recurringConfig: nil,
72                uniqueID: uniqueID
73            )
74        self.account.storage.save(<-autoBalancer, to: storagePath)
75        let autoBalancerRef = self._borrowAutoBalancer(uniqueID.id)
76
77        // issue & publish public capability
78        let publicCap = self.account.capabilities.storage.issue<&DeFiActions.AutoBalancer>(storagePath)
79        self.account.capabilities.publish(publicCap, at: publicPath)
80
81        // issue private capability & set within AutoBalancer
82        let authorizedCap = self.account.capabilities.storage.issue<auth(FungibleToken.Withdraw, FlowTransactionScheduler.Execute) &DeFiActions.AutoBalancer>(storagePath)
83        autoBalancerRef.setSelfCapability(authorizedCap)
84
85        // ensure proper configuration before closing
86        storedType = self.account.storage.type(at: storagePath)
87        publishedCap = self.account.capabilities.exists(publicPath)
88        assert(storedType == Type<@DeFiActions.AutoBalancer>(),
89            message: "Error when configuring AutoBalancer for UniqueIdentifier.id \(uniqueID.id) at path \(storagePath)")
90        assert(publishedCap,
91            message: "Error when publishing AutoBalancer Capability for UniqueIdentifier.id \(uniqueID.id) at path \(publicPath)")
92        return autoBalancerRef
93    }
94
95    /// Returns an authorized reference on the AutoBalancer with the associated UniqueIdentifier.id. If none is found,
96    /// the operation reverts.
97    access(account)
98    fun _borrowAutoBalancer(_ id: UInt64): auth(DeFiActions.Auto, DeFiActions.Set, DeFiActions.Get, FungibleToken.Withdraw) &DeFiActions.AutoBalancer {
99        let storagePath = self.deriveAutoBalancerPath(id: id, storage: true) as! StoragePath
100        return self.account.storage.borrow<auth(DeFiActions.Auto, DeFiActions.Set, DeFiActions.Get, FungibleToken.Withdraw) &DeFiActions.AutoBalancer>(
101                from: storagePath
102            ) ?? panic("Could not borrow reference to AutoBalancer with UniqueIdentifier.id \(id) from StoragePath \(storagePath)")
103    }
104
105    /// Called by strategies defined in the FlowVaults account which leverage account-hosted AutoBalancers when a
106    /// Strategy is burned
107    access(account) fun _cleanupAutoBalancer(id: UInt64) {
108        let storagePath = self.deriveAutoBalancerPath(id: id, storage: true) as! StoragePath
109        let publicPath = self.deriveAutoBalancerPath(id: id, storage: false) as! PublicPath
110        // unpublish the public AutoBalancer Capability
111        self.account.capabilities.unpublish(publicPath)
112        // delete any CapabilityControllers targetting the AutoBalancer
113        self.account.capabilities.storage.forEachController(forPath: storagePath, fun(_ controller: &StorageCapabilityController): Bool {
114            controller.delete()
115            return true
116        })
117        // load & burn the AutoBalancer
118        let autoBalancer <-self.account.storage.load<@DeFiActions.AutoBalancer>(from: storagePath)
119        Burner.burn(<-autoBalancer)
120    }
121
122    init() {
123        self.pathPrefix = "FlowVaultsAutoBalancer_"
124    }
125}
126