1+ import Test
2+ import BlockchainHelpers
3+
4+ import " test_helpers.cdc"
5+
6+ import " MOET"
7+ import " TidalProtocol"
8+
9+ access (all ) let protocolAccount = Test .getAccount (0x0000000000000007 )
10+ access (all ) let userAccount = Test .createAccount ()
11+
12+ access (all ) let flowTokenIdentifier = " A.0000000000000003.FlowToken.Vault"
13+ access (all ) var moetTokenIdentifier = " A.0000000000000007.MOET.Vault"
14+ access (all ) let flowVaultStoragePath = /storage/flowTokenVault
15+ access (all ) let wrapperStoragePath = /storage/tidalProtocolPositionWrapper
16+
17+ access (all ) let minHealth = 1.1
18+ access (all ) let targetHealth = 1.3
19+ access (all ) let maxHealth = 1.5
20+ access (all ) let flowCollateralFactor = 0.8
21+ access (all ) let flowBorrowFactor = 1.0
22+ access (all ) let flowStartPrice = 1.0 // denominated in MOET
23+ access (all ) let positionFundingAmount = 100.0
24+ access (all ) var positionID : UInt64 = 0
25+
26+ access (all ) let startCollateralValue = flowStartPrice * positionFundingAmount
27+ access (all ) let startEffectiveCollateralValue = startCollateralValue * flowCollateralFactor
28+ access (all ) let startBorrowLimitAtTarget = startEffectiveCollateralValue / targetHealth
29+
30+ access (all ) var snapshot : UInt64 = 0
31+
32+ access (all )
33+ fun setup () {
34+ deployContracts ()
35+
36+ // price setup
37+ setMockOraclePrice (signer : protocolAccount , forTokenIdentifier : flowTokenIdentifier , price : flowStartPrice )
38+
39+ // create the Pool & add FLOW as suppoorted token
40+ createAndStorePool (signer : protocolAccount , defaultTokenIdentifier : defaultTokenIdentifier , beFailed : false )
41+ addSupportedTokenSimpleInterestCurve (
42+ signer : protocolAccount ,
43+ tokenTypeIdentifier : flowTokenIdentifier ,
44+ collateralFactor : flowCollateralFactor ,
45+ borrowFactor : flowBorrowFactor ,
46+ depositRate : 1_000_000.0 ,
47+ depositCapacityCap : 1_000_000.0
48+ )
49+
50+ // prep user's account
51+ setupMoetVault (userAccount , beFailed : false )
52+ mintFlow (to : userAccount , amount : positionFundingAmount )
53+
54+ let openRes = executeTransaction (
55+ " ./transactions/mock-tidal-protocol-consumer/create_wrapped_position.cdc" ,
56+ [positionFundingAmount , flowVaultStoragePath , true ],
57+ userAccount
58+ )
59+ Test .expect (openRes , Test .beSucceeded ())
60+ // assert expected starting point
61+ let balanceAfterBorrow = getBalance (address : userAccount .address , vaultPublicPath : MOET .VaultPublicPath )!
62+ let expectedBorrowAmount = (positionFundingAmount * flowCollateralFactor ) / targetHealth
63+ Test .assert (balanceAfterBorrow > = expectedBorrowAmount - 0.01 && balanceAfterBorrow < = expectedBorrowAmount + 0.01 ,
64+ message : " Expected MOET balance to be ~\( expectedBorrowAmount ) , but got \( balanceAfterBorrow ) " )
65+
66+ let evts = Test .eventsOfType (Type <TidalProtocol .Opened >())
67+ let openedEvt = evts [evts .length - 1 ] as ! TidalProtocol .Opened
68+ positionID = openedEvt .pid
69+
70+ let health = getPositionHealth (pid : positionID , beFailed : false )
71+ Test .assertEqual (targetHealth , health )
72+
73+ snapshot = getCurrentBlockHeight ()
74+ }
75+
76+ access (all )
77+ fun testFundsAvailableAboveTargetHealthAfterDepositingFromHealthy () {
78+ log (" ==============================" )
79+ log (" Executing testFundsAvailableAboveTargetHealthAfterDepositingFromHealthy()" )
80+
81+ log (" FLOW price set to \( flowStartPrice ) " )
82+
83+ log (" .............................." )
84+ var depositAmount = 0.0
85+ var expectedAvailable = 0.0 // already at target health - nothing additional available
86+ var actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
87+ pid : positionID ,
88+ withdrawType : moetTokenIdentifier ,
89+ targetHealth : targetHealth ,
90+ depositType : flowTokenIdentifier ,
91+ depositAmount : depositAmount ,
92+ beFailed : false
93+ )
94+ log (" Depositing: \( depositAmount ) " )
95+ log (" Expected Available: \( expectedAvailable ) " )
96+ log (" Actual Available: \( actualAvailable ) " )
97+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
98+
99+ log (" .............................." )
100+ depositAmount = 100.0
101+ expectedAvailable = ((depositAmount * flowCollateralFactor ) / targetHealth ) * flowStartPrice
102+ actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
103+ pid : positionID ,
104+ withdrawType : moetTokenIdentifier ,
105+ targetHealth : targetHealth ,
106+ depositType : flowTokenIdentifier ,
107+ depositAmount : depositAmount ,
108+ beFailed : false
109+ )
110+ log (" Depositing: \( depositAmount ) " )
111+ log (" Expected Available: \( expectedAvailable ) " )
112+ log (" Actual Available: \( actualAvailable ) " )
113+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
114+
115+ log (" .............................." )
116+ depositAmount = 1_000.0
117+ expectedAvailable = ((depositAmount * flowCollateralFactor ) / targetHealth ) * flowStartPrice
118+ actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
119+ pid : positionID ,
120+ withdrawType : moetTokenIdentifier ,
121+ targetHealth : targetHealth ,
122+ depositType : flowTokenIdentifier ,
123+ depositAmount : depositAmount ,
124+ beFailed : false
125+ )
126+ log (" Depositing: \( depositAmount ) " )
127+ log (" Expected Available: \( expectedAvailable ) " )
128+ log (" Actual Available: \( actualAvailable ) " )
129+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
130+
131+ log (" .............................." )
132+ depositAmount = 10_000.0
133+ expectedAvailable = ((depositAmount * flowCollateralFactor ) / targetHealth ) * flowStartPrice
134+ actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
135+ pid : positionID ,
136+ withdrawType : moetTokenIdentifier ,
137+ targetHealth : targetHealth ,
138+ depositType : flowTokenIdentifier ,
139+ depositAmount : depositAmount ,
140+ beFailed : false
141+ )
142+ log (" Depositing: \( depositAmount ) " )
143+ log (" Expected Available: \( expectedAvailable ) " )
144+ log (" Actual Available: \( actualAvailable ) " )
145+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
146+
147+ log (" .............................." )
148+ depositAmount = 100_000.0
149+ expectedAvailable = ((depositAmount * flowCollateralFactor ) / targetHealth ) * flowStartPrice
150+ actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
151+ pid : positionID ,
152+ withdrawType : moetTokenIdentifier ,
153+ targetHealth : targetHealth ,
154+ depositType : flowTokenIdentifier ,
155+ depositAmount : depositAmount ,
156+ beFailed : false
157+ )
158+ log (" Depositing: \( depositAmount ) " )
159+ log (" Expected Available: \( expectedAvailable ) " )
160+ log (" Actual Available: \( actualAvailable ) " )
161+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
162+
163+ log (" .............................." )
164+ depositAmount = 1_000_000.0
165+ expectedAvailable = ((depositAmount * flowCollateralFactor ) / targetHealth ) * flowStartPrice
166+ actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
167+ pid : positionID ,
168+ withdrawType : moetTokenIdentifier ,
169+ targetHealth : targetHealth ,
170+ depositType : flowTokenIdentifier ,
171+ depositAmount : depositAmount ,
172+ beFailed : false
173+ )
174+ log (" Depositing: \( depositAmount ) " )
175+ log (" Expected Available: \( expectedAvailable ) " )
176+ log (" Actual Available: \( actualAvailable ) " )
177+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
178+
179+ log (" ==============================" )
180+ }
181+
182+ access (all )
183+ fun testFundsAvailableAboveTargetHealthAfterDepositingFromUndercollateralized () {
184+ log (" ==============================" )
185+ log (" Executing testFundsAvailableAboveTargetHealthAfterDepositingFromUndercollateralized()" )
186+
187+ let priceDecrease = 0.25
188+ let newPrice = flowStartPrice * (1.0 - priceDecrease )
189+
190+ let newCollateralValue = positionFundingAmount * newPrice
191+ let newEffectiveCollateralValue = newCollateralValue * flowCollateralFactor
192+ let newBorrowLimitAtTarget = newEffectiveCollateralValue / targetHealth
193+ let expectedDepositRequiredForTarget = startBorrowLimitAtTarget - newBorrowLimitAtTarget
194+
195+ setMockOraclePrice (signer : protocolAccount ,
196+ forTokenIdentifier : flowTokenIdentifier ,
197+ price : newPrice
198+ )
199+ let actualHealth = getPositionHealth (pid : positionID , beFailed : false )
200+ Test .assertEqual (targetHealth * (1.0 - priceDecrease ), actualHealth )
201+
202+ log (" FLOW price set to \( newPrice ) from \( flowStartPrice ) " )
203+ log (" Position health after price decrease: \( actualHealth ) " )
204+ log (" Expected deposit required for target health: \( expectedDepositRequiredForTarget ) " )
205+
206+ log (" .............................." )
207+ // minting to topUpSource Vault which should *not* affect calculation here
208+ let mintToSource = 100.0
209+ log (" Minting \( mintToSource ) to position topUpSource" )
210+ mintMoet (signer : protocolAccount , to : userAccount .address , amount : mintToSource , beFailed : false )
211+
212+ log (" .............................." )
213+ var depositAmount = 0.0
214+ var expectedAvailable = 0.0 // already below target health - nothing available
215+ var actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
216+ pid : positionID ,
217+ withdrawType : moetTokenIdentifier ,
218+ targetHealth : targetHealth ,
219+ depositType : flowTokenIdentifier ,
220+ depositAmount : depositAmount ,
221+ beFailed : false
222+ )
223+ log (" Depositing: \( depositAmount ) " )
224+ log (" Expected Available: \( expectedAvailable ) " )
225+ log (" Actual Available: \( actualAvailable ) " )
226+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
227+
228+ log (" .............................." )
229+ let surplusDeposit = 1.0
230+ depositAmount = expectedDepositRequiredForTarget + surplusDeposit
231+ expectedAvailable = (surplusDeposit * flowCollateralFactor / targetHealth ) * newPrice
232+ actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
233+ pid : positionID ,
234+ withdrawType : moetTokenIdentifier ,
235+ targetHealth : targetHealth ,
236+ depositType : flowTokenIdentifier ,
237+ depositAmount : depositAmount ,
238+ beFailed : false
239+ )
240+ log (" Depositing: \( depositAmount ) " )
241+ log (" Expected Available: \( expectedAvailable ) " )
242+ log (" Actual Available: \( actualAvailable ) " )
243+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
244+
245+ log (" ==============================" )
246+ }
247+
248+ access (all )
249+ fun testFundsAvailableAboveTargetHealthAfterDepositingFromOvercollateralized () {
250+ log (" ==============================" )
251+ log (" Executing testFundsAvailableAboveTargetHealthAfterDepositingFromOvercollateralized()" )
252+
253+ let priceIncrease = 0.25
254+ let newPrice = flowStartPrice * (1.0 + priceIncrease )
255+
256+ let newCollateralValue = positionFundingAmount * newPrice
257+ let newEffectiveCollateralValue = newCollateralValue * flowCollateralFactor
258+ let newBorrowLimitAtTarget = newEffectiveCollateralValue / targetHealth
259+ let expectedAvailableAboveTarget = newBorrowLimitAtTarget - startBorrowLimitAtTarget
260+
261+ setMockOraclePrice (signer : protocolAccount ,
262+ forTokenIdentifier : flowTokenIdentifier ,
263+ price : newPrice
264+ )
265+ let actualHealth = getPositionHealth (pid : positionID , beFailed : false )
266+ Test .assertEqual (targetHealth * (1.0 + priceIncrease ), actualHealth )
267+
268+ log (" FLOW price set to \( newPrice ) from \( flowStartPrice ) " )
269+ log (" Position health after price decrease: \( actualHealth ) " )
270+ log (" Expected availabe above target health: \( expectedAvailableAboveTarget ) " )
271+
272+ log (" .............................." )
273+ // minting to topUpSource Vault which should *not* affect calculation here
274+ let mintToSource = 100.0
275+ log (" Minting \( mintToSource ) to position topUpSource" )
276+ mintMoet (signer : protocolAccount , to : userAccount .address , amount : mintToSource , beFailed : false )
277+
278+ log (" .............................." )
279+ var depositAmount = 0.0
280+ var expectedAvailable = expectedAvailableAboveTarget * newPrice
281+ var actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
282+ pid : positionID ,
283+ withdrawType : moetTokenIdentifier ,
284+ targetHealth : targetHealth ,
285+ depositType : flowTokenIdentifier ,
286+ depositAmount : depositAmount ,
287+ beFailed : false
288+ )
289+ log (" Depositing: \( depositAmount ) " )
290+ log (" Expected Available: \( expectedAvailable ) " )
291+ log (" Actual Available: \( actualAvailable ) " )
292+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
293+
294+ log (" .............................." )
295+ depositAmount = 100.0
296+ expectedAvailable = (expectedAvailableAboveTarget + depositAmount ) * newPrice
297+ actualAvailable = fundsAvailableAboveTargetHealthAfterDepositing (
298+ pid : positionID ,
299+ withdrawType : moetTokenIdentifier ,
300+ targetHealth : targetHealth ,
301+ depositType : flowTokenIdentifier ,
302+ depositAmount : depositAmount ,
303+ beFailed : false
304+ )
305+ log (" Depositing: \( depositAmount ) " )
306+ log (" Expected Available: \( expectedAvailable ) " )
307+ log (" Actual Available: \( actualAvailable ) " )
308+ Test .assert (equalWithinVariance (expectedAvailable , actualAvailable , plusMinus : nil ))
309+
310+ log (" ==============================" )
311+ }
0 commit comments