Smart Contract
MorphoERC4626SwapConnectors
A.251032a66e9700ef.MorphoERC4626SwapConnectors
1import Burner from 0xf233dcee88fe0abe
2import FungibleToken from 0xf233dcee88fe0abe
3import EVM from 0xe467b9dd11fa00df
4import FlowEVMBridgeConfig from 0x1e4aa0b87d10b141
5import FlowEVMBridgeUtils from 0x1e4aa0b87d10b141
6import FlowToken from 0x1654653399040a61
7import DeFiActions from 0x6d888f175c158410
8import DeFiActionsUtils from 0x6d888f175c158410
9import MorphoERC4626SinkConnectors from 0x251032a66e9700ef
10import SwapConnectors from 0xe1a479f0cb911df9
11import EVMTokenConnectors from 0x1a771b21fcceadc2
12import ERC4626Utils from 0x04f5ae6bef48c1fc
13import EVMAmountUtils from 0x43c9e8bfec507db4
14
15/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
16/// THIS CONTRACT IS IN BETA AND IS NOT FINALIZED - INTERFACES MAY CHANGE AND/OR PENDING CHANGES MAY REQUIRE REDEPLOYMENT
17/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
18///
19/// MorphoERC4626SwapConnectors
20///
21/// Implements the DeFiActions.Swapper interface to swap asset tokens to 4626 shares, integrating the connector with an
22/// EVM Morpho ERC4626 Vault.
23///
24access(all) contract MorphoERC4626SwapConnectors {
25
26 /// Swapper
27 ///
28 /// An implementation of the DeFiActions.Swapper interface to swap assets to 4626 shares where the input token is
29 /// underlying asset in the 4626 vault. Both the asset & the 4626 shares must be onboarded to the VM bridge in order
30 /// for liquidity to flow between Cadence & EVM. These "swaps" are performed by depositing the input asset into the
31 /// ERC4626 vault and withdrawing the resulting shares from the ERC4626 vault.
32 ///
33 access(all) struct Swapper : DeFiActions.Swapper {
34 /// The asset type serving as the price basis in the ERC4626 vault
35 access(self) let assetType: Type
36 /// The EVM address of the asset ERC20 asset underlying the ERC4626 vault
37 access(self) let assetEVMAddress: EVM.EVMAddress
38 /// The address of the ERC4626 vault
39 access(self) let vaultEVMAddress: EVM.EVMAddress
40 /// The type of the bridged ERC4626 vault
41 access(self) let vaultType: Type
42 /// The token sink to use for the ERC4626 vault
43 access(self) let assetSink: MorphoERC4626SinkConnectors.AssetSink
44 /// The token source to use for the ERC4626 vault
45 access(self) let shareSource: EVMTokenConnectors.Source
46 /// The token sink to bridge ERC4626 shares into the COA/EVM
47 access(self) let shareSink: MorphoERC4626SinkConnectors.ShareSink
48 /// The token source to withdraw underlying assets back from the COA/EVM
49 access(self) let assetSource: EVMTokenConnectors.Source
50 /// The optional UniqueIdentifier of the ERC4626 vault
51 access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
52
53 /// If true, the Swapper is configured "reversed":
54 /// inType = vaultType (shares), outType = assetType (assets)
55 access(self) let isReversed: Bool
56
57 init(
58 vaultEVMAddress: EVM.EVMAddress,
59 coa: Capability<auth(EVM.Call, EVM.Bridge) &EVM.CadenceOwnedAccount>,
60 feeSource: {DeFiActions.Sink, DeFiActions.Source},
61 uniqueID: DeFiActions.UniqueIdentifier?,
62 isReversed: Bool
63 ) {
64 pre {
65 coa.check():
66 "Provided COA Capability is invalid - need Capability<&EVM.CadenceOwnedAccount>"
67
68 feeSource.getSourceType() == Type<@FlowToken.Vault>():
69 "Invalid feeSource - given Source must provide FlowToken Vault, but provides \(feeSource.getSourceType().identifier)"
70 }
71
72 self.uniqueID = uniqueID
73 self.isReversed = isReversed
74
75 self.vaultEVMAddress = vaultEVMAddress
76 self.vaultType = FlowEVMBridgeConfig.getTypeAssociated(with: self.vaultEVMAddress)
77 ?? panic("Provided ERC4626 Vault \(self.vaultEVMAddress.toString()) is not associated with a Cadence FungibleToken - ensure the type & ERC4626 contracts are associated via the VM bridge")
78 assert(
79 DeFiActionsUtils.definingContractIsFungibleToken(self.vaultType),
80 message: "Derived vault type \(self.vaultType.identifier) not FungibleToken type"
81 )
82
83 self.assetEVMAddress = ERC4626Utils.underlyingAssetEVMAddress(vault: self.vaultEVMAddress)
84 ?? panic("Cannot get an underlying asset EVM address from the vault")
85 self.assetType = FlowEVMBridgeConfig.getTypeAssociated(with: self.assetEVMAddress)
86 ?? panic("Underlying asset for vault \(self.vaultEVMAddress.toString()) (asset \(self.assetEVMAddress.toString())) is not associated with a Cadence FungibleToken - ensure the type & underlying asset contracts are associated via the VM bridge")
87 assert(
88 DeFiActionsUtils.definingContractIsFungibleToken(self.assetType),
89 message: "Derived asset type \(self.assetType.identifier) not FungibleToken type"
90 )
91
92 self.assetSink = MorphoERC4626SinkConnectors.AssetSink(
93 vaultEVMAddress: self.vaultEVMAddress,
94 coa: coa,
95 feeSource: feeSource,
96 uniqueID: self.uniqueID
97 )
98 self.shareSource = EVMTokenConnectors.Source(
99 min: nil,
100 withdrawVaultType: self.vaultType,
101 coa: coa,
102 feeSource: feeSource,
103 uniqueID: self.uniqueID
104 )
105
106 self.shareSink = MorphoERC4626SinkConnectors.ShareSink(
107 vaultEVMAddress: self.vaultEVMAddress,
108 coa: coa,
109 feeSource: feeSource,
110 uniqueID: self.uniqueID
111 )
112
113 self.assetSource = EVMTokenConnectors.Source(
114 min: nil,
115 withdrawVaultType: self.assetType,
116 coa: coa,
117 feeSource: feeSource,
118 uniqueID: self.uniqueID
119 )
120 }
121
122 // -------------------------
123 // Direction-aware in/out
124 // -------------------------
125
126 access(all) view fun inType(): Type {
127 return self.isReversed ? self.vaultType : self.assetType
128 }
129
130 access(all) view fun outType(): Type {
131 return self.isReversed ? self.assetType : self.vaultType
132 }
133
134 access(self) fun quoteRequiredAssetsForShares(desiredShares: UFix64): {DeFiActions.Quote} {
135 let desiredSharesEVM = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(
136 desiredShares,
137 erc20Address: self.vaultEVMAddress
138 )
139
140 if let requiredAssetsEVM = ERC4626Utils.previewMint(vault: self.vaultEVMAddress, shares: desiredSharesEVM) {
141 let maxAssetsEVM = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(
142 UFix64.max,
143 erc20Address: self.assetEVMAddress
144 )
145 let requiredAssetsEVMSafe = requiredAssetsEVM < maxAssetsEVM ? requiredAssetsEVM : maxAssetsEVM
146 let assetDecimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: self.assetEVMAddress)
147 let requiredAssets = EVMAmountUtils.toCadenceIn(
148 requiredAssetsEVMSafe,
149 decimals: assetDecimals
150 )
151
152 return SwapConnectors.BasicQuote(
153 inType: self.assetType,
154 outType: self.vaultType,
155 inAmount: requiredAssets,
156 outAmount: desiredShares
157 )
158 }
159
160 return SwapConnectors.BasicQuote(
161 inType: self.assetType,
162 outType: self.vaultType,
163 inAmount: 0.0,
164 outAmount: 0.0
165 )
166 }
167
168 access(self) fun quoteRequiredSharesForAssets(desiredAssets: UFix64): {DeFiActions.Quote} {
169 let desiredAssetsEVM = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(
170 desiredAssets,
171 erc20Address: self.assetEVMAddress
172 )
173
174 if let requiredSharesEVM = ERC4626Utils.previewWithdraw(vault: self.vaultEVMAddress, assets: desiredAssetsEVM) {
175 let maxSharesEVM = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(
176 UFix64.max,
177 erc20Address: self.vaultEVMAddress
178 )
179 let requiredSharesEVMSafe = requiredSharesEVM < maxSharesEVM ? requiredSharesEVM : maxSharesEVM
180 let shareDecimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: self.vaultEVMAddress)
181 let requiredShares = EVMAmountUtils.toCadenceIn(
182 requiredSharesEVMSafe,
183 decimals: shareDecimals
184 )
185
186 return SwapConnectors.BasicQuote(
187 inType: self.vaultType,
188 outType: self.assetType,
189 inAmount: requiredShares,
190 outAmount: desiredAssets
191 )
192 }
193
194 return SwapConnectors.BasicQuote(
195 inType: self.vaultType,
196 outType: self.assetType,
197 inAmount: 0.0,
198 outAmount: 0.0
199 )
200 }
201
202 // --------------------------------------------------------------------
203 // Direction model
204 //
205 // Canonical "forward" direction for this connector is:
206 // assets (underlying ERC20) -> shares (ERC4626 vault token)
207 //
208 // The effective swap / quote direction is determined by TWO flags:
209 //
210 // 1. self.isReversed
211 // - false: connector is configured in canonical forward mode
212 // - true: connector is configured reversed (shares -> assets)
213 //
214 // 2. reverse (method parameter)
215 // - false: quote/swap in the connector's configured direction
216 // - true: quote/swap in the opposite direction
217 //
218 // The resulting direction is:
219 //
220 // assetsToShares = (self.isReversed == reverse)
221 //
222 // Truth table:
223 //
224 // isReversed | reverse | effective direction
225 // -----------+---------+--------------------
226 // false | false | assets -> shares
227 // false | true | shares -> assets
228 // true | false | shares -> assets
229 // true | true | assets -> shares
230 //
231 // This same rule is used consistently for:
232 // - quoteIn / quoteOut
233 // - swap / swapBack (with different fallbacks)
234 // --------------------------------------------------------------------
235
236 /// desired OUT amount -> required IN amount
237 access(all) fun quoteIn(forDesired: UFix64, reverse: Bool): {DeFiActions.Quote} {
238 // canonical forward = assets -> shares
239 // effective assets->shares when isReversed == reverse
240 let assetsToShares = (self.isReversed == reverse)
241
242 return assetsToShares
243 ? self.quoteRequiredAssetsForShares(desiredShares: forDesired)
244 : self.quoteRequiredSharesForAssets(desiredAssets: forDesired)
245 }
246 access(self) fun quoteSharesOutForAssetsIn(providedAssets: UFix64): {DeFiActions.Quote} {
247 let providedAssetsEVM = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(
248 providedAssets,
249 erc20Address: self.assetEVMAddress
250 )
251
252 if let sharesOutEVM = ERC4626Utils.previewDeposit(vault: self.vaultEVMAddress, assets: providedAssetsEVM) {
253 let shareDecimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: self.vaultEVMAddress)
254 let sharesOut = EVMAmountUtils.toCadenceOut(
255 sharesOutEVM,
256 decimals: shareDecimals
257 )
258
259 return SwapConnectors.BasicQuote(
260 inType: self.assetType,
261 outType: self.vaultType,
262 inAmount: providedAssets,
263 outAmount: sharesOut
264 )
265 }
266
267 return SwapConnectors.BasicQuote(
268 inType: self.assetType,
269 outType: self.vaultType,
270 inAmount: 0.0,
271 outAmount: 0.0
272 )
273 }
274
275 access(self) fun quoteAssetsOutForSharesIn(providedShares: UFix64): {DeFiActions.Quote} {
276 let providedSharesEVM = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(
277 providedShares,
278 erc20Address: self.vaultEVMAddress
279 )
280
281 if let assetsOutEVM = ERC4626Utils.previewRedeem(vault: self.vaultEVMAddress, shares: providedSharesEVM) {
282 let assetDecimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: self.assetEVMAddress)
283 let assetsOut = EVMAmountUtils.toCadenceOut(
284 assetsOutEVM,
285 decimals: assetDecimals
286 )
287
288 return SwapConnectors.BasicQuote(
289 inType: self.vaultType,
290 outType: self.assetType,
291 inAmount: providedShares,
292 outAmount: assetsOut
293 )
294 }
295
296 return SwapConnectors.BasicQuote(
297 inType: self.vaultType,
298 outType: self.assetType,
299 inAmount: 0.0,
300 outAmount: 0.0
301 )
302 }
303
304 /// provided IN amount -> estimated OUT amount
305 access(all) fun quoteOut(forProvided: UFix64, reverse: Bool): {DeFiActions.Quote} {
306 // canonical forward = assets -> shares
307 // effective assets->shares when isReversed == reverse
308 let assetsToShares = (self.isReversed == reverse)
309
310 return assetsToShares
311 ? self.quoteSharesOutForAssetsIn(providedAssets: forProvided)
312 : self.quoteAssetsOutForSharesIn(providedShares: forProvided)
313 }
314
315 // -------------------------
316 // Swap internals
317 // -------------------------
318
319 /// Performs a swap taking a Vault of type inVault, outputting a resulting outVault. Implementations may choose
320 /// to swap along a pre-set path or an optimal path of a set of paths or even set of contained Swappers adapted
321 /// to use multiple Flow swap protocols.
322 access(self) fun swapAssetsToShares(
323 quote: {DeFiActions.Quote}?,
324 inVault: @{FungibleToken.Vault}
325 ): @{FungibleToken.Vault} {
326 if inVault.balance == 0.0 {
327 Burner.burn(<-inVault)
328 return <- DeFiActionsUtils.getEmptyVault(self.vaultType)
329 }
330
331 // assign or get the quote for the swap
332 let _quote = quote ?? self.quoteSharesOutForAssetsIn(providedAssets: inVault.balance)
333 let outAmount = _quote.outAmount
334
335 assert(_quote.inType == self.assetType, message: "Swap: Quote inType mismatch (expected asset)")
336 assert(_quote.outType == self.vaultType, message: "Swap: Quote outType mismatch (expected shares)")
337 assert(_quote.inAmount > 0.0, message: "Invalid quote: inAmount must be > 0")
338 assert(outAmount > 0.0, message: "Invalid quote: outAmount must be > 0")
339
340 // --- Slippage protection: don't allow spending more than quoted ---
341 let beforeInBalance = inVault.balance
342 assert(
343 beforeInBalance <= _quote.inAmount,
344 message: "Swap input (\(beforeInBalance)) exceeds quote.inAmount (\(_quote.inAmount)). Provide an updated quote or reduce inVault balance."
345 )
346
347 // Track shares available before/after to determine received shares
348 let beforeAvailable = self.shareSource.minimumAvailable()
349
350 // Deposit the inVault into the asset sink (should consume all of it)
351 self.assetSink.depositCapacity(from: &inVault as auth(FungibleToken.Withdraw) &{FungibleToken.Vault})
352
353 let remainder = inVault.balance
354 let consumedIn = beforeInBalance - remainder
355
356 // We expect full consumption in this connector's semantics.
357 // If this ever becomes "partial fill" in the future, this check + price check below
358 // ensures it still can't be worse than quoted.
359 assert(consumedIn > 0.0, message: "Asset sink did not consume any input.")
360 assert(remainder == 0.0, message: "Asset sink did not consume full input; remainder: \(remainder.toString()).")
361
362 Burner.burn(<-inVault)
363
364 // get the after available shares
365 let afterAvailable = self.shareSource.minimumAvailable()
366 assert(afterAvailable > beforeAvailable, message: "Expected ERC4626 Vault \(self.vaultEVMAddress.toString()) to have more shares after depositing")
367
368 // withdraw the available difference in shares
369 let receivedShares = afterAvailable - beforeAvailable
370
371 // --- Slippage protection: ensure minimum out ---
372 assert(
373 receivedShares >= outAmount,
374 message: "Slippage: received \(receivedShares) < quote.outAmount (\(outAmount))."
375 )
376
377 let sharesVault <- self.shareSource.withdrawAvailable(maxAmount: receivedShares)
378
379 // Extra safety: ensure the vault we’re returning matches the computed delta
380 // (withdrawAvailable could theoretically return less if liquidity changed)
381 assert(
382 sharesVault.balance >= outAmount,
383 message: "Slippage: withdrawn shares \(sharesVault.balance) < outAmount (\(outAmount))."
384 )
385
386 return <- sharesVault
387 }
388
389 access(self) fun swapSharesToAssets(
390 quote: {DeFiActions.Quote}?,
391 inVault: @{FungibleToken.Vault}
392 ): @{FungibleToken.Vault} {
393 if inVault.balance == 0.0 {
394 Burner.burn(<-inVault)
395 return <- DeFiActionsUtils.getEmptyVault(self.assetType)
396 }
397
398 // assign or get a quote from the swap
399 let _quote = quote ?? self.quoteAssetsOutForSharesIn(providedShares: inVault.balance)
400 let outAmount = _quote.outAmount
401
402 // Ensure the quote represents the inverse of this connector’s forward swap:
403 // swapback must take this connector’s outType and return its inType.
404 // These checks prevent executing a quote meant for a different connector
405 // or accidentally performing a forward swap instead of a reversal.
406 assert(_quote.inType == self.vaultType, message: "Swap: Quote inType mismatch (expected shares)")
407 assert(_quote.outType == self.assetType, message: "Swap: Quote outType mismatch (expected asset)")
408 assert(_quote.inAmount > 0.0, message: "Invalid quote: inAmount must be > 0")
409 assert(outAmount > 0.0, message: "Invalid quote: outAmount must be > 0")
410
411 // Track assets available before/after to determine received assets
412 let beforeInBalance = inVault.balance
413 assert(
414 beforeInBalance <= _quote.inAmount,
415 message: "Swap input (\(beforeInBalance)) exceeds quote.inAmount (\(_quote.inAmount)). Provide an updated quote or reduce inVault balance."
416 )
417
418 let beforeAvailable = self.assetSource.minimumAvailable()
419
420 self.shareSink.depositCapacity(from: &inVault as auth(FungibleToken.Withdraw) &{FungibleToken.Vault})
421
422 let remainder = inVault.balance
423 let consumedIn = beforeInBalance - remainder
424
425 assert(consumedIn > 0.0, message: "Share sink did not consume any input.")
426 assert(remainder == 0.0, message: "Share sink did not consume full input; remainder: \(remainder.toString()).")
427
428 Burner.burn(<-inVault)
429
430 let afterAvailable = self.assetSource.minimumAvailable()
431 assert(afterAvailable > beforeAvailable, message: "Expected more assets after depositing")
432
433 let receivedAssets = afterAvailable - beforeAvailable
434
435 // Derive the expected output from previewRedeem of the actual consumed shares rather
436 // than the quote's outAmount. The quote may have been generated via quoteIn (using
437 // previewWithdraw which rounds up shares), then passed through MultiSwapper which
438 // preserves the desired outAmount. Since redeem rounds down assets (vault-favorable),
439 // the actual output can be less than the quoted outAmount. Using previewRedeem of the
440 // consumed shares gives the correct floor for the slippage check.
441 let consumedSharesEVM = FlowEVMBridgeUtils.convertCadenceAmountToERC20Amount(
442 consumedIn,
443 erc20Address: self.vaultEVMAddress
444 )
445 var expectedOut = outAmount
446 if let previewOutEVM = ERC4626Utils.previewRedeem(vault: self.vaultEVMAddress, shares: consumedSharesEVM) {
447 let assetDecimals = FlowEVMBridgeUtils.getTokenDecimals(evmContractAddress: self.assetEVMAddress)
448 let previewOut = EVMAmountUtils.toCadenceOut(
449 previewOutEVM,
450 decimals: assetDecimals
451 )
452 if previewOut < expectedOut {
453 expectedOut = previewOut
454 }
455 }
456
457 assert(receivedAssets >= expectedOut, message: "Slippage: received < quote.outAmount")
458
459 let assetsVault <- self.assetSource.withdrawAvailable(maxAmount: receivedAssets)
460 assert(assetsVault.balance >= expectedOut, message: "Slippage: withdrawn assets < outAmount")
461
462 return <- assetsVault
463 }
464
465 // -------------------------
466 // Direction-aware swap entrypoints
467 // -------------------------
468
469 access(self) fun quoteIndicatesAssetsToShares(_ q: {DeFiActions.Quote}): Bool {
470 return q.inType == self.assetType && q.outType == self.vaultType
471 }
472
473 access(self) fun quoteIndicatesSharesToAssets(_ q: {DeFiActions.Quote}): Bool {
474 return q.inType == self.vaultType && q.outType == self.assetType
475 }
476
477 access(self) fun decideAssetsToShares(
478 quote: {DeFiActions.Quote}?,
479 fallbackAssetsToShares: Bool
480 ): Bool {
481 if quote == nil {
482 return fallbackAssetsToShares
483 }
484 assert(
485 self.quoteIndicatesAssetsToShares(quote!) || self.quoteIndicatesSharesToAssets(quote!),
486 message: "Quote types not recognized for this connector"
487 )
488 return self.quoteIndicatesAssetsToShares(quote!)
489 }
490
491 access(self) fun assertInputVaultType(
492 _ vault: &{FungibleToken.Vault},
493 assetsToShares: Bool,
494 context: String
495 ) {
496 let expectedType = assetsToShares ? self.assetType : self.vaultType
497 assert(
498 vault.getType() == expectedType,
499 message: "\(context): input vault type mismatch. Expected \(expectedType.identifier), got \(vault.getType().identifier)"
500 )
501 }
502
503 access(all) fun swap(
504 quote: {DeFiActions.Quote}?,
505 inVault: @{FungibleToken.Vault}
506 ): @{FungibleToken.Vault} {
507 // Decide direction:
508 // - if quote provided, trust its type pair
509 // - else fall back to configured direction (isReversed)
510 let assetsToShares = self.decideAssetsToShares(quote: quote, fallbackAssetsToShares: !self.isReversed)
511
512 self.assertInputVaultType(
513 &inVault as &{FungibleToken.Vault},
514 assetsToShares: assetsToShares,
515 context: "Swap"
516 )
517
518 if assetsToShares {
519 return <- self.swapAssetsToShares(quote: quote, inVault: <-inVault)
520 }
521 return <- self.swapSharesToAssets(quote: quote, inVault: <-inVault)
522 }
523
524 /// Performs a swap taking a Vault of type outVault, outputting a resulting inVault. Implementations may choose
525 /// to swap along a pre-set path or an optimal path of a set of paths or even set of contained Swappers adapted
526 /// to use multiple Flow swap protocols.
527 access(all) fun swapBack(
528 quote: {DeFiActions.Quote}?,
529 residual: @{FungibleToken.Vault}
530 ): @{FungibleToken.Vault} {
531 // Decide direction:
532 // - if quote provided, trust its type pair
533 // - else fall back to configured direction (isReversed)
534 let assetsToShares = self.decideAssetsToShares(quote: quote, fallbackAssetsToShares: self.isReversed)
535
536 self.assertInputVaultType(
537 &residual as &{FungibleToken.Vault},
538 assetsToShares: assetsToShares,
539 context: "SwapBack"
540 )
541
542 if assetsToShares {
543 return <- self.swapAssetsToShares(quote: quote, inVault: <-residual)
544 }
545 return <- self.swapSharesToAssets(quote: quote, inVault: <-residual)
546 }
547
548 /// Returns a ComponentInfo struct containing information about this component and a list of ComponentInfo for
549 /// each inner component in the stack.
550 access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
551 return DeFiActions.ComponentInfo(
552 type: self.getType(),
553 id: self.id(),
554 innerComponents: [
555 self.assetSink.getComponentInfo(),
556 self.shareSource.getComponentInfo(),
557 self.shareSink.getComponentInfo(),
558 self.assetSource.getComponentInfo()
559 ]
560 )
561 }
562 /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
563 /// a DeFiActions stack. See DeFiActions.align() for more information.
564 ///
565 /// @return a copy of the struct's UniqueIdentifier
566 ///
567 access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
568 return self.uniqueID
569 }
570 /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
571 /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
572 ///
573 /// @param id: the UniqueIdentifier to set for this component
574 ///
575 access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
576 self.uniqueID = id
577 }
578 }
579}
580