Smart Contract

FungibleTokenConnectors

A.0c237e1265caa7a3.FungibleTokenConnectors

Valid From

131,179,864

Deployed

6d ago
Feb 21, 2026, 03:43:26 PM UTC

Dependents

12 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
3
4import DeFiActionsUtils from 0x6d888f175c158410
5import DeFiActions from 0x6d888f175c158410
6
7/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
8/// THIS CONTRACT IS IN BETA AND IS NOT FINALIZED - INTERFACES MAY CHANGE AND/OR PENDING CHANGES MAY REQUIRE REDEPLOYMENT
9/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10///
11/// FungibleTokenConnectors
12///
13/// This contract defines generic DeFi Actions Sink & Source connector implementations for use with underlying Vault
14/// Capabilities. These connectors can be used alone or in conjunction with other DeFi Actions connectors to create
15/// complex DeFi workflows.
16///
17access(all) contract FungibleTokenConnectors {
18
19    /// VaultSink
20    ///
21    /// A DeFiActions connector that deposits tokens into a Vault
22    ///
23    access(all) struct VaultSink : DeFiActions.Sink {
24        /// The Vault Type accepted by the Sink
25        access(all) let depositVaultType: Type
26        /// The maximum balance of the linked Vault, checked before executing a deposit
27        access(all) let maximumBalance: UFix64
28        /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
29        /// specific Identifier to associated connectors on construction
30        access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
31        /// An unentitled Capability on the Vault to which deposits are distributed
32        access(self) let depositVault: Capability<&{FungibleToken.Vault}>
33
34        init(
35            max: UFix64?,
36            depositVault: Capability<&{FungibleToken.Vault}>,
37            uniqueID: DeFiActions.UniqueIdentifier?
38        ) {
39            pre {
40                depositVault.check(): "Provided invalid Capability"
41                DeFiActionsUtils.definingContractIsFungibleToken(depositVault.borrow()!.getType()):
42                "The contract defining Vault \(depositVault.borrow()!.getType().identifier) does not conform to FungibleToken contract interface"
43                (max ?? UFix64.max) > 0.0:
44                "Maximum balance must be greater than 0.0 if provided"
45            }
46            self.maximumBalance = max ?? UFix64.max // assume no maximum if none provided
47            self.uniqueID = uniqueID
48            self.depositVaultType = depositVault.borrow()!.getType()
49            self.depositVault = depositVault
50        }
51
52        /// Returns a ComponentInfo struct containing information about this VaultSink and its inner DFA components
53        ///
54        /// @return a ComponentInfo struct containing information about this component and a list of ComponentInfo for
55        ///     each inner component in the stack.
56        ///
57        access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
58            return DeFiActions.ComponentInfo(
59                type: self.getType(),
60                id: self.id(),
61                innerComponents: []
62            )
63        }
64        /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
65        /// a DeFiActions stack. See DeFiActions.align() for more information.
66        ///
67        /// @return a copy of the struct's UniqueIdentifier
68        ///
69        access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
70            return self.uniqueID
71        }
72        /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
73        /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
74        ///
75        /// @param id: the UniqueIdentifier to set for this component
76        ///
77        access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
78            self.uniqueID = id
79        }
80        /// Returns the Vault type accepted by this Sink
81        access(all) view fun getSinkType(): Type {
82            return self.depositVaultType
83        }
84        /// Returns an estimate of how much of the associated Vault can be accepted by this Sink
85        access(all) fun minimumCapacity(): UFix64 {
86            if let vault = self.depositVault.borrow() {
87                return vault.balance < self.maximumBalance ? self.maximumBalance - vault.balance : 0.0
88            }
89            return 0.0
90        }
91        /// Deposits up to the Sink's capacity from the provided Vault
92        access(all) fun depositCapacity(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) {
93            let minimumCapacity = self.minimumCapacity()
94            if !self.depositVault.check() || minimumCapacity == 0.0 {
95                return
96            }
97            // deposit the lesser of the originating vault balance and minimum capacity
98            let capacity = minimumCapacity <= from.balance ? minimumCapacity : from.balance
99            self.depositVault.borrow()!.deposit(from: <-from.withdraw(amount: capacity))
100        }
101    }
102
103    /// VaultSource
104    ///
105    /// A DeFiActions connector that withdraws tokens from a Vault
106    ///
107    access(all) struct VaultSource : DeFiActions.Source {
108        /// Returns the Vault type provided by this Source
109        access(all) let withdrawVaultType: Type
110        /// The minimum balance of the linked Vault
111        access(all) let minimumBalance: UFix64
112        /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
113        /// specific Identifier to associated connectors on construction
114        access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
115        /// An entitled Capability on the Vault from which withdrawals are sourced
116        access(self) let withdrawVault: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>
117
118        init(
119            min: UFix64?,
120            withdrawVault: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>,
121            uniqueID: DeFiActions.UniqueIdentifier?
122        ) {
123            pre {
124                withdrawVault.check(): "Provided invalid Capability"
125                DeFiActionsUtils.definingContractIsFungibleToken(withdrawVault.borrow()!.getType()):
126                "The contract defining Vault \(withdrawVault.borrow()!.getType().identifier) does not conform to FungibleToken contract interface"
127            }
128            self.minimumBalance = min ?? 0.0 // assume no minimum if none provided
129            self.withdrawVault = withdrawVault
130            self.uniqueID = uniqueID
131            self.withdrawVaultType = withdrawVault.borrow()!.getType()
132        }
133        /// Returns a ComponentInfo struct containing information about this VaultSource and its inner DFA components
134        ///
135        /// @return a ComponentInfo struct containing information about this component and a list of ComponentInfo for
136        ///     each inner component in the stack.
137        ///
138        access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
139            return DeFiActions.ComponentInfo(
140                type: self.getType(),
141                id: self.id(),
142                innerComponents: []
143            )
144        }
145        /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
146        /// a DeFiActions stack. See DeFiActions.align() for more information.
147        ///
148        /// @return a copy of the struct's UniqueIdentifier
149        ///
150        access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
151            return self.uniqueID
152        }
153        /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
154        /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
155        ///
156        /// @param id: the UniqueIdentifier to set for this component
157        ///
158        access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
159            self.uniqueID = id
160        }
161        /// Returns the Vault type provided by this Source
162        access(all) view fun getSourceType(): Type {
163            return self.withdrawVaultType
164        }
165        /// Returns an estimate of how much of the associated Vault can be provided by this Source
166        access(all) fun minimumAvailable(): UFix64 {
167            if let vault = self.withdrawVault.borrow() {
168                return self.minimumBalance < vault.balance ? vault.balance - self.minimumBalance : 0.0
169            }
170            return 0.0
171        }
172        /// Withdraws the lesser of maxAmount or minimumAvailable(). If none is available, an empty Vault should be
173        /// returned
174        access(FungibleToken.Withdraw) fun withdrawAvailable(maxAmount: UFix64): @{FungibleToken.Vault} {
175            let available = self.minimumAvailable()
176            if !self.withdrawVault.check() || available == 0.0 || maxAmount == 0.0 {
177                return <- DeFiActionsUtils.getEmptyVault(self.withdrawVaultType)
178            }
179            // take the lesser between the available and maximum requested amount
180            let withdrawalAmount = available <= maxAmount ? available : maxAmount
181            return <- self.withdrawVault.borrow()!.withdraw(amount: withdrawalAmount)
182        }
183    }
184
185    /// VaultSinkAndSource
186    ///
187    /// A DeFiActions connector that both deposits and withdraws tokens from a Vault
188    ///
189    access(all) struct VaultSinkAndSource : DeFiActions.Sink, DeFiActions.Source {
190        /// The minimum balance of the linked Vault
191        access(all) let minimumBalance: UFix64
192        /// The maximum balance of the linked Vault
193        access(all) let maximumBalance: UFix64
194        /// The type of Vault this connector accepts (as a Sink) and provides (as a Source)
195        access(all) let vaultType: Type
196        /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
197        /// specific Identifier to associated connectors on construction
198        access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
199        /// An entitled Capability on the Vault from which withdrawals are sourced & deposit are routed
200        access(self) let vault: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>
201
202        init(
203            min: UFix64?,
204            max: UFix64?,
205            vault: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>,
206            uniqueID: DeFiActions.UniqueIdentifier?
207        ) {
208            pre {
209                vault.check(): "Invalid Vault Capability provided"
210                DeFiActionsUtils.definingContractIsFungibleToken(vault.borrow()!.getType()):
211                "The contract defining Vault \(vault.borrow()!.getType().identifier) does not conform to FungibleToken contract interface"
212                min ?? 0.0 < max ?? UFix64.max:
213                "Minimum balance must be less than maximum balance if either is declared"
214            }
215            self.minimumBalance = min ?? 0.0
216            self.maximumBalance = max ?? UFix64.max
217            self.vaultType = vault.borrow()!.getType()
218            self.uniqueID = uniqueID
219            self.vault = vault
220        }
221
222        /// Returns a ComponentInfo struct containing information about this VaultSinkAndSource and its inner DFA components
223        ///
224        /// @return a ComponentInfo struct containing information about this component and a list of ComponentInfo for
225        ///     each inner component in the stack.
226        ///
227        access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
228            return DeFiActions.ComponentInfo(
229                type: self.getType(),
230                id: self.id(),
231                innerComponents: []
232            )
233        }
234        /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
235        /// a DeFiActions stack. See DeFiActions.align() for more information.
236        ///
237        /// @return a copy of the struct's UniqueIdentifier
238        ///
239        access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
240            return self.uniqueID
241        }
242
243        /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
244        /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
245        ///
246        /// @param id: the UniqueIdentifier to set for this component
247        ///
248        access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
249            self.uniqueID = id
250        }
251        /// Returns the Vault type accepted by this Sink
252        access(all) view fun getSinkType(): Type {
253            return self.vaultType
254        }
255        /// Returns the Vault type provided by this Source
256        access(all) view fun getSourceType(): Type {
257            return self.vaultType
258        }
259        /// Returns an estimate of how much of the associated Vault can be accepted by this Sink
260        access(all) fun minimumCapacity(): UFix64 {
261            if let vault = self.vault.borrow() {
262                return vault.balance < self.maximumBalance ? self.maximumBalance - vault.balance : 0.0
263            }
264            return 0.0
265        }
266        /// Returns an estimate of how much of the associated Vault can be provided by this Source
267        access(all) fun minimumAvailable(): UFix64 {
268            if let vault = self.vault.borrow() {
269                return self.minimumBalance < vault.balance ? vault.balance - self.minimumBalance : 0.0
270            }
271            return 0.0
272        }
273        /// Deposits up to the Sink's capacity from the provided Vault
274        access(all) fun depositCapacity(from: auth(FungibleToken.Withdraw) &{FungibleToken.Vault}) {
275            let minimumCapacity = self.minimumCapacity()
276            if !self.vault.check() || minimumCapacity == 0.0 {
277                return
278            }
279            // deposit the lesser of the originating vault balance and minimum capacity
280            let capacity = minimumCapacity <= from.balance ? minimumCapacity : from.balance
281            self.vault.borrow()!.deposit(from: <-from.withdraw(amount: capacity))
282        }
283        /// Withdraws the lesser of maxAmount or minimumAvailable(). If none is available, an empty Vault should be
284        /// returned
285        access(FungibleToken.Withdraw) fun withdrawAvailable(maxAmount: UFix64): @{FungibleToken.Vault} {
286            let available = self.minimumAvailable()
287            if !self.vault.check() || available == 0.0 || maxAmount == 0.0 {
288                return <- DeFiActionsUtils.getEmptyVault(self.vaultType)
289            }
290            // take the lesser between the available and maximum requested amount
291            let withdrawalAmount = available <= maxAmount ? available : maxAmount
292            return <- self.vault.borrow()!.withdraw(amount: withdrawalAmount)
293        }
294    }
295}
296