Smart Contract
FlowYieldVaultsConnector
A.a092c4aab33daeda.FlowYieldVaultsConnector
1/*
2FlowYieldVaultsConnector - Mainnet FlowYieldVaults Integration
3
4This connector enables PrizeSavings to deposit funds into FlowYieldVaults (yield-bearing strategies)
5and implements DeFiActions.Sink and DeFiActions.Source interfaces.
6
7FlowYieldVaults Contract: mainnet://b1d63873c3cc9f79.FlowYieldVaults
8*/
9
10import FungibleToken from 0xf233dcee88fe0abe
11import FlowYieldVaults from 0xb1d63873c3cc9f79
12import FlowYieldVaultsClosedBeta from 0xb1d63873c3cc9f79
13import DeFiActions from 0x92195d814edf9cb0
14
15access(all) contract FlowYieldVaultsConnector {
16
17 // Storage paths
18 access(all) let ManagerStoragePath: StoragePath
19 access(all) let ManagerPublicPath: PublicPath
20
21 // Events
22 access(all) event ConnectorCreated(managerAddress: Address, strategyType: String, vaultType: String)
23 access(all) event DepositedToYieldVault(yieldVaultID: UInt64, amount: UFix64, vaultType: String)
24 access(all) event WithdrawnFromYieldVault(yieldVaultID: UInt64, amount: UFix64, vaultType: String)
25 access(all) event YieldVaultCreated(yieldVaultID: UInt64, strategyType: String, initialAmount: UFix64)
26
27 /// YieldVaultManagerWrapper Resource
28 /// Wraps FlowYieldVaults.YieldVaultManager with beta badge authentication
29 access(all) resource YieldVaultManagerWrapper {
30 access(self) let yieldVaultManagerCap: Capability<auth(FungibleToken.Withdraw) &FlowYieldVaults.YieldVaultManager>
31 access(self) let betaBadgeCap: Capability<auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge>
32 access(self) var yieldVaultID: UInt64?
33 access(all) let vaultType: Type
34 access(all) let strategyType: Type
35
36 init(
37 yieldVaultManagerCap: Capability<auth(FungibleToken.Withdraw) &FlowYieldVaults.YieldVaultManager>,
38 betaBadgeCap: Capability<auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge>,
39 vaultType: Type,
40 strategyType: Type
41 ) {
42 pre {
43 yieldVaultManagerCap.check(): "Invalid YieldVaultManager capability"
44 betaBadgeCap.check(): "Invalid Beta badge capability"
45 }
46
47 self.yieldVaultManagerCap = yieldVaultManagerCap
48 self.betaBadgeCap = betaBadgeCap
49 self.vaultType = vaultType
50 self.strategyType = strategyType
51 self.yieldVaultID = nil
52 }
53
54 access(all) fun depositToYieldVault(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) {
55 pre {
56 from.getType() == self.vaultType: "Vault type mismatch"
57 from.balance > 0.0: "Cannot deposit zero balance"
58 }
59
60 let amount = from.balance
61 let yieldVaultManager = self.yieldVaultManagerCap.borrow()
62 ?? panic("Cannot borrow YieldVaultManager")
63 let betaBadge = self.betaBadgeCap.borrow()
64 ?? panic("Cannot borrow Beta badge")
65
66 // If we don't have a YieldVault yet, create one
67 if self.yieldVaultID == nil {
68 let initialVault <- from.withdraw(amount: amount)
69
70 let newID = yieldVaultManager.createYieldVault(
71 betaRef: betaBadge,
72 strategyType: self.strategyType,
73 withVault: <- initialVault
74 )
75
76 self.yieldVaultID = newID
77
78 emit YieldVaultCreated(
79 yieldVaultID: self.yieldVaultID!,
80 strategyType: self.strategyType.identifier,
81 initialAmount: amount
82 )
83
84 emit DepositedToYieldVault(
85 yieldVaultID: self.yieldVaultID!,
86 amount: amount,
87 vaultType: self.vaultType.identifier
88 )
89 } else {
90 let depositVault <- from.withdraw(amount: amount)
91
92 yieldVaultManager.depositToYieldVault(
93 betaRef: betaBadge,
94 self.yieldVaultID!,
95 from: <- depositVault
96 )
97
98 emit DepositedToYieldVault(
99 yieldVaultID: self.yieldVaultID!,
100 amount: amount,
101 vaultType: self.vaultType.identifier
102 )
103 }
104 }
105
106 access(all) fun getYieldVaultBalance(): UFix64 {
107 if self.yieldVaultID == nil {
108 return 0.0
109 }
110
111 let yieldVaultManager = self.yieldVaultManagerCap.borrow()
112 ?? panic("Cannot borrow YieldVaultManager")
113
114 let yieldVaultRef = yieldVaultManager.borrowYieldVault(id: self.yieldVaultID!)
115 if yieldVaultRef == nil {
116 return 0.0
117 }
118
119 return yieldVaultRef!.getYieldVaultBalance()
120 }
121
122 access(all) fun withdrawFromYieldVault(maxAmount: UFix64): @{FungibleToken.Vault} {
123 pre {
124 self.yieldVaultID != nil: "No YieldVault initialized"
125 maxAmount > 0.0: "Cannot withdraw zero amount"
126 }
127
128 let yieldVaultManager = self.yieldVaultManagerCap.borrow()
129 ?? panic("Cannot borrow YieldVaultManager")
130
131 let available = self.getYieldVaultBalance()
132 let withdrawAmount = maxAmount < available ? maxAmount : available
133
134 assert(withdrawAmount > 0.0, message: "Insufficient balance in YieldVault")
135
136 let vault <- yieldVaultManager.withdrawFromYieldVault(self.yieldVaultID!, amount: withdrawAmount)
137
138 emit WithdrawnFromYieldVault(
139 yieldVaultID: self.yieldVaultID!,
140 amount: withdrawAmount,
141 vaultType: vault.getType().identifier
142 )
143
144 return <- vault
145 }
146 }
147
148 /// Connector Struct
149 /// Implements DeFiActions.Sink and DeFiActions.Source
150 /// References a stored YieldVaultManagerWrapper resource
151 access(all) struct Connector: DeFiActions.Sink, DeFiActions.Source {
152 access(all) let managerAddress: Address
153 access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
154 access(all) let vaultType: Type
155
156 init(managerAddress: Address, vaultType: Type) {
157 self.managerAddress = managerAddress
158 self.vaultType = vaultType
159 self.uniqueID = nil
160 }
161
162 /// DeFiActions.Sink Implementation
163 access(all) fun depositCapacity(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) {
164 let managerAccount = getAccount(self.managerAddress)
165 let managerRef = managerAccount.capabilities.borrow<&YieldVaultManagerWrapper>(
166 FlowYieldVaultsConnector.ManagerPublicPath
167 ) ?? panic("Cannot borrow YieldVaultManagerWrapper from address")
168
169 managerRef.depositToYieldVault(from: from)
170 }
171
172 access(all) view fun getSinkType(): Type {
173 return self.vaultType
174 }
175
176 access(all) view fun minimumCapacity(): UFix64 {
177 return 0.0
178 }
179
180 /// DeFiActions.Source Implementation
181 access(all) fun minimumAvailable(): UFix64 {
182 let managerAccount = getAccount(self.managerAddress)
183 if let managerRef = managerAccount.capabilities.borrow<&YieldVaultManagerWrapper>(
184 FlowYieldVaultsConnector.ManagerPublicPath
185 ) {
186 return managerRef.getYieldVaultBalance()
187 }
188 return 0.0
189 }
190
191 access(FungibleToken.Withdraw) fun withdrawAvailable(maxAmount: UFix64): @{FungibleToken.Vault} {
192 let managerAccount = getAccount(self.managerAddress)
193 let managerRef = managerAccount.capabilities.borrow<&YieldVaultManagerWrapper>(
194 FlowYieldVaultsConnector.ManagerPublicPath
195 ) ?? panic("Cannot borrow YieldVaultManagerWrapper from address")
196
197 return <- managerRef.withdrawFromYieldVault(maxAmount: maxAmount)
198 }
199
200 access(all) view fun getSourceType(): Type {
201 return self.vaultType
202 }
203
204 /// DeFiActions Component Info
205 access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
206 return DeFiActions.ComponentInfo(
207 type: self.getType(),
208 id: self.uniqueID?.id,
209 innerComponents: []
210 )
211 }
212
213 access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
214 return self.uniqueID
215 }
216
217 access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
218 self.uniqueID = id
219 }
220 }
221
222 /// Create a new YieldVaultManagerWrapper and store it
223 /// Returns a Connector struct that references it
224 access(all) fun createConnectorAndManager(
225 account: auth(Storage, Capabilities) &Account,
226 yieldVaultManagerCap: Capability<auth(FungibleToken.Withdraw) &FlowYieldVaults.YieldVaultManager>,
227 betaBadgeCap: Capability<auth(FlowYieldVaultsClosedBeta.Beta) &FlowYieldVaultsClosedBeta.BetaBadge>,
228 vaultType: Type,
229 strategyType: Type
230 ): Connector {
231 // Validate that the strategy supports the vault type
232 let supportedVaults = FlowYieldVaults.getSupportedInitializationVaults(forStrategy: strategyType)
233 assert(
234 supportedVaults[vaultType] == true,
235 message: "Strategy does not support vault type"
236 )
237
238 // Create and store the YieldVaultManagerWrapper resource
239 let manager <- create YieldVaultManagerWrapper(
240 yieldVaultManagerCap: yieldVaultManagerCap,
241 betaBadgeCap: betaBadgeCap,
242 vaultType: vaultType,
243 strategyType: strategyType
244 )
245
246 account.storage.save(<-manager, to: self.ManagerStoragePath)
247
248 // Create public capability for the manager
249 let managerCap = account.capabilities.storage.issue<&YieldVaultManagerWrapper>(self.ManagerStoragePath)
250 account.capabilities.publish(managerCap, at: self.ManagerPublicPath)
251
252 emit ConnectorCreated(
253 managerAddress: account.address,
254 strategyType: strategyType.identifier,
255 vaultType: vaultType.identifier
256 )
257
258 // Return the struct connector that references this manager
259 return Connector(
260 managerAddress: account.address,
261 vaultType: vaultType
262 )
263 }
264
265 init() {
266 let identifier = "flowYieldVaultsManager_\(self.account.address)"
267 self.ManagerStoragePath = StoragePath(identifier: identifier)!
268 self.ManagerPublicPath = PublicPath(identifier: identifier)!
269 }
270}
271
272