Smart Contract

IncrementFiSwapConnectors

A.efa9bd7d1b17f1ed.IncrementFiSwapConnectors

Valid From

122,643,900

Deployed

5d ago
Feb 22, 2026, 06:34:46 AM UTC

Dependents

38 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import Burner from 0xf233dcee88fe0abe
3
4import SwapInterfaces from 0xb78ef7afa52ff906
5import SwapConfig from 0xb78ef7afa52ff906
6import SwapFactory from 0xb063c16cac85dbd1
7import SwapRouter from 0xa6850776a94e6551
8import SwapConnectors from 0x0bce04a00aedf132
9import DeFiActions from 0x92195d814edf9cb0
10
11/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12/// THIS CONTRACT IS IN BETA AND IS NOT FINALIZED - INTERFACES MAY CHANGE AND/OR PENDING CHANGES MAY REQUIRE REDEPLOYMENT
13/// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14///
15/// IncrementFiSwapConnectors
16///
17/// DeFiActions adapter implementations fitting IncrementFi protocols to the data structure defined in DeFiActions.
18///
19access(all) contract IncrementFiSwapConnectors {
20
21    /// Swapper
22    ///
23    /// A DeFiActions connector that swaps between tokens using IncrementFi's SwapRouter contract
24    ///
25    access(all) struct Swapper : DeFiActions.Swapper {
26        /// A swap path as defined by IncrementFi's SwapRouter
27        ///  e.g. [A.f8d6e0586b0a20c7.FUSD, A.f8d6e0586b0a20c7.FlowToken, A.f8d6e0586b0a20c7.USDC]
28        access(all) let path: [String]
29        /// An optional identifier allowing protocols to identify stacked connector operations by defining a protocol-
30        /// specific Identifier to associated connectors on construction
31        access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
32        /// The pre-conversion currency accepted for a swap
33        access(self) let inVault: Type
34        /// The post-conversion currency returned by a swap
35        access(self) let outVault: Type
36
37        init(
38            path: [String],
39            inVault: Type,
40            outVault: Type,
41            uniqueID: DeFiActions.UniqueIdentifier?
42        ) {
43            pre {
44                path.length >= 2:
45                "Provided path must have a length of at least 2 - provided path has \(path.length) elements"
46            }
47            IncrementFiSwapConnectors._validateSwapperInitArgs(path: path, inVault: inVault, outVault: outVault)
48
49            self.path = path
50            self.inVault = inVault
51            self.outVault = outVault
52            self.uniqueID = uniqueID
53        }
54
55        /// Returns a ComponentInfo struct containing information about this Swapper and its inner DFA components
56        ///
57        /// @return a ComponentInfo struct containing information about this component and a list of ComponentInfo for
58        ///     each inner component in the stack.
59        ///
60        access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
61            return DeFiActions.ComponentInfo(
62                type: self.getType(),
63                id: self.id(),
64                innerComponents: []
65            )
66        }
67        /// Returns a copy of the struct's UniqueIdentifier, used in extending a stack to identify another connector in
68        /// a DeFiActions stack. See DeFiActions.align() for more information.
69        ///
70        /// @return a copy of the struct's UniqueIdentifier
71        ///
72        access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? {
73            return self.uniqueID
74        }
75        /// Sets the UniqueIdentifier of this component to the provided UniqueIdentifier, used in extending a stack to
76        /// identify another connector in a DeFiActions stack. See DeFiActions.align() for more information.
77        ///
78        /// @param id: the UniqueIdentifier to set for this component
79        ///
80        access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) {
81            self.uniqueID = id
82        }
83        /// The type of Vault this Swapper accepts when performing a swap
84        access(all) view fun inType(): Type {
85            return self.inVault
86        }
87        /// The type of Vault this Swapper provides when performing a swap
88        access(all) view fun outType(): Type {
89            return self.outVault
90        }
91        /// The estimated amount required to provide a Vault with the desired output balance
92        access(all) fun quoteIn(forDesired: UFix64, reverse: Bool): {DeFiActions.Quote} {
93            let amountsIn = SwapRouter.getAmountsIn(amountOut: forDesired, tokenKeyPath: reverse ? self.path.reverse() : self.path)
94            return SwapConnectors.BasicQuote(
95                inType: reverse ? self.outType() : self.inType(),
96                outType: reverse ? self.inType() : self.outType(),
97                inAmount: amountsIn.length == 0 ? 0.0 : amountsIn[0],
98                outAmount: forDesired
99            )
100        }
101        /// The estimated amount delivered out for a provided input balance
102        access(all) fun quoteOut(forProvided: UFix64, reverse: Bool): {DeFiActions.Quote} {
103            let amountsOut = SwapRouter.getAmountsOut(amountIn: forProvided, tokenKeyPath: reverse ? self.path.reverse() : self.path)
104            return SwapConnectors.BasicQuote(
105                inType: reverse ? self.outType() : self.inType(),
106                outType: reverse ? self.inType() : self.outType(),
107                inAmount: forProvided,
108                outAmount: amountsOut.length == 0 ? 0.0 : amountsOut[amountsOut.length - 1]
109            )
110        }
111        /// Performs a swap taking a Vault of type inVault, outputting a resulting outVault. Implementations may choose
112        /// to swap along a pre-set path or an optimal path of a set of paths or even set of contained Swappers adapted
113        /// to use multiple Flow swap protocols.
114        access(all) fun swap(quote: {DeFiActions.Quote}?, inVault: @{FungibleToken.Vault}): @{FungibleToken.Vault} {
115            let amountOut = self.quoteOut(forProvided: inVault.balance, reverse: false).outAmount
116            return <- SwapRouter.swapExactTokensForTokens(
117                exactVaultIn: <-inVault,
118                amountOutMin: amountOut,
119                tokenKeyPath: self.path,
120                deadline: getCurrentBlock().timestamp
121            )
122        }
123        /// Performs a swap taking a Vault of type outVault, outputting a resulting inVault. Implementations may choose
124        /// to swap along a pre-set path or an optimal path of a set of paths or even set of contained Swappers adapted
125        /// to use multiple Flow swap protocols.
126        access(all) fun swapBack(quote: {DeFiActions.Quote}?, residual: @{FungibleToken.Vault}): @{FungibleToken.Vault} {
127            let amountOut = self.quoteOut(forProvided: residual.balance, reverse: true).outAmount
128            return <- SwapRouter.swapExactTokensForTokens(
129                exactVaultIn: <-residual,
130                amountOutMin: amountOut,
131                tokenKeyPath: self.path.reverse(),
132                deadline: getCurrentBlock().timestamp
133            )
134        }
135    }
136
137    /* --- INTERNAL HELPERS --- */
138
139    /// Reverts if the in and out Vaults are not defined by the token key path identifiers as used by IncrementFi's
140    /// SwapRouter. Notably does not validate the intermediary path values if there are any.
141    ///
142    access(self)
143    view fun _validateSwapperInitArgs(
144        path: [String],
145        inVault: Type,
146        outVault: Type
147    ) {
148        // ensure the path in and out identifiers are consistent with the defined in and out Vault types
149        let inIdentifier = path[0]
150        let outIdentifier = path[path.length - 1]
151        let inSplit = inIdentifier.split(separator: ".")
152        let outSplit = outIdentifier.split(separator: ".")
153        assert(inSplit.length == 3, message: "Unknown IncrementFi path identifier at path[0] \(inIdentifier)")
154        assert(inSplit.length == 3, message: "Unknown IncrementFi path identifier at path[\(path.length - 1)] \(outIdentifier)")
155
156        // compare the defining contract address and name with the in and out Vault types
157        let inAddress = inSplit[1]
158        let outAddress = outSplit[1]
159        let inContract = inSplit[2]
160        let outContract = outSplit[2]
161        assert("0x\(inAddress)" == inVault.address!.toString(),
162            message: "Mismatching contract address for inVault - path defines 0x\(inAddress) but inVault defined by \(inVault.address!.toString())")
163        assert("0x\(outAddress)" == outVault.address!.toString(),
164            message: "Mismatching contract address for outVault - path defines 0x\(outAddress) but outVault defined by \(outVault.address!.toString())")
165        assert(inContract == inVault.contractName!,
166            message: "Mismatching contract address for inVault - path defines 0x\(inAddress) but inVault defined by \(inVault.address!.toString())")
167        assert(outContract == outVault.contractName!,
168            message: "Mismatching contract address for inVault - path defines 0x\(inAddress) but inVault defined by \(inVault.address!.toString())")
169    }
170}
171