Skip to content

Commit 2a8f219

Browse files
sisyphusSmilingsisyphusSmiling
authored andcommitted
add initial fundsAvailableAboveTargetHealth() test cases
1 parent cc1b734 commit 2a8f219

5 files changed

Lines changed: 401 additions & 19 deletions
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import "TidalProtocol"
2+
3+
access(all)
4+
fun main(
5+
pid: UInt64,
6+
withdrawType: String,
7+
targetHealth: UFix64,
8+
depositType: String,
9+
depositAmount: UFix64
10+
): UFix64 {
11+
let _withdrawType = CompositeType(withdrawType) ?? panic("Invalid Vault identifier withdrawType \(withdrawType)")
12+
let _depositType = CompositeType(depositType) ?? panic("Invalid Vault identifier depositType \(depositType)")
13+
let address = Type<@TidalProtocol.Pool>().address!
14+
return getAccount(address).capabilities.borrow<&TidalProtocol.Pool>(TidalProtocol.PoolPublicPath)
15+
?.fundsAvailableAboveTargetHealthAfterDepositing(
16+
pid: pid,
17+
withdrawType: _withdrawType,
18+
targetHealth: targetHealth,
19+
depositType: _depositType,
20+
depositAmount: depositAmount
21+
) ?? panic("Could not reference TidalProtocol Pool at address \(address) at PublicPath \(TidalProtocol.PoolPublicPath)")
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import "TidalProtocol"
2+
3+
access(all)
4+
fun main(
5+
pid: UInt64,
6+
depositType: String,
7+
targetHealth: UFix64,
8+
withdrawType: String,
9+
withdrawAmount: UFix64
10+
): UFix64 {
11+
let _depositType = CompositeType(depositType) ?? panic("Invalid Vault identifier depositType \(depositType)")
12+
let _withdrawType = CompositeType(withdrawType) ?? panic("Invalid Vault identifier withdrawType \(withdrawType)")
13+
let address = Type<@TidalProtocol.Pool>().address!
14+
return getAccount(address).capabilities.borrow<&TidalProtocol.Pool>(TidalProtocol.PoolPublicPath)
15+
?.fundsRequiredForTargetHealthAfterWithdrawing(
16+
pid: pid,
17+
depositType: _depositType,
18+
targetHealth: targetHealth,
19+
withdrawType: _withdrawType,
20+
withdrawAmount: withdrawAmount
21+
) ?? panic("Could not reference TidalProtocol Pool at address \(address) at PublicPath \(TidalProtocol.PoolPublicPath)")
22+
}
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
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+
}

cadence/tests/position_lifecycle_happy_test.cdc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ access(all) let protocolAccount = Test.getAccount(0x0000000000000007)
1414
access(all) var snapshot: UInt64 = 0
1515

1616
access(all) let flowTokenIdentifier = "A.0000000000000003.FlowToken.Vault"
17-
access(all) var yieldTokenIdentifier = "A.0000000000000007.YieldToken.Vault"
1817
access(all) let flowVaultStoragePath = /storage/flowTokenVault
1918
access(all) let wrapperStoragePath = /storage/tidalProtocolPositionWrapper
2019

0 commit comments

Comments
 (0)