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