Smart Contract
AgentManager2
A.79f5b5b0f95a160b.AgentManager2
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3import stFlowToken from 0xd6f80565193ad727
4import EVM from 0xe467b9dd11fa00df
5import VaultCore from 0x79f5b5b0f95a160b
6import IncrementStakingStrategy from 0x79f5b5b0f95a160b
7import IncrementLoopingStrategy from 0x79f5b5b0f95a160b
8import IncrementLendingStrategy from 0x79f5b5b0f95a160b
9import IncrementFarmingStrategy from 0x79f5b5b0f95a160b
10import SwapStrategy from 0x79f5b5b0f95a160b
11
12access(all) contract AgentManager2 {
13
14 access(all) let AgentStoragePath: StoragePath
15 access(all) let AgentPublicPath: PublicPath
16 access(all) let EVM_VAULT_CORE: String
17 access(all) let EVM_STRATEGY_MANAGER: String
18
19 access(all) event StrategyExecuted(strategy: String, amount: UFix64, result: String)
20 access(all) event FundsBridgedToEVM(amount: UFix64, evmAddress: String)
21 access(all) event FundsBridgedFromEVM(amount: UFix64)
22 access(all) event YieldHarvested(strategy: String, amount: UFix64)
23
24 access(self) var totalBridgedToEVM: UFix64
25 access(self) var totalBridgedFromEVM: UFix64
26
27 access(all) resource Agent {
28 access(self) let vaultRef: &VaultCore.Vault
29 access(self) let coa: auth(EVM.Call, EVM.Withdraw) &EVM.CadenceOwnedAccount
30 access(self) var stakingStrategy: @IncrementStakingStrategy.Strategy
31 access(self) var loopingStrategy: @IncrementLoopingStrategy.Strategy
32 access(self) var lendingStrategy: @IncrementLendingStrategy.Strategy
33 access(self) var farmingStrategy: @IncrementFarmingStrategy.Strategy
34 access(self) var swapStrategy: @SwapStrategy.Strategy
35
36 init(vaultRef: &VaultCore.Vault, coa: auth(EVM.Call, EVM.Withdraw) &EVM.CadenceOwnedAccount) {
37 self.vaultRef = vaultRef
38 self.coa = coa
39 self.stakingStrategy <- IncrementStakingStrategy.createStrategy()
40 self.loopingStrategy <- IncrementLoopingStrategy.createStrategy()
41 self.lendingStrategy <- IncrementLendingStrategy.createStrategy()
42 self.farmingStrategy <- IncrementFarmingStrategy.createStrategy()
43 self.swapStrategy <- SwapStrategy.createStrategy()
44 }
45
46 access(all) fun executeStaking(amount: UFix64): UFix64 {
47 let strategyRef = &self.stakingStrategy as &IncrementStakingStrategy.Strategy
48 let flowVault <- self.vaultRef.withdrawForStrategy(assetType: VaultCore.AssetType.flow, amount: amount) as! @FlowToken.Vault
49 let stFlowVault <- strategyRef.executeStrategy(from: <-flowVault)
50 let received = stFlowVault.balance
51 self.vaultRef.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-stFlowVault)
52 emit StrategyExecuted(strategy: "Staking", amount: amount, result: received.toString())
53 return received
54 }
55
56 access(all) fun executeLooping(amount: UFix64, numLoops: UInt8): UFix64 {
57 let strategyRef = &self.loopingStrategy as &IncrementLoopingStrategy.Strategy
58 let flowVault <- self.vaultRef.withdrawForStrategy(assetType: VaultCore.AssetType.flow, amount: amount) as! @FlowToken.Vault
59 let stFlowVault <- strategyRef.executeStrategy(from: <-flowVault, numLoops: numLoops)
60 let received = stFlowVault.balance
61 self.vaultRef.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-stFlowVault)
62 emit StrategyExecuted(strategy: "Looping", amount: amount, result: received.toString())
63 return received
64 }
65
66 access(all) fun supplyToLending(asset: String, amount: UFix64) {
67 let lendingRef = &self.lendingStrategy as &IncrementLendingStrategy.Strategy
68 if asset == "FLOW" {
69 let vault <- self.vaultRef.withdrawForStrategy(assetType: VaultCore.AssetType.flow, amount: amount) as! @FlowToken.Vault
70 lendingRef.depositFlow(vault: <-vault)
71 lendingRef.supplyFlow(amount: amount)
72 } else if asset == "stFLOW" {
73 let vault <- self.vaultRef.withdrawForStrategy(assetType: VaultCore.AssetType.stflow, amount: amount) as! @stFlowToken.Vault
74 lendingRef.depositStFlow(vault: <-vault)
75 lendingRef.supplyStFlow(amount: amount)
76 }
77 emit StrategyExecuted(strategy: "Lending-Supply", amount: amount, result: "Success")
78 }
79
80 access(all) fun stakeInFarm(poolId: UInt64, amount: UFix64, tokenType: String) {
81 let farmingRef = &self.farmingStrategy as &IncrementFarmingStrategy.Strategy
82 if tokenType == "FLOW" {
83 let vault <- self.vaultRef.withdrawForStrategy(assetType: VaultCore.AssetType.flow, amount: amount) as! @FlowToken.Vault
84 let success = farmingRef.executeStrategy(poolId: poolId, from: <-vault)
85 emit StrategyExecuted(strategy: "Farming", amount: amount, result: success ? "true" : "false")
86 } else if tokenType == "stFLOW" {
87 let vault <- self.vaultRef.withdrawForStrategy(assetType: VaultCore.AssetType.stflow, amount: amount) as! @stFlowToken.Vault
88 let success = farmingRef.executeStrategy(poolId: poolId, from: <-vault)
89 emit StrategyExecuted(strategy: "Farming", amount: amount, result: success ? "true" : "false")
90 }
91 }
92
93 access(all) fun harvestFarmingRewards(poolId: UInt64) {
94 let farmingRef = &self.farmingStrategy as &IncrementFarmingStrategy.Strategy
95 let rewards <- farmingRef.harvestPool(poolId: poolId)
96 var totalHarvested: UFix64 = 0.0
97 for tokenKey in rewards.keys {
98 let rewardVault <- rewards.remove(key: tokenKey)!
99 totalHarvested = totalHarvested + rewardVault.balance
100 if tokenKey.slice(from: tokenKey.length - 9, upTo: tokenKey.length) == "FlowToken" {
101 self.vaultRef.depositFromStrategy(assetType: VaultCore.AssetType.flow, from: <-rewardVault)
102 } else if tokenKey.slice(from: tokenKey.length - 11, upTo: tokenKey.length) == "stFlowToken" {
103 self.vaultRef.depositFromStrategy(assetType: VaultCore.AssetType.stflow, from: <-rewardVault)
104 } else {
105 destroy rewardVault
106 }
107 }
108 destroy rewards
109 self.vaultRef.recordYieldHarvest(assetType: VaultCore.AssetType.flow, amount: totalHarvested)
110 emit YieldHarvested(strategy: "Farming", amount: totalHarvested)
111 }
112
113 access(all) fun bridgeToEVM(amount: UFix64): Bool {
114 let flowVault <- self.vaultRef.withdrawForEVMBridge(assetType: VaultCore.AssetType.flow, amount: amount) as! @FlowToken.Vault
115 self.coa.deposit(from: <-flowVault)
116 AgentManager2.totalBridgedToEVM = AgentManager2.totalBridgedToEVM + amount
117 emit FundsBridgedToEVM(amount: amount, evmAddress: self.coa.address().toString())
118 return true
119 }
120
121 access(all) fun bridgeFromEVM(amount: UFix64): Bool {
122 let scaledAmount = amount * 1000000000.0
123 let amountUInt = UInt(scaledAmount) * 1000000000
124 let balance = EVM.Balance(attoflow: amountUInt)
125 let flowVault <- self.coa.withdraw(balance: balance) as! @FlowToken.Vault
126 let actualAmount = flowVault.balance
127 self.vaultRef.depositFromEVMBridge(from: <-flowVault)
128 AgentManager2.totalBridgedFromEVM = AgentManager2.totalBridgedFromEVM + actualAmount
129 emit FundsBridgedFromEVM(amount: actualAmount)
130 return true
131 }
132
133 access(all) fun executeEVMStrategy(contractAddress: String, calldata: [UInt8], value: UFix64): EVM.Result {
134 let scaledValue = value * 1000000000.0
135 let amountUInt = UInt(scaledValue) * 1000000000
136 let balance = EVM.Balance(attoflow: amountUInt)
137 let addressBytes = contractAddress.decodeHex()
138 assert(addressBytes.length == 20, message: "Invalid EVM address")
139 let fixedBytes: [UInt8; 20] = [addressBytes[0], addressBytes[1], addressBytes[2], addressBytes[3], addressBytes[4], addressBytes[5], addressBytes[6], addressBytes[7], addressBytes[8], addressBytes[9], addressBytes[10], addressBytes[11], addressBytes[12], addressBytes[13], addressBytes[14], addressBytes[15], addressBytes[16], addressBytes[17], addressBytes[18], addressBytes[19]]
140 let evmAddress = EVM.EVMAddress(bytes: fixedBytes)
141 return self.coa.call(to: evmAddress, data: calldata, gasLimit: 10_000_000, value: balance)
142 }
143
144 access(all) fun getStrategyBalances(): {String: {String: UFix64}} {
145 return {"staking": self.stakingStrategy.getBalances(), "looping": self.loopingStrategy.getBalances(), "lending": self.lendingStrategy.getBalances(), "farming": self.farmingStrategy.getBalances(), "swap": self.swapStrategy.getBalances()}
146 }
147
148 access(all) fun getFarmingPositions(): {UInt64: {String: UFix64}} {
149 return self.farmingStrategy.getPositions()
150 }
151
152 access(all) fun getLendingPosition(): IncrementLendingStrategy.UserPosition {
153 return self.lendingStrategy.getPositions()
154 }
155
156 access(all) fun getLoopingHealth(): {String: UFix64} {
157 return self.loopingStrategy.getHealthMetrics()
158 }
159
160 access(all) fun getCOAAddress(): String {
161 return self.coa.address().toString()
162 }
163
164 access(all) fun getCOABalance(): UFix64 {
165 let balanceAttoflow = self.coa.balance().attoflow
166 let scaledDown = UFix64(balanceAttoflow / 1000000000)
167 return scaledDown / 1000000000.0
168 }
169 }
170
171 access(all) fun createAgent(vaultRef: &VaultCore.Vault, coa: auth(EVM.Call, EVM.Withdraw) &EVM.CadenceOwnedAccount): @Agent {
172 return <- create Agent(vaultRef: vaultRef, coa: coa)
173 }
174
175 access(all) fun getMetrics(): {String: UFix64} {
176 return {"totalBridgedToEVM": self.totalBridgedToEVM, "totalBridgedFromEVM": self.totalBridgedFromEVM}
177 }
178
179 init() {
180 self.AgentStoragePath = /storage/AgentManager2
181 self.AgentPublicPath = /public/AgentManager2
182 self.EVM_VAULT_CORE = "0xc0F67510F9E8974345f7fE8b8981C780F94BFbf9"
183 self.EVM_STRATEGY_MANAGER = "0x915537401B7BC088d54a58e55b488B821508A55f"
184 self.totalBridgedToEVM = 0.0
185 self.totalBridgedFromEVM = 0.0
186 }
187}