Smart Contract

IncrementFiFlashloanConnectors

A.e844c7cf7430a77c.IncrementFiFlashloanConnectors

Valid From

131,179,881

Deployed

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

Dependents

20 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import DeFiActions from 0x6d888f175c158410
3import SwapInterfaces from 0xb78ef7afa52ff906
4import SwapConfig from 0xb78ef7afa52ff906
5import SwapFactory from 0xb063c16cac85dbd1
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/// IncrementFiFlashloanConnectors
12///
13/// DeFiActions adapter implementations fitting IncrementFi protocols to the DeFiActions Flasher interface.
14///
15access(all) contract IncrementFiFlashloanConnectors {
16
17    /// Canonical path in which to store the generic FlashLoanExecutor resource
18    access(all) let ExecutorStoragePath: StoragePath
19
20    /* --- CONSTRUCTS --- */
21
22    /// Flasher
23    ///
24    /// A DeFiActions connector that performs flash loans using IncrementFi's SwapPair contract
25    ///
26    access(all) struct Flasher : DeFiActions.Flasher {
27        /// The address of the SwapPair contract to use for flash loans
28        access(all) let pairAddress: Address
29        /// The type of token to borrow
30        access(all) let type: Type
31        /// Capability to the FlashLoanExecutor resource
32        access(self) let executor: Capability<&{SwapInterfaces.FlashLoanExecutor}>
33        /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
34        /// specific Identifier to associated connectors on construction
35        access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
36
37        init(
38            pairAddress: Address,
39            type: Type,
40            executor: Capability<&{SwapInterfaces.FlashLoanExecutor}>,
41            uniqueID: DeFiActions.UniqueIdentifier?
42        ) {
43            pre {
44                executor.check(): "Invalid SwapInterfaces.FlashLoanExecutor capability provided"
45            }
46            let pair = getAccount(pairAddress).capabilities.borrow<&{SwapInterfaces.PairPublic}>(SwapConfig.PairPublicPath)
47                ?? panic("Could not reference SwapPair public capability at address \(pairAddress)")
48            let pairInfo = pair.getPairInfoStruct()
49            assert(pairInfo.token0Key == type.identifier || pairInfo.token1Key == type.identifier,
50                message: "Provided type is not supported by the SwapPair at address \(pairAddress) - "
51                    .concat("valid types for this SwapPair are \(pairInfo.token0Key) and \(pairInfo.token1Key)"))
52            self.pairAddress = pairAddress
53            self.type = type
54            self.executor = executor
55            self.uniqueID = uniqueID
56        }
57
58        /// Returns a ComponentInfo struct containing information about this Flasher and its inner DFA components
59        ///
60        /// @return a ComponentInfo struct containing information about this component and a list of ComponentInfo for
61        ///     each inner component in the stack.
62        ///
63        access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
64            return DeFiActions.ComponentInfo(
65                type: self.getType(),
66                id: self.id(),
67                innerComponents: []
68            )
69        }
70        /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
71        /// a DeFiActions stack. See DeFiActions.align() for more information.
72        ///
73        /// @return a copy of the struct's UniqueIdentifier
74        ///
75        access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
76            return self.uniqueID
77        }
78        /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
79        /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
80        ///
81        /// @param id: the UniqueIdentifier to set for this component
82        ///
83        access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
84            self.uniqueID = id
85        }
86        /// Returns the asset type this Flasher can issue as a flash loan
87        ///
88        /// @return the type of token this Flasher can issue as a flash loan
89        ///
90        access(all) view fun borrowType(): Type {
91            return self.type
92        }
93        /// Returns the estimated fee for a flash loan of the specified amount
94        ///
95        /// @param loanAmount: The amount of tokens to borrow
96        /// @return the estimated fee for a flash loan of the specified amount
97        ///
98        access(all) fun calculateFee(loanAmount: UFix64): UFix64 {
99            return UFix64(SwapFactory.getFlashloanRateBps()) * loanAmount / 10000.0
100        }
101        /// Performs a flash loan of the specified amount. The callback function is passed the fee amount, a Vault
102        /// containing the loan, and the data. The callback function should return a Vault containing the loan + fee.
103        ///
104        /// @param amount: The amount of tokens to borrow
105        /// @param data: Optional data to pass to the callback function
106        /// @param callback: The callback function to use for the flash loan
107        ///
108        access(all) fun flashLoan(
109            amount: UFix64,
110            data: AnyStruct?,
111            callback: fun(UFix64, @{FungibleToken.Vault}, AnyStruct?): @{FungibleToken.Vault} // fee, loan, data
112        ) {
113            // get the SwapPair public capability on which to perform the flash loan
114            let pair = getAccount(self.pairAddress).capabilities.borrow<&{SwapInterfaces.PairPublic}>(
115                    SwapConfig.PairPublicPath
116                ) ?? panic("Could not reference SwapPair public capability at address \(self.pairAddress)")
117
118            // cast data to expected params type and add fee and callback to params for the callback function
119            let params = data as! {String: AnyStruct}? ?? {}
120            params["fee"] = self.calculateFee(loanAmount: amount)
121            params["callback"] = callback
122
123            // perform the flash loan
124            pair.flashloan(
125                executor: self._borrowExecutor(),
126                requestedTokenVaultType: self.type,
127                requestedAmount: amount,
128                params: params
129            )
130        }
131        /// Returns a reference to the FlashLoanExecutor capability
132        ///
133        /// @return a reference to the FlashLoanExecutor capability
134        ///
135        access(self) fun _borrowExecutor(): &{SwapInterfaces.FlashLoanExecutor} {
136            return self.executor.borrow() ?? panic("Could not borrow FlashLoanExecutor capability")
137        }
138    }
139
140    /// FlashLoanExecutor
141    ///
142    /// A resource that implements the SwapInterfaces.FlashLoanExecutor interface and is used to execute flash loans.
143    /// This resource is required to in order to execute flash loans on IncrementFi's SwapPair contract, but is made
144    /// generically to be used in conjunction with the Flasher DeFiActions connector defined in this contract. Instead
145    /// of statically declaring the logic within the Executor's executeAndRepay() function, the callback function is
146    /// passed as a parameter to the executeAndRepay() function via the params object indexed by "callback".
147    ///
148    access(all) resource Executor : SwapInterfaces.FlashLoanExecutor {
149        /// Performs a flash loan of the specified amount. The Flasher.flashLoan() callback function should be found in
150        /// the params object passed to this function under the key "callback". The callback function is passed the fee
151        /// amount, a Vault containing the loan, and the data. The callback function should return a Vault containing
152        /// the loan + fee.
153        access(all) fun executeAndRepay(loanedToken: @{FungibleToken.Vault}, params: {String: AnyStruct}): @{FungibleToken.Vault} {
154            // cast params to expected types and execute the callback
155            let fee = params.remove(key: "fee") as? UFix64 ?? panic("No fee provided in params to executeAndRepay")
156            let callback = params.remove(key: "callback") as? fun(UFix64, @{FungibleToken.Vault}, AnyStruct?): @{FungibleToken.Vault}
157                ?? panic("No callback function provided in params to executeAndRepay")
158
159            // execute the callback logic
160            let repaidToken <- callback(fee, <-loanedToken, params)
161
162            // return the repaid token
163            return <- repaidToken
164        }
165    }
166
167    /* --- PUBLIC FUNCTIONS --- */
168
169    /// Creates a new FlashLoanExecutor resource
170    ///
171    /// @return a new FlashLoanExecutor resource
172    ///
173    access(all) fun createExecutor(): @Executor {
174        return <- create Executor()
175    }
176
177    init() {
178        self.ExecutorStoragePath = StoragePath(identifier: "IncrementFiFlashloanConnectorsExecutor_\(self.account.address)")!
179    }
180}
181