Smart Contract
IncrementFiSwapConnectors
A.efa9bd7d1b17f1ed.IncrementFiSwapConnectors
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