Conversation
4ca1038 to
e45967b
Compare
e45967b to
82d82ed
Compare
* Add forked rebalance scenarios 4 and 5. * Update forked scenarios to match main. * Update scenarios 4,5.
| } | ||
|
|
||
| access(all) var testSnapshot: UInt64 = 0 | ||
| access(all) |
There was a problem hiding this comment.
| access(all) | |
| // Verify that the YieldVault correctly rebalances yield token holdings when FLOW price changes | |
| access(all) |
|
|
||
| let flowPrices = [0.5, 0.8, 1.0, 1.2, 1.5, 2.0, 3.0, 5.0] | ||
|
|
||
| // Expected values from Google sheet calculations |
There was a problem hiding this comment.
can you link the google sheet?
| EVM.store(target: poolAddr, slot: slotHex(3), value: zero32) | ||
|
|
||
| // --- Slot 4: liquidity = uint128 max --- | ||
| let liquidityAmount: UInt256 = 340282366920938463463374607431768211455 // 2^128 - 1 |
There was a problem hiding this comment.
I'm concerned that we are mocking the uniswap pool in a way that have max liquidity. I understand this is useful to ensure that no matter how much token to swap, the swapped price can always be the targeted price we set.
But in real world, the liquidity is often capped, and we also want to verify the behavior when there isn't enough liquidity.
There was a problem hiding this comment.
Yeah, that is a fair concern.
The intitial scope of the forked simulations was to replicate the existing rebalance style tests, as the team wasn't completely that the behaviour would be matched in a real integration-style test against real oracle integrations & EVM pools.
That being said, I agree that the rigidity leaves room for error. Could be worth exploring another style test as a follow-up with more realistic liquidity ticks, but only asserting properties instead of absolute values (e.g. rebalance happens, health factor improves/hits target, realsistic slippage values don't affect system negatively) rather than exact values. Open to ideas on what that should look like.
| @@ -0,0 +1,294 @@ | |||
| #test_fork(network: "mainnet-fork", height: 143292255) | |||
There was a problem hiding this comment.
What is the difference in the setup between this forked mainnet and rebalance_scenario1_test.cdc?
What is covered in this tests but is not covered in there?
There was a problem hiding this comment.
The main difference is just using the contracts deployed on mainnet instead of the mocked ones (e.g. MockSwapper, MockOracle) in the original rebalance_scenario*.cdc. Otherwise, the tests are identical by design and the expected values are exactly the same.
| let expectedYieldTokenValues: {UFix64: UFix64} = { | ||
| 0.5: 307.69230769, | ||
| 0.8: 492.30769231, | ||
| 1.0: 615.38461538, |
There was a problem hiding this comment.
Basically value = key * 615.38461538, for instance 5.0: (5.0 * 615.38461538) = 3076.92307692.
So how does the rebalancing works in this tests? I'm not sure I understand the specific case we are testing here.
When flow price drops to 0.5, it means the yield vault price is dropped for the same ratio (50% off). Then the rebalance on both the yield vault and the position is for the yield vault value to realize it's value dropped for 50%?
There was a problem hiding this comment.
OK, I think I got it. suggested the above comments
|
|
||
| let flowPrices = [0.5, 0.8, 1.0, 1.2, 1.5, 2.0, 3.0, 5.0] | ||
|
|
||
| // Expected values from Google sheet calculations |
There was a problem hiding this comment.
| // Expected values from Google sheet calculations | |
| // ============================================================================ | |
| // REBALANCING MATH FOR FUSDEVStrategy | |
| // ============================================================================ | |
| // | |
| // Initial Setup: | |
| // - Collateral: 1000 FLOW at $1.0 = $1000 | |
| // - LTV (Loan-to-Value): 80% (0.8) | |
| // - Borrow-Eligible: 1000 * 1.0 * 0.8 = $800 | |
| // - Target Health Factor: 1.3 | |
| // - Initial Debt: 800 / 1.3 = 615.384615385 MOET | |
| // - Initial HF: (1000 * 1.0 * 0.8) / 615.384615385 = 1.300 | |
| // | |
| // Rebalancing Triggers: | |
| // - HF < 1.1: Position is under-collateralized → Repay debt | |
| // - HF > 1.5: Position is over-collateralized → Borrow more | |
| // - Rebalancing restores HF to target 1.3 | |
| // | |
| // Trigger Calculation (with initial debt 615.384615385): | |
| // - HF < 1.1 when: 1000 * X * 0.8 / 615.384615385 < 1.1 → X < 0.84615 | |
| // - HF > 1.5 when: 1000 * X * 0.8 / 615.384615385 > 1.5 → X > 1.15385 | |
| // | |
| // Expected Values Table (after rebalancing to HF = 1.3): | |
| // ┌────────────┬────────────┬───────────────┬───────────────┬──────────────┬───────────────────┬─────────────┬─────────────┬─────────────┐ | |
| // │ FLOW Price │ Collateral │ Borrow-Elig. │ Debt Before │ HF Before │ Action │ Debt After │ YIELD After │ HF After │ | |
| // ├────────────┼────────────┼───────────────┼───────────────┼──────────────┼───────────────────┼─────────────┼─────────────┼─────────────┤ | |
| // │ 0.50 │ 500 │ 400 │ 615.38 │ 0.65 │ Repay 307.69 │ 307.69 │ 307.69 │ 1.30 │ | |
| // │ 0.80 │ 800 │ 640 │ 615.38 │ 1.04 │ Repay 123.08 │ 492.31 │ 492.31 │ 1.30 │ | |
| // │ 1.00 │ 1000 │ 800 │ 615.38 │ 1.30 │ none │ 615.38 │ 615.38 │ 1.30 │ | |
| // │ 1.20 │ 1200 │ 960 │ 615.38 │ 1.56 │ Borrow 123.08 │ 738.46 │ 738.46 │ 1.30 │ | |
| // │ 1.50 │ 1500 │ 1200 │ 615.38 │ 1.95 │ Borrow 307.69 │ 923.08 │ 923.08 │ 1.30 │ | |
| // │ 2.00 │ 2000 │ 1600 │ 615.38 │ 2.60 │ Borrow 615.38 │ 1230.77 │ 1230.77 │ 1.30 │ | |
| // │ 3.00 │ 3000 │ 2400 │ 615.38 │ 3.90 │ Borrow 1230.77 │ 1846.15 │ 1846.15 │ 1.30 │ | |
| // │ 5.00 │ 5000 │ 4000 │ 615.38 │ 6.50 │ Borrow 2461.54 │ 3076.92 │ 3076.92 │ 1.30 │ | |
| // └────────────┴────────────┴───────────────┴───────────────┴──────────────┴───────────────────┴─────────────┴─────────────┴─────────────┘ | |
| // | |
| // Formula: New Debt = Borrow-Eligible / Target HF = (Collateral * LTV) / 1.3 | |
| // ============================================================================ | |
| let expectedYieldTokenValues: {UFix64: UFix64} = { | ||
| 0.5: 307.69230769, | ||
| 0.8: 492.30769231, | ||
| 1.0: 615.38461538, |
There was a problem hiding this comment.
OK, I think I got it. suggested the above comments
|
|
||
| let user = Test.createAccount() | ||
|
|
||
| let yieldPriceIncreases = [1.1, 1.2, 1.3, 1.5, 2.0, 3.0] |
There was a problem hiding this comment.
| let yieldPriceIncreases = [1.1, 1.2, 1.3, 1.5, 2.0, 3.0] | |
| // =================================================================================== | |
| // REBALANCING SIMULATION: YIELD price appreciation with constant Health Factor 1.3 | |
| // =================================================================================== | |
| // | |
| // Thresholds: | |
| // AutoBalancer: lowerThreshold=0.95, upperThreshold=1.05 (±5% of base value) | |
| // Position: minHealth=1.1, targetHealth=1.3, maxHealth=1.5 | |
| // | |
| // Initial State (Price=$1.00): | |
| // Collateral: 1000 FLOW | |
| // Debt: 1000 × 0.8 / 1.3 = 615.38 (borrowed to buy YIELD tokens) | |
| // YIELD Units: 615.38 (purchased with debt at $1.00) | |
| // Baseline: $615.38 (AutoBalancer's valueOfDeposits, equals initial debt) | |
| // Health: 1.3 | |
| // | |
| // When YIELD Price increases (e.g. $1.00 → $1.10): | |
| // | |
| // 1. TRIGGER: Price change | |
| // YIELD Value = 615.38 × $1.10 = $676.92 | |
| // Value Ratio = $676.92 / $615.38 = 110% | |
| // Exceeds AutoBalancer upperThreshold (1.05) → rebalance triggered | |
| // | |
| // 2. AUTOBALANCER ACTION: Sell YIELD to bring value back to baseline | |
| // Value Diff = $676.92 - $615.38 = $61.54 (surplus above baseline) | |
| // Bal Sell = Value Diff / Price = $61.54 / $1.10 = 55.94 units | |
| // Remaining YIELD = 615.38 - 55.94 = 559.44 units (worth $615.38 = baseline) | |
| // Profit $61.54 added to Collateral: 1000 + 61.54 = 1061.54 | |
| // | |
| // 3. POSITION REBALANCE: Borrow more (higher collateral supports more debt) | |
| // Target Debt = 1061.54 × 0.8 / 1.3 = 653.25 | |
| // Borrow: 653.25 - 615.38 = 37.87 | |
| // YIELD Bought: 37.87 / $1.10 = 34.43 units | |
| // | |
| // 4. FINAL STATE: | |
| // YIELD Units: 559.44 + 34.43 = 593.87 | |
| // Debt: 653.25 | |
| // Collateral: 1061.54 | |
| // Health: 1.3 (maintained) | |
| // | |
| // Key Formulas: | |
| // Bal Sell = (Prev Units × New Price - Baseline) / New Price | |
| // = Prev Units - (Baseline / New Price) | |
| // Profit = Bal Sell × Price | |
| // New Collateral = Prev Collateral + Profit | |
| // Target Debt = Collateral × 0.8 / 1.3 | |
| // YIELD Bought = Borrow / Price | |
| // Final YIELD Units = (Prev Units - Bal Sell) + YIELD Bought | |
| // | |
| // ----------------------------------------------------------------------------------- | |
| // Price | Debt | YIELD Units | Collateral | Health | Actions | |
| // ----------------------------------------------------------------------------------- | |
| // 1.00 | 615.38 | 615.38 | 1000.00 | 1.30 | (initial) | |
| // 1.10 | 653.25 | 593.87 | 1061.54 | 1.30 | Sell 55.94 | Borrow 37.87 | |
| // 1.20 | 689.80 | 574.83 | 1120.93 | 1.30 | Sell 49.49 | Borrow 36.55 | |
| // 1.30 | 725.17 | 557.83 | 1178.41 | 1.30 | Sell 44.22 | Borrow 35.37 | |
| // 1.50 | 793.83 | 529.22 | 1289.97 | 1.30 | Sell 74.38 | Borrow 68.66 | |
| // 2.00 | 956.67 | 478.33 | 1554.58 | 1.30 | Sell 132.31 | Borrow 162.84 | |
| // 3.00 | 1251.03 | 417.01 | 2032.92 | 1.30 | Sell 159.44 | Borrow 294.36 | |
| // ----------------------------------------------------------------------------------- | |
| // | |
| // =================================================================================== | |
| let yieldPriceIncreases = [1.1, 1.2, 1.3, 1.5, 2.0, 3.0] |
There was a problem hiding this comment.
Notice in step 2 the rebalancer sells 55.94 yield token, and then in step 3 it buys back 34.43 yield token. It would be nicer to only sell the diff, but probably more complex to implement.
… feature/forked-simulations
… feature/forked-simulations
… feature/forked-simulations
Co-authored-by: Leo Zhang <zhangchiqing@gmail.com>
Description
Feature branch that adds forked rebalance simulations for the real PYUSD0 strategy, mirroring those initially created via mocked bootstrapped tests.
For contributor use:
masterbranchFiles changedin the Github PR explorer