Smart Contract
MockDexSwapper
A.b1d63873c3cc9f79.MockDexSwapper
1import Burner from 0xf233dcee88fe0abe
2import FungibleToken from 0xf233dcee88fe0abe
3
4import DeFiActions from 0x6d888f175c158410
5import DeFiActionsUtils from 0x6d888f175c158410
6
7/// TEST-ONLY mock swapper that withdraws output from a user-provided Vault capability.
8/// Do NOT use in production.
9access(all) contract MockDexSwapper {
10
11 /// Holds the set of available swappers which will be provided to users of SwapperProvider.
12 /// inType -> outType -> Swapper
13 access(self) let swappers: {Type: {Type: Swapper}}
14
15 init() {
16 self.swappers = {}
17 }
18
19 access(all) fun getSwapper(inType: Type, outType: Type): Swapper? {
20 if let swappersForInType = self.swappers[inType] {
21 return swappersForInType[outType]
22 }
23 return nil
24 }
25
26 /// Used by testing code to configure the DEX with swappers for a specific token pair.
27 ///
28 /// IMPORTANT: This function will overwrite any existing swapper for the same token pair.
29 /// This is intended to be used in cases where we want to change the price only, without
30 /// needing to remove and re-add the swapper.
31 ///
32 /// @param swapper: The swapper to set for the token pair
33 access(all) fun setMockDEXSwapperForPair(swapper: Swapper) {
34 let inType = swapper.inType()
35 let outType = swapper.outType()
36 let swappersRef = &self.swappers as auth(Mutate) &{Type: {Type: Swapper}}
37 if swappersRef[inType] == nil {
38 swappersRef[inType] = { outType: swapper }
39 } else {
40 let swappersForInTypeRef = &self.swappers[inType]! as auth(Mutate) &{Type: Swapper}
41 swappersForInTypeRef[outType] = swapper
42 }
43 }
44
45 /// Used by testing code to remove a swapper for the given token pair.
46 /// Panics if no swapper for the given pair exists.
47 access(all) fun removeMockDEXSwapperForPair(inType: Type, outType: Type) {
48 let swappersForInTypeRef = &self.swappers[inType]! as auth(Mutate) &{Type: Swapper}
49 swappersForInTypeRef.remove(key: outType)
50 }
51
52 access(all) struct BasicQuote : DeFiActions.Quote {
53 access(all) let inType: Type
54 access(all) let outType: Type
55 access(all) let inAmount: UFix64
56 access(all) let outAmount: UFix64
57 init(inType: Type, outType: Type, inAmount: UFix64, outAmount: UFix64) {
58 self.inType = inType
59 self.outType = outType
60 self.inAmount = inAmount
61 self.outAmount = outAmount
62 }
63 }
64
65 /// NOTE: reverse swaps are unsupported.
66 access(all) struct Swapper : DeFiActions.Swapper {
67 access(self) let inVault: Type
68 access(self) let outVault: Type
69 /// source for output tokens only (reverse swaps unsupported)
70 access(self) let vaultSource: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>
71 access(self) let priceRatio: UFix64 // out per unit in
72 access(contract) var uniqueID: DeFiActions.UniqueIdentifier?
73
74 init(inVault: Type, outVault: Type, vaultSource: Capability<auth(FungibleToken.Withdraw) &{FungibleToken.Vault}>, priceRatio: UFix64, uniqueID: DeFiActions.UniqueIdentifier?) {
75 pre {
76 inVault.isSubtype(of: Type<@{FungibleToken.Vault}>()): "inVault must be a FungibleToken Vault"
77 outVault.isSubtype(of: Type<@{FungibleToken.Vault}>()): "outVault must be a FungibleToken Vault"
78 vaultSource.check(): "Invalid vaultSource capability"
79 priceRatio > 0.0: "Invalid price ratio"
80 }
81 self.inVault = inVault
82 self.outVault = outVault
83 self.vaultSource = vaultSource
84 self.priceRatio = priceRatio
85 self.uniqueID = uniqueID
86 }
87
88 access(all) view fun inType(): Type { return self.inVault }
89 access(all) view fun outType(): Type { return self.outVault }
90
91 access(all) fun quoteIn(forDesired: UFix64, reverse: Bool): {DeFiActions.Quote} {
92 let inAmt = reverse ? forDesired * self.priceRatio : forDesired / self.priceRatio
93 return BasicQuote(
94 inType: reverse ? self.outType() : self.inType(),
95 outType: reverse ? self.inType() : self.outType(),
96 inAmount: inAmt,
97 outAmount: forDesired
98 )
99 }
100
101 access(all) fun quoteOut(forProvided: UFix64, reverse: Bool): {DeFiActions.Quote} {
102 let outAmt = reverse ? forProvided / self.priceRatio : forProvided * self.priceRatio
103 return BasicQuote(
104 inType: reverse ? self.outType() : self.inType(),
105 outType: reverse ? self.inType() : self.outType(),
106 inAmount: forProvided,
107 outAmount: outAmt
108 )
109 }
110
111 access(all) fun swap(quote: {DeFiActions.Quote}?, inVault: @{FungibleToken.Vault}): @{FungibleToken.Vault} {
112 pre { inVault.getType() == self.inType(): "Wrong in type" }
113 let outAmt = (quote?.outAmount) ?? (inVault.balance * self.priceRatio)
114 // burn seized input and withdraw from the provided source
115 Burner.burn(<-inVault)
116 let src = self.vaultSource.borrow() ?? panic("Invalid borrowed vault source")
117 return <- src.withdraw(amount: outAmt)
118 }
119
120 access(all) fun swapBack(quote: {DeFiActions.Quote}?, residual: @{FungibleToken.Vault}): @{FungibleToken.Vault} {
121 // Not needed in tests; burn residual and panic to surface misuse
122 Burner.burn(<-residual)
123 panic("MockSwapper.swapBack() not implemented")
124 }
125
126 access(all) fun getComponentInfo(): DeFiActions.ComponentInfo {
127 return DeFiActions.ComponentInfo(type: self.getType(), id: self.id(), innerComponents: [])
128 }
129 access(contract) view fun copyID(): DeFiActions.UniqueIdentifier? { return self.uniqueID }
130 access(contract) fun setID(_ id: DeFiActions.UniqueIdentifier?) { self.uniqueID = id }
131 }
132
133 access(all) struct SwapperProvider : DeFiActions.SwapperProvider {
134 access(all) fun getSwapper(inType: Type, outType: Type): Swapper? {
135 return MockDexSwapper.getSwapper(inType: inType, outType: outType)
136 }
137 }
138}
139