Smart Contract

AgentManager

A.79f5b5b0f95a160b.AgentManager

Valid From

128,856,514

Deployed

1w ago
Feb 20, 2026, 08:47:08 AM UTC

Dependents

0 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3import stFlowToken from 0xd6f80565193ad727
4import VaultCore from 0x79f5b5b0f95a160b
5import IncrementStakingStrategy from 0x79f5b5b0f95a160b
6import IncrementLoopingStrategy from 0x79f5b5b0f95a160b
7import IncrementFarmingStrategy from 0x79f5b5b0f95a160b
8import SwapStrategy from 0x79f5b5b0f95a160b
9
10access(all) contract AgentManager {
11    
12    access(all) let AgentStoragePath: StoragePath
13    access(all) let AgentPrivatePath: PrivatePath
14    
15    access(all) event AgentInitialized(agent: Address)
16    access(all) event StrategyExecuted(strategyType: String, assetType: String, amount: UFix64, result: UFix64)
17    access(all) event YieldHarvested(strategyType: String, amount: UFix64)
18    access(all) event HealthCheckPerformed(healthy: Bool, details: {String: UFix64})
19    
20    access(self) var authorizedAgent: Address?
21    access(self) var totalStrategyExecutions: UInt64
22    access(self) var totalYieldHarvested: UFix64
23    access(self) var lastHealthCheck: UFix64
24    
25    access(all) enum StrategyType: UInt8 {
26        access(all) case incrementStaking
27        access(all) case incrementLooping
28        access(all) case incrementFarming
29        access(all) case swap
30    }
31    
32    access(all) resource AgentCapability {
33        access(self) let vaultCap: Capability<&VaultCore.Vault>
34        access(self) let stakingStrategy: @IncrementStakingStrategy.Strategy
35        access(self) let loopingStrategy: @IncrementLoopingStrategy.Strategy
36        access(self) let farmingStrategy: @IncrementFarmingStrategy.Strategy
37        access(self) let swapStrategy: @SwapStrategy.Strategy
38        
39        init(vaultCap: Capability<&VaultCore.Vault>) {
40            self.vaultCap = vaultCap
41            self.stakingStrategy <- IncrementStakingStrategy.createStrategy()
42            self.loopingStrategy <- IncrementLoopingStrategy.createStrategy()
43            self.farmingStrategy <- IncrementFarmingStrategy.createStrategy()
44            self.swapStrategy <- SwapStrategy.createStrategy()
45        }
46        
47        access(all) fun executeIncrementStaking(amount: UFix64): UFix64 {
48            pre {
49                amount > 0.0: "Amount must be positive"
50            }
51            
52            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
53            let flowVault <- vault.withdrawForStrategy(assetType: VaultCore.AssetType.flow, amount: amount) as! @FlowToken.Vault
54            let stFlowVault <- self.stakingStrategy.executeStrategy(from: <-flowVault)
55            let stFlowReceived = stFlowVault.balance
56            vault.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-stFlowVault)
57            
58            AgentManager.totalStrategyExecutions = AgentManager.totalStrategyExecutions + 1
59            emit StrategyExecuted(strategyType: "IncrementStaking", assetType: "FLOW", amount: amount, result: stFlowReceived)
60            
61            return stFlowReceived
62        }
63        
64        access(all) fun executeIncrementLooping(amount: UFix64, numLoops: UInt8): UFix64 {
65            pre {
66                amount > 0.0: "Amount must be positive"
67                numLoops >= 1 && numLoops <= 3: "Loops must be 1-3"
68            }
69            
70            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
71            let flowVault <- vault.withdrawForStrategy(assetType: VaultCore.AssetType.flow, amount: amount) as! @FlowToken.Vault
72            let stFlowVault <- self.loopingStrategy.executeStrategy(from: <-flowVault, numLoops: numLoops)
73            let stFlowReceived = stFlowVault.balance
74            vault.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-stFlowVault)
75            
76            AgentManager.totalStrategyExecutions = AgentManager.totalStrategyExecutions + 1
77            emit StrategyExecuted(strategyType: "IncrementLooping", assetType: "FLOW", amount: amount, result: stFlowReceived)
78            
79            return stFlowReceived
80        }
81        
82        access(all) fun executeIncrementFarming(poolId: UInt64, amount: UFix64, assetType: VaultCore.AssetType): Bool {
83            pre {
84                amount > 0.0: "Amount must be positive"
85            }
86            
87            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
88            let assetVault <- vault.withdrawForStrategy(assetType: assetType, amount: amount)
89            let success = self.farmingStrategy.executeStrategy(poolId: poolId, from: <-assetVault)
90            
91            AgentManager.totalStrategyExecutions = AgentManager.totalStrategyExecutions + 1
92            emit StrategyExecuted(strategyType: "IncrementFarming", assetType: assetType == VaultCore.AssetType.flow ? "FLOW" : "stFLOW", amount: amount, result: success ? 1.0 : 0.0)
93            
94            return success
95        }
96        
97        access(all) fun executeSwap(fromAsset: VaultCore.AssetType, toAsset: VaultCore.AssetType, amount: UFix64): UFix64 {
98            pre {
99                amount > 0.0: "Amount must be positive"
100                fromAsset != toAsset: "Cannot swap same asset"
101            }
102            
103            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
104            var resultAmount = 0.0
105            let sourceVault <- vault.withdrawForStrategy(assetType: fromAsset, amount: amount)
106            
107            if fromAsset == VaultCore.AssetType.flow && toAsset == VaultCore.AssetType.stflow {
108                let flowVault <- sourceVault as! @FlowToken.Vault
109                let stFlowVault <- self.swapStrategy.swapFlowToStFlow(from: <-flowVault)
110                resultAmount = stFlowVault.balance
111                vault.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-stFlowVault)
112            } else if fromAsset == VaultCore.AssetType.stflow && toAsset == VaultCore.AssetType.flow {
113                let stFlowVault <- sourceVault as! @stFlowToken.Vault
114                let flowVault <- self.swapStrategy.swapStFlowToFlow(from: <-stFlowVault)
115                resultAmount = flowVault.balance
116                vault.depositFromStrategy(assetType: VaultCore.AssetType.flow, from: <-flowVault)
117            } else {
118                destroy sourceVault
119                panic("Unsupported swap direction")
120            }
121            
122            AgentManager.totalStrategyExecutions = AgentManager.totalStrategyExecutions + 1
123            emit StrategyExecuted(strategyType: "Swap", assetType: fromAsset == VaultCore.AssetType.flow ? "FLOW" : "stFLOW", amount: amount, result: resultAmount)
124            
125            return resultAmount
126        }
127        
128        access(all) fun harvestStaking(): UFix64 {
129            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
130            let harvestedVault <- self.stakingStrategy.harvest()
131            let harvestedAmount = harvestedVault.balance
132            
133            if harvestedAmount > 0.0 {
134                vault.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-harvestedVault)
135                vault.recordYieldHarvest(assetType: VaultCore.AssetType.stflow, amount: harvestedAmount)
136                AgentManager.totalYieldHarvested = AgentManager.totalYieldHarvested + harvestedAmount
137                emit YieldHarvested(strategyType: "IncrementStaking", amount: harvestedAmount)
138            } else {
139                destroy harvestedVault
140            }
141            
142            return harvestedAmount
143        }
144        
145        access(all) fun harvestFarming(poolId: UInt64): UFix64 {
146            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
147            let harvestedVaults <- self.farmingStrategy.harvestPool(poolId: poolId)
148            
149            var totalHarvested: UFix64 = 0.0
150            
151            // Process each reward token type
152            for tokenKey in harvestedVaults.keys {
153                let rewardVault <- harvestedVaults.remove(key: tokenKey)!
154                let amount = rewardVault.balance
155                totalHarvested = totalHarvested + amount
156                
157                // Deposit based on token type
158                if tokenKey.contains("FlowToken") {
159                    vault.depositFromStrategy(assetType: VaultCore.AssetType.flow, from: <-rewardVault)
160                    vault.recordYieldHarvest(assetType: VaultCore.AssetType.flow, amount: amount)
161                } else if tokenKey.contains("stFlowToken") {
162                    vault.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-rewardVault)
163                    vault.recordYieldHarvest(assetType: VaultCore.AssetType.stflow, amount: amount)
164                } else {
165                    // For other tokens, just destroy for now
166                    destroy rewardVault
167                }
168            }
169            
170            destroy harvestedVaults
171            
172            if totalHarvested > 0.0 {
173                AgentManager.totalYieldHarvested = AgentManager.totalYieldHarvested + totalHarvested
174                emit YieldHarvested(strategyType: "IncrementFarming", amount: totalHarvested)
175            }
176            
177            return totalHarvested
178        }
179        
180        access(all) fun harvestAllFarms(): UFix64 {
181            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
182            let harvestedVaults <- self.farmingStrategy.harvestAll()
183            
184            var totalHarvested: UFix64 = 0.0
185            
186            // Process each reward token type
187            for tokenKey in harvestedVaults.keys {
188                let rewardVault <- harvestedVaults.remove(key: tokenKey)!
189                let amount = rewardVault.balance
190                totalHarvested = totalHarvested + amount
191                
192                // Deposit based on token type
193                if tokenKey.contains("FlowToken") {
194                    vault.depositFromStrategy(assetType: VaultCore.AssetType.flow, from: <-rewardVault)
195                    vault.recordYieldHarvest(assetType: VaultCore.AssetType.flow, amount: amount)
196                } else if tokenKey.contains("stFlowToken") {
197                    vault.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-rewardVault)
198                    vault.recordYieldHarvest(assetType: VaultCore.AssetType.stflow, amount: amount)
199                } else {
200                    // For other tokens, just destroy for now
201                    destroy rewardVault
202                }
203            }
204            
205            destroy harvestedVaults
206            
207            if totalHarvested > 0.0 {
208                AgentManager.totalYieldHarvested = AgentManager.totalYieldHarvested + totalHarvested
209                emit YieldHarvested(strategyType: "IncrementFarmingAll", amount: totalHarvested)
210            }
211            
212            return totalHarvested
213        }
214        
215        access(all) fun checkLoopingHealth(): {String: UFix64} {
216            let metrics = self.loopingStrategy.getHealthMetrics()
217            let healthFactor = metrics["healthFactor"]!
218            let isHealthy = healthFactor > 1.5
219            AgentManager.lastHealthCheck = getCurrentBlock().timestamp
220            emit HealthCheckPerformed(healthy: isHealthy, details: metrics)
221            return metrics
222        }
223        
224        access(all) fun getFarmingPositions(): {UInt64: {String: UFix64}} {
225            return self.farmingStrategy.getPositions()
226        }
227        
228        access(all) fun getStrategyBalances(): {String: {String: UFix64}} {
229            return {
230                "staking": self.stakingStrategy.getBalances(),
231                "looping": self.loopingStrategy.getBalances(),
232                "farming": self.farmingStrategy.getBalances(),
233                "swap": self.swapStrategy.getBalances()
234            }
235        }
236        
237        access(all) fun getSwapQuote(fromAsset: VaultCore.AssetType, toAsset: VaultCore.AssetType, amount: UFix64): SwapStrategy.RouteQuote {
238            if fromAsset == VaultCore.AssetType.flow && toAsset == VaultCore.AssetType.stflow {
239                return SwapStrategy.getQuoteFlowToStFlow(amount: amount)
240            } else if fromAsset == VaultCore.AssetType.stflow && toAsset == VaultCore.AssetType.flow {
241                return SwapStrategy.getQuoteStFlowToFlow(amount: amount)
242            } else {
243                panic("Unsupported swap direction")
244            }
245        }
246        
247        access(all) fun withdrawForEVMBridge(amount: UFix64): @FlowToken.Vault {
248            pre {
249                amount > 0.0: "Amount must be positive"
250            }
251            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
252            let flowVault <- vault.withdrawForEVMBridge(assetType: VaultCore.AssetType.flow, amount: amount) as! @FlowToken.Vault
253            return <- flowVault
254        }
255        
256        access(all) fun depositFromEVMBridge(from: @FlowToken.Vault) {
257            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
258            vault.depositFromEVMBridge(from: <-from)
259        }
260        
261        access(all) fun emergencyExitAll() {
262            let vault = self.vaultCap.borrow() ?? panic("Cannot borrow vault")
263            
264            // Exit staking strategy
265            let stakingExit <- self.stakingStrategy.emergencyExit()
266            if stakingExit.balance > 0.0 {
267                vault.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-stakingExit)
268            } else {
269                destroy stakingExit
270            }
271            
272            // Exit looping strategy
273            let loopingExit <- self.loopingStrategy.emergencyExit()
274            destroy loopingExit
275            
276            // Exit farming strategy - returns dictionary of vaults
277            let farmingExit <- self.farmingStrategy.emergencyExit()
278            for tokenKey in farmingExit.keys {
279                let exitVault <- farmingExit.remove(key: tokenKey)!
280                let amount = exitVault.balance
281                
282                if amount > 0.0 {
283                    // Deposit based on token type
284                    if tokenKey.contains("FlowToken") {
285                        vault.depositFromStrategy(assetType: VaultCore.AssetType.flow, from: <-exitVault)
286                    } else if tokenKey.contains("stFlowToken") {
287                        vault.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-exitVault)
288                    } else {
289                        destroy exitVault
290                    }
291                } else {
292                    destroy exitVault
293                }
294            }
295            destroy farmingExit
296            
297            // Exit swap strategy
298            let swapExit <- self.swapStrategy.emergencyExit()
299            if swapExit.balance > 0.0 {
300                vault.depositFromStrategy(assetType: VaultCore.AssetType.flow, from: <-swapExit)
301            } else {
302                destroy swapExit
303            }
304        }
305    }
306    
307    access(all) fun createAgentCapability(vaultCap: Capability<&VaultCore.Vault>): @AgentCapability {
308        return <- create AgentCapability(vaultCap: vaultCap)
309    }
310    
311    access(all) fun setAuthorizedAgent(agent: Address) {
312        self.authorizedAgent = agent
313        emit AgentInitialized(agent: agent)
314    }
315    
316    access(all) fun getMetrics(): {String: AnyStruct} {
317        return {
318            "authorizedAgent": self.authorizedAgent,
319            "totalStrategyExecutions": self.totalStrategyExecutions,
320            "totalYieldHarvested": self.totalYieldHarvested,
321            "lastHealthCheck": self.lastHealthCheck,
322            "stakingMetrics": IncrementStakingStrategy.getMetrics(),
323            "loopingMetrics": IncrementLoopingStrategy.getMetrics(),
324            "farmingMetrics": IncrementFarmingStrategy.getMetrics(),
325            "swapMetrics": SwapStrategy.getMetrics()
326        }
327    }
328    
329    init() {
330        self.AgentStoragePath = /storage/AgentCapability
331        self.AgentPrivatePath = /private/AgentCapability
332        self.authorizedAgent = nil
333        self.totalStrategyExecutions = 0
334        self.totalYieldHarvested = 0.0
335        self.lastHealthCheck = getCurrentBlock().timestamp
336    }
337}