Smart Contract
DeFiActions
A.92195d814edf9cb0.DeFiActions
1import Burner from 0xf233dcee88fe0abe
2import ViewResolver from 0x1d7e57aa55817448
3import FungibleToken from 0xf233dcee88fe0abe
4
5import DeFiActionsUtils from 0x92195d814edf9cb0
6import DeFiActionsMathUtils from 0x92195d814edf9cb0
7
8/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
9/// THIS CONTRACT IS IN BETA AND IS NOT FINALIZED - INTERFACES MAY CHANGE AND/OR PENDING CHANGES MAY REQUIRE REDEPLOYMENT
10/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
11///
12/// [BETA] DeFiActions
13///
14/// DeFiActions is a library of small DeFi components that act as glue to connect typical DeFi primitives (dexes, lending
15/// pools, farms) into individual aggregations.
16///
17/// The core component of DeFiActions is the “Connector”; a conduit between the more complex pieces of the DeFi puzzle.
18/// Connectors aren't to do anything especially complex, but make it simple and straightforward to connect the
19/// traditional DeFi pieces together into new, custom aggregations.
20///
21/// Connectors should be thought of analogously with the small text processing tools of Unix that are mostly meant to be
22/// connected with pipe operations instead of being operated individually. All Connectors are either a “Source” or
23/// “Sink”.
24///
25access(all) contract DeFiActions {
26
27 /* --- FIELDS --- */
28
29 /// The current ID assigned to UniqueIdentifiers as they are initialized
30 /// It is incremented by 1 every time a UniqueIdentifier is created so each ID is only ever used once
31 access(all) var currentID: UInt64
32 /// The AuthenticationToken Capability required to create a UniqueIdentifier
33 access(self) let authTokenCap: Capability<auth(Identify) &AuthenticationToken>
34 /// The StoragePath for the AuthenticationToken resource
35 access(self) let AuthTokenStoragePath: StoragePath
36
37 /* --- INTERFACE-LEVEL EVENTS --- */
38
39 /// Emitted when value is deposited to a Sink
40 access(all) event Deposited(
41 type: String,
42 amount: UFix64,
43 fromUUID: UInt64,
44 uniqueID: UInt64?,
45 sinkType: String
46 )
47 /// Emitted when value is withdrawn from a Source
48 access(all) event Withdrawn(
49 type: String,
50 amount: UFix64,
51 withdrawnUUID: UInt64,
52 uniqueID: UInt64?,
53 sourceType: String
54 )
55 /// Emitted when a Swapper executes a Swap
56 access(all) event Swapped(
57 inVault: String,
58 outVault: String,
59 inAmount: UFix64,
60 outAmount: UFix64,
61 inUUID: UInt64,
62 outUUID: UInt64,
63 uniqueID: UInt64?,
64 swapperType: String
65 )
66 /// Emitted when a Flasher executes a flash loan
67 access(all) event Flashed(
68 requestedAmount: UFix64,
69 borrowType: String,
70 uniqueID: UInt64?,
71 flasherType: String
72 )
73 /// Emitted when an IdentifiableResource's UniqueIdentifier is aligned with another DFA component
74 access(all) event UpdatedID(
75 oldID: UInt64?,
76 newID: UInt64?,
77 component: String,
78 uuid: UInt64?
79 )
80 /// Emitted when an AutoBalancer is created
81 access(all) event CreatedAutoBalancer(
82 lowerThreshold: UFix64,
83 upperThreshold: UFix64,
84 vaultType: String,
85 vaultUUID: UInt64,
86 uuid: UInt64,
87 uniqueID: UInt64?
88 )
89 /// Emitted when AutoBalancer.rebalance() is called
90 access(all) event Rebalanced(
91 amount: UFix64,
92 value: UFix64,
93 unitOfAccount: String,
94 isSurplus: Bool,
95 vaultType: String,
96 vaultUUID: UInt64,
97 balancerUUID: UInt64,
98 address: Address?,
99 uuid: UInt64,
100 uniqueID: UInt64?
101 )
102
103 /* --- CONSTRUCTS --- */
104
105 access(all) entitlement Identify
106
107 /// AuthenticationToken
108 ///
109 /// A resource intended to ensure UniqueIdentifiers are only created by the DeFiActions contract
110 ///
111 access(all) resource AuthenticationToken {}
112
113 /// UniqueIdentifier
114 ///
115 /// This construct enables protocols to trace stack operations via DeFiActions interface-level events, identifying
116 /// them by UniqueIdentifier IDs. IdentifiableResource Implementations should ensure that access to them is
117 /// encapsulated by the structures they are used to identify.
118 ///
119 access(all) struct UniqueIdentifier {
120 /// The ID value of this UniqueIdentifier
121 access(all) let id: UInt64
122 /// The AuthenticationToken Capability required to create this UniqueIdentifier. Since this is a struct which
123 /// can be created in any context, this authorized Capability ensures that the UniqueIdentifier can only be
124 /// created by the DeFiActions contract, thus preventing forged UniqueIdentifiers from being created.
125 access(self) let authCap: Capability<auth(Identify) &AuthenticationToken>
126
127 access(contract) view init(_ id: UInt64, _ authCap: Capability<auth(Identify) &AuthenticationToken>) {
128 pre {
129 authCap.check(): "Invalid AuthenticationToken Capability provided"
130 }
131 self.id = id
132 self.authCap = authCap
133 }
134 }
135
136 /// ComponentInfo
137 ///
138 /// A struct containing minimal information about a DeFiActions component and its inner components
139 ///
140 access(all) struct ComponentInfo {
141 /// The type of the component
142 access(all) let type: Type
143 /// The UniqueIdentifier.id of the component
144 access(all) let id: UInt64?
145 /// The inner component types of the serving component
146 access(all) let innerComponents: [ComponentInfo]
147 init(
148 type: Type,
149 id: UInt64?,
150 innerComponents: [ComponentInfo]
151 ) {
152 self.type = type
153 self.id = id
154 self.innerComponents = innerComponents
155 }
156 }
157
158 /// Extend entitlement allowing for the authorized copying of UniqueIdentifiers from existing components
159 access(all) entitlement Extend
160
161 /// IdentifiableResource
162 ///
163 /// A resource interface containing a UniqueIdentifier and convenience getters about it
164 ///
165 access(all) struct interface IdentifiableStruct {
166 /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
167 /// specific Identifier to associated connectors on construction
168 access(contract) var uniqueID: UniqueIdentifier?
169 /// Convenience method returning the inner UniqueIdentifier's id or `nil` if none is set.
170 ///
171 /// NOTE: This interface method may be spoofed if the function is overridden, so callers should not rely on it
172 /// for critical identification unless the implementation itself is known and trusted
173 access(all) view fun id(): UInt64? {
174 return self.uniqueID?.id
175 }
176 /// Returns a ComponentInfo struct containing information about this component and a list of ComponentInfo for
177 /// each inner component in the stack.
178 access(all) fun getComponentInfo(): ComponentInfo
179 /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
180 /// a DeFiActions stack. See DeFiActions.align() for more information.
181 access(contract) view fun copyID(): UniqueIdentifier? {
182 post {
183 result?.id == self.uniqueID?.id:
184 "UniqueIdentifier of \(self.getType().identifier) was not successfully copied"
185 }
186 }
187 /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
188 /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
189 access(contract) fun setID(_ id: UniqueIdentifier?) {
190 post {
191 self.uniqueID?.id == id?.id:
192 "UniqueIdentifier of \(self.getType().identifier) was not successfully set"
193 DeFiActions.emitUpdatedID(
194 oldID: before(self.uniqueID?.id),
195 newID: self.uniqueID?.id,
196 component: self.getType().identifier,
197 uuid: nil // no UUID for structs
198 ): "Unknown error emitting DeFiActions.UpdatedID from IdentifiableStruct \(self.getType().identifier) with ID ".concat(self.id()?.toString() ?? "UNASSIGNED")
199 }
200 }
201 }
202
203 /// IdentifiableResource
204 ///
205 /// A resource interface containing a UniqueIdentifier and convenience getters about it
206 ///
207 access(all) resource interface IdentifiableResource {
208 /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
209 /// specific Identifier to associated connectors on construction
210 access(contract) var uniqueID: UniqueIdentifier?
211 /// Convenience method returning the inner UniqueIdentifier's id or `nil` if none is set.
212 ///
213 /// NOTE: This interface method may be spoofed if the function is overridden, so callers should not rely on it
214 /// for critical identification unless the implementation itself is known and trusted
215 access(all) view fun id(): UInt64? {
216 return self.uniqueID?.id
217 }
218 /// Returns a ComponentInfo struct containing information about this component and a list of ComponentInfo for
219 /// each inner component in the stack.
220 access(all) fun getComponentInfo(): ComponentInfo
221 /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
222 /// a DeFiActions stack. See DeFiActions.align() for more information.
223 access(contract) view fun copyID(): UniqueIdentifier? {
224 post {
225 result?.id == self.uniqueID?.id:
226 "UniqueIdentifier of \(self.getType().identifier) was not successfully copied"
227 }
228 }
229 /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
230 /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
231 access(contract) fun setID(_ id: UniqueIdentifier?) {
232 post {
233 self.uniqueID?.id == id?.id:
234 "UniqueIdentifier of \(self.getType().identifier) was not successfully set"
235 DeFiActions.emitUpdatedID(
236 oldID: before(self.uniqueID?.id),
237 newID: self.uniqueID?.id,
238 component: self.getType().identifier,
239 uuid: self.uuid
240 ): "Unknown error emitting DeFiActions.UpdatedID from IdentifiableStruct \(self.getType().identifier) with ID ".concat(self.id()?.toString() ?? "UNASSIGNED")
241 }
242 }
243 }
244
245 /// Sink
246 ///
247 /// A Sink Connector (or just “Sink”) is analogous to the Fungible Token Receiver interface that accepts deposits of
248 /// funds. It differs from the standard Receiver interface in that it is a struct interface (instead of resource
249 /// interface) and allows for the graceful handling of Sinks that have a limited capacity on the amount they can
250 /// accept for deposit. Implementations should therefore avoid the possibility of reversion with graceful fallback
251 /// on unexpected conditions, executing no-ops instead of reverting.
252 ///
253 access(all) struct interface Sink : IdentifiableStruct {
254 /// Returns the Vault type accepted by this Sink
255 access(all) view fun getSinkType(): Type
256 /// Returns an estimate of how much can be withdrawn from the depositing Vault for this Sink to reach capacity
257 access(all) fun minimumCapacity(): UFix64
258 /// Deposits up to the Sink's capacity from the provided Vault
259 access(all) fun depositCapacity(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) {
260 pre {
261 from.getType() == self.getSinkType():
262 "Invalid vault provided for deposit - \(from.getType().identifier) is not \(self.getSinkType().identifier)"
263 }
264 post {
265 DeFiActions.emitDeposited(
266 type: from.getType().identifier,
267 beforeBalance: before(from.balance),
268 afterBalance: from.balance,
269 fromUUID: from.uuid,
270 uniqueID: self.uniqueID?.id,
271 sinkType: self.getType().identifier
272 ): "Unknown error emitting DeFiActions.Withdrawn from Sink \(self.getType().identifier) with ID ".concat(self.id()?.toString() ?? "UNASSIGNED")
273 }
274 }
275 }
276
277 /// Source
278 ///
279 /// A Source Connector (or just “Source”) is analogous to the Fungible Token Provider interface that provides funds
280 /// on demand. It differs from the standard Provider interface in that it is a struct interface (instead of resource
281 /// interface) and allows for graceful handling of the case that the Source might not know exactly the total amount
282 /// of funds available to be withdrawn. Implementations should therefore avoid the possibility of reversion with
283 /// graceful fallback on unexpected conditions, executing no-ops or returning an empty Vault instead of reverting.
284 ///
285 access(all) struct interface Source : IdentifiableStruct {
286 /// Returns the Vault type provided by this Source
287 access(all) view fun getSourceType(): Type
288 /// Returns an estimate of how much of the associated Vault Type can be provided by this Source
289 access(all) fun minimumAvailable(): UFix64
290 /// Withdraws the lesser of maxAmount or minimumAvailable(). If none is available, an empty Vault should be
291 /// returned
292 access(FungibleToken.Withdraw) fun withdrawAvailable(maxAmount: UFix64): @{FungibleToken.Vault} {
293 post {
294 result.getType() == self.getSourceType():
295 "Invalid vault provided for withdraw - \(result.getType().identifier) is not \(self.getSourceType().identifier)"
296 DeFiActions.emitWithdrawn(
297 type: result.getType().identifier,
298 amount: result.balance,
299 withdrawnUUID: result.uuid,
300 uniqueID: self.uniqueID?.id ?? nil,
301 sourceType: self.getType().identifier
302 ): "Unknown error emitting DeFiActions.Withdrawn from Source \(self.getType().identifier) with ID ".concat(self.id()?.toString() ?? "UNASSIGNED")
303 }
304 }
305 }
306
307 /// Quote
308 ///
309 /// An interface for an estimate to be returned by a Swapper when asking for a swap estimate. This may be helpful
310 /// for passing additional parameters to a Swapper relevant to the use case. Implementations may choose to add
311 /// fields relevant to their Swapper implementation and downcast in swap() and/or swapBack() scope.
312 ///
313 access(all) struct interface Quote {
314 /// The quoted pre-swap Vault type
315 access(all) let inType: Type
316 /// The quoted post-swap Vault type
317 access(all) let outType: Type
318 /// The quoted amount of pre-swap currency
319 access(all) let inAmount: UFix64
320 /// The quoted amount of post-swap currency for the defined inAmount
321 access(all) let outAmount: UFix64
322 }
323
324 /// Swapper
325 ///
326 /// A basic interface for a struct that swaps between tokens. Implementations may choose to adapt this interface
327 /// to fit any given swap protocol or set of protocols.
328 ///
329 access(all) struct interface Swapper : IdentifiableStruct {
330 /// The type of Vault this Swapper accepts when performing a swap
331 access(all) view fun inType(): Type
332 /// The type of Vault this Swapper provides when performing a swap
333 access(all) view fun outType(): Type
334 /// The estimated amount required to provide a Vault with the desired output balance
335 access(all) fun quoteIn(forDesired: UFix64, reverse: Bool): {Quote} // fun quoteIn/Out
336 /// The estimated amount delivered out for a provided input balance
337 access(all) fun quoteOut(forProvided: UFix64, reverse: Bool): {Quote}
338 /// Performs a swap taking a Vault of type inVault, outputting a resulting outVault. Implementations may choose
339 /// to swap along a pre-set path or an optimal path of a set of paths or even set of contained Swappers adapted
340 /// to use multiple Flow swap protocols.
341 access(all) fun swap(quote: {Quote}?, inVault: @{FungibleToken.Vault}): @{FungibleToken.Vault} {
342 pre {
343 inVault.getType() == self.inType():
344 "Invalid vault provided for swap - \(inVault.getType().identifier) is not \(self.inType().identifier)"
345 (quote?.inType ?? inVault.getType()) == inVault.getType():
346 "Quote.inType type \(quote!.inType.identifier) does not match the provided inVault \(inVault.getType().identifier)"
347 }
348 post {
349 emit Swapped(
350 inVault: before(inVault.getType().identifier),
351 outVault: result.getType().identifier,
352 inAmount: before(inVault.balance),
353 outAmount: result.balance,
354 inUUID: before(inVault.uuid),
355 outUUID: result.uuid,
356 uniqueID: self.uniqueID?.id ?? nil,
357 swapperType: self.getType().identifier
358 )
359 }
360 }
361 /// Performs a swap taking a Vault of type outVault, outputting a resulting inVault. Implementations may choose
362 /// to swap along a pre-set path or an optimal path of a set of paths or even set of contained Swappers adapted
363 /// to use multiple Flow swap protocols.
364 // TODO: Impl detail - accept quote that was just used by swap() but reverse the direction assuming swap() was just called
365 access(all) fun swapBack(quote: {Quote}?, residual: @{FungibleToken.Vault}): @{FungibleToken.Vault} {
366 pre {
367 residual.getType() == self.outType():
368 "Invalid vault provided for swapBack - \(residual.getType().identifier) is not \(self.outType().identifier)"
369 }
370 post {
371 emit Swapped(
372 inVault: before(residual.getType().identifier),
373 outVault: result.getType().identifier,
374 inAmount: before(residual.balance),
375 outAmount: result.balance,
376 inUUID: before(residual.uuid),
377 outUUID: result.uuid,
378 uniqueID: self.uniqueID?.id ?? nil,
379 swapperType: self.getType().identifier
380 )
381 }
382 }
383 }
384
385 /// PriceOracle
386 ///
387 /// An interface for a price oracle adapter. Implementations should adapt this interface to various price feed
388 /// oracles deployed on Flow
389 ///
390 access(all) struct interface PriceOracle : IdentifiableStruct {
391 /// Returns the asset type serving as the price basis - e.g. USD in FLOW/USD
392 access(all) view fun unitOfAccount(): Type
393 /// Returns the latest price data for a given asset denominated in unitOfAccount() if available, otherwise `nil`
394 /// should be returned. Callers should note that although an optional is supported, implementations may choose
395 /// to revert.
396 access(all) fun price(ofToken: Type): UFix64?
397 }
398
399 /// Flasher
400 ///
401 /// An interface for a flash loan adapter. Implementations should adapt this interface to various flash loan
402 /// protocols deployed on Flow
403 ///
404 access(all) struct interface Flasher : IdentifiableStruct {
405 /// Returns the asset type this Flasher can issue as a flash loan
406 access(all) view fun borrowType(): Type
407 /// Returns the estimated fee for a flash loan of the specified amount
408 access(all) fun calculateFee(loanAmount: UFix64): UFix64
409 /// Performs a flash loan of the specified amount. The callback function is passed the fee amount, a Vault
410 /// containing the loan, and the data. The callback function should return a Vault containing the loan + fee.
411 access(all) fun flashLoan(
412 amount: UFix64,
413 data: AnyStruct?,
414 callback: fun(UFix64, @{FungibleToken.Vault}, AnyStruct?): @{FungibleToken.Vault} // fee, loan, data
415 ) {
416 post {
417 emit Flashed(
418 requestedAmount: amount,
419 borrowType: self.borrowType().identifier,
420 uniqueID: self.uniqueID?.id ?? nil,
421 flasherType: self.getType().identifier
422 )
423 }
424 }
425 }
426
427 /*******************************************************************************************************************
428 NOTICE: The AutoBalancer will extend the FlowCallbackScheduler.CallbackHandler interface which is not yet
429 finalized. To avoid the need for re-deploying with that interface and related fields managing ScheduleCallback
430 structs, the AutoBalancer and its connectors are omitted from the DeFiActions contract on Testnet & Mainnet
431 until the FlowCallbackScheduler contract is available.
432 *******************************************************************************************************************/
433
434 // /// AutoBalancerSink
435 // ///
436 // /// A DeFiActions Sink enabling the deposit of funds to an underlying AutoBalancer resource. As written, this Source
437 // /// may be used with externally defined AutoBalancer implementations
438 // ///
439 // access(all) struct AutoBalancerSink : Sink {
440 // /// The Type this Sink accepts
441 // access(self) let type: Type
442 // /// An authorized Capability on the underlying AutoBalancer where funds are deposited
443 // access(self) let autoBalancer: Capability<&AutoBalancer>
444 // /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
445 // /// specific Identifier to associated connectors on construction
446 // access(contract) var uniqueID: UniqueIdentifier?
447
448 // init(autoBalancer: Capability<&AutoBalancer>, uniqueID: UniqueIdentifier?) {
449 // pre {
450 // autoBalancer.check():
451 // "Invalid AutoBalancer Capability Provided"
452 // }
453 // self.type = autoBalancer.borrow()!.vaultType()
454 // self.autoBalancer = autoBalancer
455 // self.uniqueID = uniqueID
456 // }
457
458 // /// Returns the Vault type accepted by this Sink
459 // access(all) view fun getSinkType(): Type {
460 // return self.type
461 // }
462 // /// Returns an estimate of how much can be withdrawn from the depositing Vault for this Sink to reach capacity
463 // /// can currently only be UFix64.max or 0.0
464 // access(all) fun minimumCapacity(): UFix64 {
465 // return self.autoBalancer.check() ? UFix64.max : 0.0
466 // }
467 // /// Deposits up to the Sink's capacity from the provided Vault
468 // access(all) fun depositCapacity(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) {
469 // if let ab = self.autoBalancer.borrow() {
470 // ab.deposit(from: <-from.withdraw(amount: from.balance))
471 // }
472 // return
473 // }
474 // /// Returns a ComponentInfo struct containing information about this component and a list of ComponentInfo for
475 // /// each inner component in the stack.
476 // access(all) fun getComponentInfo(): ComponentInfo {
477 // return ComponentInfo(
478 // type: self.getType(),
479 // id: self.id(),
480 // innerComponents: []
481 // )
482 // }
483 // /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
484 // /// a DeFiActions stack. See DeFiActions.align() for more information.
485 // access(contract) view fun copyID(): UniqueIdentifier? {
486 // return self.uniqueID
487 // }
488 // /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
489 // /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
490 // access(contract) fun setID(_ id: UniqueIdentifier?) {
491 // self.uniqueID = id
492 // }
493 // }
494
495 // /// AutoBalancerSource
496 // ///
497 // /// A DeFiActions Source targeting an underlying AutoBalancer resource. As written, this Source may be used with
498 // /// externally defined AutoBalancer implementations
499 // ///
500 // access(all) struct AutoBalancerSource : Source {
501 // /// The Type this Source provides
502 // access(self) let type: Type
503 // /// An authorized Capability on the underlying AutoBalancer where funds are sourced
504 // access(self) let autoBalancer: Capability<auth(FungibleToken.Withdraw) &AutoBalancer>
505 // /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
506 // /// specific Identifier to associated connectors on construction
507 // access(contract) var uniqueID: UniqueIdentifier?
508
509 // init(autoBalancer: Capability<auth(FungibleToken.Withdraw) &AutoBalancer>, uniqueID: UniqueIdentifier?) {
510 // pre {
511 // autoBalancer.check():
512 // "Invalid AutoBalancer Capability Provided"
513 // }
514 // self.type = autoBalancer.borrow()!.vaultType()
515 // self.autoBalancer = autoBalancer
516 // self.uniqueID = uniqueID
517 // }
518
519 // /// Returns the Vault type provided by this Source
520 // access(all) view fun getSourceType(): Type {
521 // return self.type
522 // }
523 // /// Returns an estimate of how much of the associated Vault Type can be provided by this Source
524 // access(all) fun minimumAvailable(): UFix64 {
525 // if let ab = self.autoBalancer.borrow() {
526 // return ab.vaultBalance()
527 // }
528 // return 0.0
529 // }
530 // /// Withdraws the lesser of maxAmount or minimumAvailable(). If none is available, an empty Vault should be
531 // /// returned
532 // access(FungibleToken.Withdraw) fun withdrawAvailable(maxAmount: UFix64): @{FungibleToken.Vault} {
533 // if let ab = self.autoBalancer.borrow() {
534 // return <-ab.withdraw(
535 // amount: maxAmount <= ab.vaultBalance() ? maxAmount : ab.vaultBalance()
536 // )
537 // }
538 // return <- DeFiActionsUtils.getEmptyVault(self.type)
539 // }
540 // /// Returns a ComponentInfo struct containing information about this component and a list of ComponentInfo for
541 // /// each inner component in the stack.
542 // access(all) fun getComponentInfo(): ComponentInfo {
543 // return ComponentInfo(
544 // type: self.getType(),
545 // id: self.id(),
546 // innerComponents: []
547 // )
548 // }
549 // /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
550 // /// a DeFiActions stack. See DeFiActions.align() for more information.
551 // access(contract) view fun copyID(): UniqueIdentifier? {
552 // return self.uniqueID
553 // }
554 // /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
555 // /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
556 // access(contract) fun setID(_ id: UniqueIdentifier?) {
557 // self.uniqueID = id
558 // }
559 // }
560
561 // /// Entitlement used by the AutoBalancer to set inner Sink and Source
562 // access(all) entitlement Auto
563 // access(all) entitlement Set
564 // access(all) entitlement Get
565
566 // /// AutoBalancer
567 // ///
568 // /// A resource designed to enable permissionless rebalancing of value around a wrapped Vault. An
569 // /// AutoBalancer can be a critical component of DeFiActions stacks by allowing for strategies to compound, repay
570 // /// loans or direct accumulated value to other sub-systems and/or user Vaults.
571 // ///
572 // access(all) resource AutoBalancer : IdentifiableResource, FungibleToken.Receiver, FungibleToken.Provider, ViewResolver.Resolver, Burner.Burnable {
573 // /// The value in deposits & withdrawals over time denominated in oracle.unitOfAccount()
574 // access(self) var _valueOfDeposits: UFix64
575 // /// The percentage low and high thresholds defining when a rebalance executes
576 // /// Index 0 is low, index 1 is high
577 // access(self) var _rebalanceRange: [UFix64; 2]
578 // /// Oracle used to track the baseValue for deposits & withdrawals over time
579 // access(self) let _oracle: {PriceOracle}
580 // /// The inner Vault's Type captured for the ResourceDestroyed event
581 // access(self) let _vaultType: Type
582 // /// Vault used to deposit & withdraw from made optional only so the Vault can be burned via Burner.burn() if the
583 // /// AutoBalancer is burned and the Vault's burnCallback() can be called in the process
584 // access(self) var _vault: @{FungibleToken.Vault}?
585 // /// An optional Sink used to deposit excess funds from the inner Vault once the converted value exceeds the
586 // /// rebalance range. This Sink may be used to compound yield into a position or direct excess value to an
587 // /// external Vault
588 // access(self) var _rebalanceSink: {Sink}?
589 // /// An optional Source used to deposit excess funds to the inner Vault once the converted value is below the
590 // /// rebalance range
591 // access(self) var _rebalanceSource: {Source}?
592 // /// Capability on this AutoBalancer instance
593 // access(self) var _selfCap: Capability<auth(FungibleToken.Withdraw) &AutoBalancer>?
594 // /// An optional UniqueIdentifier tying this AutoBalancer to a given stack
595 // access(contract) var uniqueID: UniqueIdentifier?
596
597 // /// Emitted when the AutoBalancer is destroyed
598 // access(all) event ResourceDestroyed(
599 // uuid: UInt64 = self.uuid,
600 // vaultType: String = self._vaultType.identifier,
601 // balance: UFix64? = self._vault?.balance,
602 // uniqueID: UInt64? = self.uniqueID?.id
603 // )
604
605 // init(
606 // lower: UFix64,
607 // upper: UFix64,
608 // oracle: {PriceOracle},
609 // vaultType: Type,
610 // outSink: {Sink}?,
611 // inSource: {Source}?,
612 // uniqueID: UniqueIdentifier?
613 // ) {
614 // pre {
615 // lower < upper && 0.01 <= lower && lower < 1.0 && 1.0 < upper && upper < 2.0:
616 // "Invalid rebalanceRange [lower, upper]: [\(lower), \(upper)] - thresholds must be set such that 0.01 <= lower < 1.0 and 1.0 < upper < 2.0 relative to value of deposits"
617 // DeFiActionsUtils.definingContractIsFungibleToken(vaultType):
618 // "The contract defining Vault \(vaultType.identifier) does not conform to FungibleToken contract interface"
619 // }
620 // assert(oracle.price(ofToken: vaultType) != nil,
621 // message: "Provided Oracle \(oracle.getType().identifier) could not provide a price for vault \(vaultType.identifier)")
622 // self._valueOfDeposits = 0.0
623 // self._rebalanceRange = [lower, upper]
624 // self._oracle = oracle
625 // self._vault <- DeFiActionsUtils.getEmptyVault(vaultType)
626 // self._vaultType = vaultType
627 // self._rebalanceSink = outSink
628 // self._rebalanceSource = inSource
629 // self._selfCap = nil
630 // self.uniqueID = uniqueID
631
632 // emit CreatedAutoBalancer(
633 // lowerThreshold: lower,
634 // upperThreshold: upper,
635 // vaultType: vaultType.identifier,
636 // vaultUUID: self._borrowVault().uuid,
637 // uuid: self.uuid,
638 // uniqueID: self.id()
639 // )
640 // }
641
642 // /* Core AutoBalancer Functionality */
643
644 // /// Returns the balance of the inner Vault
645 // ///
646 // /// @return the current balance of the inner Vault
647 // ///
648 // access(all) view fun vaultBalance(): UFix64 {
649 // return self._borrowVault().balance
650 // }
651 // /// Returns the Type of the inner Vault
652 // ///
653 // /// @return the Type of the inner Vault
654 // ///
655 // access(all) view fun vaultType(): Type {
656 // return self._borrowVault().getType()
657 // }
658 // /// Returns the low and high rebalance thresholds as a fixed length UFix64 containing [low, high]
659 // ///
660 // /// @return a sorted fixed-length array containing the relative lower and upper thresholds conditioning
661 // /// rebalance execution
662 // ///
663 // access(all) view fun rebalanceThresholds(): [UFix64; 2] {
664 // return self._rebalanceRange
665 // }
666 // /// Returns the value of all accounted deposits/withdraws as they have occurred denominated in unitOfAccount.
667 // /// The returned value is the value as tracked historically, not necessarily the current value of the inner
668 // /// Vault's balance.
669 // ///
670 // /// @return the historical value of deposits
671 // ///
672 // access(all) view fun valueOfDeposits(): UFix64 {
673 // return self._valueOfDeposits
674 // }
675 // /// Returns the token Type serving as the price basis of this AutoBalancer
676 // ///
677 // /// @return the price denomination of value of the underlying vault as returned from the inner PriceOracle
678 // ///
679 // access(all) view fun unitOfAccount(): Type {
680 // return self._oracle.unitOfAccount()
681 // }
682 // /// Returns the current value of the inner Vault's balance. If a price is not available from the AutoBalancer's
683 // /// PriceOracle, `nil` is returned
684 // ///
685 // /// @return the current value of the inner's Vault's balance denominated in unitOfAccount() if a price is
686 // /// available, `nil` otherwise
687 // ///
688 // access(all) fun currentValue(): UFix64? {
689 // if let price = self._oracle.price(ofToken: self.vaultType()) {
690 // return price * self._borrowVault().balance
691 // }
692 // return nil
693 // }
694 // /// Returns a ComponentInfo struct containing information about this AutoBalancer and its inner DFA components
695 // ///
696 // /// @return a ComponentInfo struct containing information about this component and a list of ComponentInfo for
697 // /// each inner component in the stack.
698 // ///
699 // access(all) fun getComponentInfo(): ComponentInfo {
700 // // get the inner components
701 // let oracle = self._borrowOracle()
702 // let inner: [ComponentInfo] = [oracle.getComponentInfo()]
703
704 // // get the info for the optional inner components if they exist
705 // let maybeSink = self._borrowSink()
706 // let maybeSource = self._borrowSource()
707 // if let sink = maybeSink {
708 // inner.append(sink.getComponentInfo())
709 // }
710 // if let source = maybeSource {
711 // inner.append(source.getComponentInfo())
712 // }
713
714 // // create the ComponentInfo for the AutoBalancer and insert it at the beginning of the list
715 // return ComponentInfo(
716 // type: self.getType(),
717 // id: self.id(),
718 // innerComponents: inner
719 // )
720 // }
721 // /// Convenience method issuing a Sink allowing for deposits to this AutoBalancer. If the AutoBalancer's
722 // /// Capability on itself is not set or is invalid, `nil` is returned.
723 // ///
724 // /// @return a Sink routing deposits to this AutoBalancer
725 // ///
726 // access(all) fun createBalancerSink(): {Sink}? {
727 // if self._selfCap == nil || !self._selfCap!.check() {
728 // return nil
729 // }
730 // return AutoBalancerSink(autoBalancer: self._selfCap!, uniqueID: self.uniqueID)
731 // }
732 // /// Convenience method issuing a Source enabling withdrawals from this AutoBalancer. If the AutoBalancer's
733 // /// Capability on itself is not set or is invalid, `nil` is returned.
734 // ///
735 // /// @return a Source routing withdrawals from this AutoBalancer
736 // ///
737 // access(Get) fun createBalancerSource(): {Source}? {
738 // if self._selfCap == nil || !self._selfCap!.check() {
739 // return nil
740 // }
741 // return AutoBalancerSource(autoBalancer: self._selfCap!, uniqueID: self.uniqueID)
742 // }
743 // /// A setter enabling an AutoBalancer to set a Sink to which overflow value should be deposited
744 // ///
745 // /// @param sink: The optional Sink DeFiActions connector from which funds are sourced when this AutoBalancer
746 // /// current value rises above the upper threshold relative to its valueOfDeposits(). If `nil`, overflown
747 // /// value will not rebalance
748 // ///
749 // access(Set) fun setSink(_ sink: {Sink}?, updateSinkID: Bool) {
750 // if sink != nil && updateSinkID {
751 // let toUpdate = &sink! as auth(Extend) &{IdentifiableStruct}
752 // let toAlign = &self as auth(Identify) &{IdentifiableResource}
753 // DeFiActions.alignID(toUpdate: toUpdate, with: toAlign)
754 // }
755 // self._rebalanceSink = sink
756 // }
757 // /// A setter enabling an AutoBalancer to set a Source from which underflow value should be withdrawn
758 // ///
759 // /// @param source: The optional Source DeFiActions connector from which funds are sourced when this AutoBalancer
760 // /// current value falls below the lower threshold relative to its valueOfDeposits(). If `nil`, underflown
761 // /// value will not rebalance
762 // ///
763 // access(Set) fun setSource(_ source: {Source}?, updateSourceID: Bool) {
764 // if source != nil && updateSourceID {
765 // let toUpdate = &source! as auth(Extend) &{IdentifiableStruct}
766 // let toAlign = &self as auth(Identify) &{IdentifiableResource}
767 // DeFiActions.alignID(toUpdate: toUpdate, with: toAlign)
768 // }
769 // self._rebalanceSource = source
770 // }
771 // /// Enables the setting of a Capability on the AutoBalancer for the distribution of Sinks & Sources targeting
772 // /// the AutoBalancer instance. Due to the mechanisms of Capabilities, this must be done after the AutoBalancer
773 // /// has been saved to account storage and an authorized Capability has been issued.
774 // access(Set) fun setSelfCapability(_ cap: Capability<auth(FungibleToken.Withdraw) &AutoBalancer>) {
775 // pre {
776 // self._selfCap == nil || self._selfCap!.check() != true:
777 // "Internal AutoBalancer Capability has been set and is still valid - cannot be re-assigned"
778 // cap.check(): "Invalid AutoBalancer Capability provided"
779 // self.getType() == cap.borrow()!.getType() && self.uuid == cap.borrow()!.uuid:
780 // "Provided Capability does not target this AutoBalancer of type \(self.getType().identifier) with UUID \(self.uuid) - "
781 // .concat("provided Capability for AutoBalancer of type \(cap.borrow()!.getType().identifier) with UUID \(cap.borrow()!.uuid)")
782 // }
783 // self._selfCap = cap
784 // }
785 // /// Sets the rebalance range of this AutoBalancer
786 // ///
787 // /// @param range: a sorted array containing lower and upper thresholds that condition rebalance execution. The
788 // /// thresholds must be values such that 0.01 <= range[0] < 1.0 && 1.0 < range[1] < 2.0
789 // ///
790 // access(Set) fun setRebalanceRange(_ range: [UFix64; 2]) {
791 // pre {
792 // range[0] < range[1] && 0.01 <= range[0] && range[0] < 1.0 && 1.0 < range[1] && range[1] < 2.0:
793 // "Invalid rebalanceRange [lower, upper]: [\(range[0]), \(range[1])] - thresholds must be set such that 0.01 <= range[0] < 1.0 and 1.0 < range[1] < 2.0 relative to value of deposits"
794 // }
795 // self._rebalanceRange = range
796 // }
797 // /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
798 // /// a DeFiActions stack. See DeFiActions.align() for more information.
799 // access(contract) view fun copyID(): UniqueIdentifier? {
800 // return self.uniqueID
801 // }
802 // /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
803 // /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
804 // access(contract) fun setID(_ id: UniqueIdentifier?) {
805 // self.uniqueID = id
806 // }
807 // /// Allows for external parties to call on the AutoBalancer and execute a rebalance according to it's rebalance
808 // /// parameters. This method must be called by external party regularly in order for rebalancing to occur.
809 // ///
810 // /// @param force: if false, rebalance will occur only when beyond upper or lower thresholds; if true, rebalance
811 // /// will execute as long as a price is available via the oracle and the current value is non-zero
812 // ///
813 // access(Auto) fun rebalance(force: Bool) {
814 // let currentPrice = self._oracle.price(ofToken: self._vaultType)
815 // if currentPrice == nil {
816 // return // no price available -> do nothing
817 // }
818 // let currentValue = self.currentValue()!
819 // // calculate the difference between the current value and the historical value of deposits
820 // var valueDiff: UFix64 = currentValue < self._valueOfDeposits ? self._valueOfDeposits - currentValue : currentValue - self._valueOfDeposits
821 // // if deficit detected, choose lower threshold, otherwise choose upper threshold
822 // let isDeficit = currentValue < self._valueOfDeposits
823 // let threshold = isDeficit ? (1.0 - self._rebalanceRange[0]) : (self._rebalanceRange[1] - 1.0)
824
825 // if currentPrice == 0.0 || valueDiff == 0.0 || ((valueDiff / self._valueOfDeposits) < threshold && !force) {
826 // // division by zero, no difference, or difference does not exceed rebalance ratio & not forced -> no-op
827 // return
828 // }
829
830 // let vault = self._borrowVault()
831 // //var amount = valueDiff / currentPrice!
832 // var amount = DeFiActionsMathUtils.divUFix64WithRounding(valueDiff, currentPrice!)
833 // var executed = false
834 // let maybeRebalanceSource = &self._rebalanceSource as auth(FungibleToken.Withdraw) &{Source}?
835 // let maybeRebalanceSink = &self._rebalanceSink as &{Sink}?
836 // if isDeficit && maybeRebalanceSource != nil {
837 // // rebalance back up to baseline sourcing funds from _rebalanceSource
838 // vault.deposit(from: <- maybeRebalanceSource!.withdrawAvailable(maxAmount: amount))
839 // executed = true
840 // } else if !isDeficit && maybeRebalanceSink != nil {
841 // // rebalance back down to baseline depositing excess to _rebalanceSink
842 // if amount > vault.balance {
843 // amount = vault.balance // protect underflow
844 // }
845 // let surplus <- vault.withdraw(amount: amount)
846 // maybeRebalanceSink!.depositCapacity(from: &surplus as auth(FungibleToken.Withdraw) &{FungibleToken.Vault})
847 // executed = true
848 // if surplus.balance == 0.0 {
849 // Burner.burn(<-surplus) // could destroy
850 // } else {
851 // amount = amount - surplus.balance // update the rebalanced amount
852 // valueDiff = valueDiff - (surplus.balance * currentPrice!) // update the value difference
853 // vault.deposit(from: <-surplus) // deposit any excess not taken by the Sink
854 // }
855 // }
856 // // emit event only if rebalance was executed
857 // if executed {
858 // emit Rebalanced(
859 // amount: amount,
860 // value: valueDiff,
861 // unitOfAccount: self.unitOfAccount().identifier,
862 // isSurplus: !isDeficit,
863 // vaultType: self.vaultType().identifier,
864 // vaultUUID: self._borrowVault().uuid,
865 // balancerUUID: self.uuid,
866 // address: self.owner?.address,
867 // uuid: self.uuid,
868 // uniqueID: self.id()
869 // )
870 // }
871 // }
872
873 // /* ViewResolver.Resolver conformance */
874
875 // /// Passthrough to inner Vault's view Types
876 // access(all) view fun getViews(): [Type] {
877 // return self._borrowVault().getViews()
878 // }
879 // /// Passthrough to inner Vault's view resolution
880 // access(all) fun resolveView(_ view: Type): AnyStruct? {
881 // return self._borrowVault().resolveView(view)
882 // }
883
884 // /* FungibleToken.Receiver & .Provider conformance */
885
886 // /// Only the nested Vault type is supported by this AutoBalancer for deposits & withdrawal for the sake of
887 // /// single asset accounting
888 // access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
889 // return { self.vaultType(): true }
890 // }
891 // /// True if the provided Type is the nested Vault Type, false otherwise
892 // access(all) view fun isSupportedVaultType(type: Type): Bool {
893 // return self.getSupportedVaultTypes()[type] == true
894 // }
895 // /// Passthrough to the inner Vault's isAvailableToWithdraw() method
896 // access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
897 // return self._borrowVault().isAvailableToWithdraw(amount: amount)
898 // }
899 // /// Deposits the provided Vault to the nested Vault if it is of the same Type, reverting otherwise. In the
900 // /// process, the current value of the deposited amount (denominated in unitOfAccount) increments the
901 // /// AutoBalancer's baseValue. If a price is not available via the internal PriceOracle, an average price is
902 // /// calculated base on the inner vault balance & valueOfDeposits and valueOfDeposits is incremented by the
903 // /// value of the deposited vault on the basis of that average
904 // access(all) fun deposit(from: @{FungibleToken.Vault}) {
905 // pre {
906 // from.getType() == self.vaultType():
907 // "Invalid Vault type \(from.getType().identifier) deposited - this AutoBalancer only accepts \(self.vaultType().identifier)"
908 // }
909 // // if no price available use an average price based on historical value of deposits and inner vault balance
910 // let price = self._oracle.price(ofToken: from.getType()) ?? (self.valueOfDeposits() / self.vaultBalance())
911 // self._valueOfDeposits = self._valueOfDeposits + (from.balance * price)
912 // self._borrowVault().deposit(from: <-from)
913 // }
914 // /// Returns the requested amount of the nested Vault type, reducing the baseValue by the current value
915 // /// (denominated in unitOfAccount) of the token amount. The AutoBalancer's valueOfDeposits is decremented
916 // /// in proportion to the amount withdrawn relative to the inner Vault's balance
917 // access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} {
918 // pre {
919 // amount <= self.vaultBalance(): "Withdraw amount \(amount) exceeds current vault balance \(self.vaultBalance())"
920 // }
921 // if amount == 0.0 {
922 // return <- self._borrowVault().createEmptyVault()
923 // }
924 // // adjust historical value of deposits proportionate to the amount withdrawn & return withdrawn vault
925 // // self._valueOfDeposits = (1.0 - amount / self.vaultBalance()) * self._valueOfDeposits
926 // let proportion: UFix64 = 1.0 - DeFiActionsMathUtils.divUFix64WithRounding(amount, self.vaultBalance())
927 // let newValue = self._valueOfDeposits * proportion
928 // self._valueOfDeposits = newValue
929 // return <- self._borrowVault().withdraw(amount: amount)
930 // }
931
932 // /* Burnable.Burner conformance */
933
934 // /// Executed in Burner.burn(). Passes along the inner vault to be burned, executing the inner Vault's
935 // /// burnCallback() logic
936 // access(contract) fun burnCallback() {
937 // let vault <- self._vault <- nil
938 // Burner.burn(<-vault) // executes the inner Vault's burnCallback()
939 // }
940
941 // /* Internal */
942
943 // /// Returns a reference to the inner Vault
944 // access(self) view fun _borrowVault(): auth(FungibleToken.Withdraw) &{FungibleToken.Vault} {
945 // return (&self._vault)!
946 // }
947 // /// Returns a reference to the inner Vault
948 // access(self) view fun _borrowOracle(): &{PriceOracle} {
949 // return &self._oracle
950 // }
951 // /// Returns a reference to the inner Vault
952 // access(self) view fun _borrowSink(): &{Sink}? {
953 // return &self._rebalanceSink
954 // }
955 // /// Returns a reference to the inner Source
956 // access(self) view fun _borrowSource(): auth(FungibleToken.Withdraw) &{Source}? {
957 // return &self._rebalanceSource as auth(FungibleToken.Withdraw) &{Source}?
958 // }
959 // }
960
961 // /* --- PUBLIC METHODS --- */
962
963 // /// Returns an AutoBalancer wrapping the provided Vault.
964 // ///
965 // /// @param oracle: The oracle used to query deposited & withdrawn value and to determine if a rebalance should execute
966 // /// @param vault: The Vault wrapped by the AutoBalancer
967 // /// @param rebalanceRange: The percentage range from the AutoBalancer's base value at which a rebalance is executed
968 // /// @param outSink: An optional DeFiActions Sink to which excess value is directed when rebalancing
969 // /// @param inSource: An optional DeFiActions Source from which value is withdrawn to the inner vault when rebalancing
970 // /// @param uniqueID: An optional DeFiActions UniqueIdentifier used for identifying rebalance events
971 // ///
972 // access(all) fun createAutoBalancer(
973 // oracle: {PriceOracle},
974 // vaultType: Type,
975 // lowerThreshold: UFix64,
976 // upperThreshold: UFix64,
977 // rebalanceSink: {Sink}?,
978 // rebalanceSource: {Source}?,
979 // uniqueID: UniqueIdentifier?
980 // ): @AutoBalancer {
981 // let ab <- create AutoBalancer(
982 // lower: lowerThreshold,
983 // upper: upperThreshold,
984 // oracle: oracle,
985 // vaultType: vaultType,
986 // outSink: rebalanceSink,
987 // inSource: rebalanceSource,
988 // uniqueID: uniqueID
989 // )
990 // return <- ab
991 // }
992
993 /// Creates a new UniqueIdentifier used for identifying action stacks
994 ///
995 /// @return a new UniqueIdentifier
996 ///
997 access(all) fun createUniqueIdentifier(): UniqueIdentifier {
998 let id = UniqueIdentifier(self.currentID, self.authTokenCap)
999 self.currentID = self.currentID + 1
1000 return id
1001 }
1002
1003 /// Aligns the UniqueIdentifier of the provided component with the provided component, setting the UniqueIdentifier of
1004 /// the provided component to the UniqueIdentifier of the provided component. Parameters are AnyStruct to allow for
1005 /// alignment of both IdentifiableStruct and IdentifiableResource. However, note that the provided component must
1006 /// be an auth(Extend) &{IdentifiableStruct} or auth(Extend) &{IdentifiableResource} to be aligned.
1007 ///
1008 /// @param toUpdate: The component to update the UniqueIdentifier of. Must be an auth(Extend) &{IdentifiableStruct}
1009 /// or auth(Extend) &{IdentifiableResource}
1010 /// @param with: The component to align the UniqueIdentifier of the provided component with. Must be an
1011 /// auth(Identify) &{IdentifiableStruct} or auth(Identify) &{IdentifiableResource}
1012 ///
1013 access(all) fun alignID(toUpdate: AnyStruct, with: AnyStruct) {
1014 let maybeISToUpdate = toUpdate as? auth(Extend) &{IdentifiableStruct}
1015 let maybeIRToUpdate = toUpdate as? auth(Extend) &{IdentifiableResource}
1016 let maybeISWith = with as? auth(Identify) &{IdentifiableStruct}
1017 let maybeIRWith = with as? auth(Identify) &{IdentifiableResource}
1018
1019 if maybeISToUpdate != nil && maybeISWith != nil {
1020 maybeISToUpdate!.setID(maybeISWith!.copyID())
1021 } else if maybeISToUpdate != nil && maybeIRWith != nil {
1022 maybeISToUpdate!.setID(maybeIRWith!.copyID())
1023 } else if maybeIRToUpdate != nil && maybeISWith != nil {
1024 maybeIRToUpdate!.setID(maybeISWith!.copyID())
1025 } else if maybeIRToUpdate != nil && maybeIRWith != nil {
1026 maybeIRToUpdate!.setID(maybeIRWith!.copyID())
1027 }
1028 return
1029 }
1030
1031 /* --- INTERNAL CONDITIONAL EVENT EMITTERS --- */
1032
1033 /// Emits Deposited event if a change in balance is detected
1034 access(self) view fun emitDeposited(
1035 type: String,
1036 beforeBalance: UFix64,
1037 afterBalance: UFix64,
1038 fromUUID: UInt64,
1039 uniqueID: UInt64?,
1040 sinkType: String
1041 ): Bool {
1042 if beforeBalance == afterBalance {
1043 return true
1044 }
1045 emit Deposited(
1046 type: type,
1047 amount: beforeBalance > afterBalance ? beforeBalance - afterBalance : afterBalance - beforeBalance,
1048 fromUUID: fromUUID,
1049 uniqueID: uniqueID,
1050 sinkType: sinkType
1051 )
1052 return true
1053 }
1054
1055 /// Emits Withdrawn event if a change in balance is detected
1056 access(self) view fun emitWithdrawn(
1057 type: String,
1058 amount: UFix64,
1059 withdrawnUUID: UInt64,
1060 uniqueID: UInt64?,
1061 sourceType: String
1062 ): Bool {
1063 if amount == 0.0 {
1064 return true
1065 }
1066 emit Withdrawn(
1067 type: type,
1068 amount: amount,
1069 withdrawnUUID: withdrawnUUID,
1070 uniqueID: uniqueID,
1071 sourceType: sourceType
1072 )
1073 return true
1074 }
1075
1076 /// Emits Aligned event if a change in UniqueIdentifier is detected
1077 access(self) view fun emitUpdatedID(
1078 oldID: UInt64?,
1079 newID: UInt64?,
1080 component: String,
1081 uuid: UInt64?
1082 ): Bool {
1083 if oldID == newID {
1084 return true
1085 }
1086 emit UpdatedID(
1087 oldID: oldID,
1088 newID: newID,
1089 component: component,
1090 uuid: uuid
1091 )
1092 return true
1093 }
1094
1095 init() {
1096 self.currentID = 0
1097 self.AuthTokenStoragePath = /storage/authToken
1098
1099 self.account.storage.save(<-create AuthenticationToken(), to: self.AuthTokenStoragePath)
1100 self.authTokenCap = self.account.capabilities.storage.issue<auth(Identify) &AuthenticationToken>(self.AuthTokenStoragePath)
1101
1102 assert(self.authTokenCap.check(), message: "Failed to issue AuthenticationToken Capability")
1103 }
1104}
1105