Smart Contract
AgentManager
A.79f5b5b0f95a160b.AgentManager
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}