-
Notifications
You must be signed in to change notification settings - Fork 0
Recreate scenario 1 using fork testing setup. #128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 12 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
e1007b2
Recreate scenario 1 using forked testnet.
RZhang05 351578c
Remove unused function.
RZhang05 5ff2bd0
Update for mainnet addresses.
RZhang05 3068055
Use mUSDC strategy with real oracles on testnet.
RZhang05 deb846e
Update symbol prices.
RZhang05 f197957
Switch to mainnet.
RZhang05 a719c67
Merge branch 'main' into raymond/forked-scen1
RZhang05 d52baf9
Add option to transfer flow from whale account instead of minting.
RZhang05 44a77a6
Merge branch 'nialexsan/pyusd-fyv-strategy' into raymond/forked-scen1
RZhang05 0d6b270
Use fixed mainnet height, new FUSDEV strategy.
RZhang05 2e2400c
Add percent tolerance check to forked test.
RZhang05 fc67c98
Clean up forked scenario 1.
RZhang05 f2ea7b3
Remove unnecessary imports.
RZhang05 eae9d1e
Add EVM State Manipulation Helpers For Forked Simulations
jribbink 0ba2dd2
Merge remote-tracking branch 'origin/main' into jribbink/evm-test-hel…
jribbink c405a2c
Fix bugs with decimal offsets & cleanup
jribbink af63f67
tidy comments
jribbink bb17527
Cleanup test helpers & fix precision
jribbink 5dc80b4
Merge remote-tracking branch 'origin/main' into jribbink/evm-test-hel…
jribbink fb8b266
Update to newer CLI
jribbink dc143d0
address feedback
jribbink 5939f17
Add test for EVM state helpers
jribbink 4c1df74
cleanup test assertion
jribbink d88f651
cleanup test assertion
jribbink 4f6c322
Fix percent tolerance
jribbink 8829009
Merge branch 'feature/forked-simulations' into jribbink/evm-test-helpers
jribbink 875ff38
Merge branch 'main' into raymond/forked-scen1
RZhang05 845507f
Merge branch 'jribbink/evm-test-helpers' into raymond/forked-scen1
RZhang05 48a4275
Update to new strategy and use new evm helpers.
RZhang05 e7a6683
Clean up.
RZhang05 7ab7e9c
Merge branch 'feature/forked-simulations' into raymond/forked-scen1
RZhang05 d95de5c
Fix merge.
RZhang05 2a42e2b
Normalize comments.
RZhang05 d0c7462
Temporarily skip closing of yield vault.
RZhang05 f2e72c6
Apply suggestions from code review
RZhang05 ecfe8e7
Switch flow.json back to tab spacing.
RZhang05 d4b1fc1
Merge branch 'raymond/forked-scen1' of https://github.com/onflow/Flow…
RZhang05 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,187 @@ | ||
| // this height guarantees enough liquidity for the test | ||
| #test_fork(network: "mainnet", height: 140164761) | ||
|
|
||
| import Test | ||
| import BlockchainHelpers | ||
|
|
||
| import "test_helpers.cdc" | ||
|
|
||
| // standards | ||
| import "EVM" | ||
| // FlowYieldVaults platform | ||
| import "FlowYieldVaults" | ||
| // vm bridge | ||
| import "FlowEVMBridgeConfig" | ||
| // live oracles | ||
| import "ERC4626PriceOracles" | ||
| // mocks | ||
| import "MockOracle" | ||
| import "MockSwapper" | ||
| // other | ||
| import "FlowToken" | ||
| import "MOET" | ||
| import "YieldToken" | ||
| import "FlowYieldVaultsStrategiesV1_1" | ||
| import "FlowCreditMarket" | ||
|
|
||
|
|
||
| // check (and update) flow.json for correct addresses | ||
| // mainnet addresses | ||
| access(all) let flowYieldVaultsAccount = Test.getAccount(0xb1d63873c3cc9f79) | ||
| access(all) let yieldTokenAccount = Test.getAccount(0xb1d63873c3cc9f79) | ||
| access(all) let flowCreditMarketAccount = Test.getAccount(0x6b00ff876c299c61) | ||
| access(all) let bandOracleAccount = Test.getAccount(0x6801a6222ebf784a) | ||
| access(all) let whaleFlowAccount = Test.getAccount(0x92674150c9213fc9) | ||
|
|
||
| access(all) var strategyIdentifier = Type<@FlowYieldVaultsStrategiesV1_1.FUSDEVStrategy>().identifier | ||
| access(all) var flowTokenIdentifier = Type<@FlowToken.Vault>().identifier | ||
| access(all) var moetTokenIdentifier = Type<@MOET.Vault>().identifier | ||
|
|
||
| access(all) let collateralFactor = 0.8 | ||
| access(all) let targetHealthFactor = 1.3 | ||
|
|
||
| access(all) var snapshot: UInt64 = 0 | ||
|
|
||
| access(all) | ||
| fun setup() { | ||
| // BandOracle is only used for FLOW price for FCM collateral | ||
| let symbolPrices: {String: UFix64} = { | ||
| "FLOW": 1.0 | ||
| } | ||
| setBandOraclePrices(signer: bandOracleAccount, symbolPrices: symbolPrices) | ||
|
|
||
| let reserveAmount = 100_000_00.0 | ||
| // service account does not have enough flow to "mint" | ||
| // var mintFlowResult = mintFlow(to: flowCreditMarketAccount, amount: reserveAmount) | ||
| // Test.expect(mintFlowResult, Test.beSucceeded()) | ||
| transferFlow(signer: whaleFlowAccount, recipient: flowCreditMarketAccount.address, amount: reserveAmount) | ||
|
|
||
| mintMoet(signer: flowCreditMarketAccount, to: flowCreditMarketAccount.address, amount: reserveAmount, beFailed: false) | ||
|
|
||
| // Fund FlowYieldVaults account for scheduling fees (atomic initial scheduling) | ||
| // service account does not have enough flow to "mint" | ||
| // mintFlowResult = mintFlow(to: flowYieldVaultsAccount, amount: 100.0) | ||
| // Test.expect(mintFlowResult, Test.beSucceeded()) | ||
| transferFlow(signer: whaleFlowAccount, recipient: flowYieldVaultsAccount.address, amount: 100.0) | ||
| } | ||
|
|
||
| access(all) var testSnapshot: UInt64 = 0 | ||
| access(all) | ||
| fun test_ForkedRebalanceYieldVaultScenario1() { | ||
| let fundingAmount = 1000.0 | ||
|
|
||
| let user = Test.createAccount() | ||
|
|
||
| let flowPrices = [0.5, 0.8, 1.0, 1.2, 1.5, 2.0, 3.0, 5.0] | ||
|
|
||
| // Expected values from Google sheet calculations | ||
| let expectedYieldTokenValues: {UFix64: UFix64} = { | ||
| 0.5: 307.69230769, | ||
| 0.8: 492.30769231, | ||
| 1.0: 615.38461538, | ||
| 1.2: 738.46153846, | ||
| 1.5: 923.07692308, | ||
| 2.0: 1230.76923077, | ||
| 3.0: 1846.15384615, | ||
| 5.0: 3076.92307692 | ||
| } | ||
|
|
||
| // Likely 0.0 | ||
| let flowBalanceBefore = getBalance(address: user.address, vaultPublicPath: /public/flowTokenReceiver)! | ||
| // service account does not have enough flow to "mint" | ||
| // let mintFlowResult =The code snippet `mintFlow(to: user, amount: fundingAmount)` is a function call that mints a specified amount of a token (in this case, Flow tokens) to a specific user account. | ||
| // mintFlow(to: user, amount: fundingAmount) | ||
| // Test.expect(mintFlowResult, Test.beSucceeded()) | ||
| transferFlow(signer: whaleFlowAccount, recipient: user.address, amount: fundingAmount) | ||
| grantBeta(flowYieldVaultsAccount, user) | ||
|
|
||
| createYieldVault( | ||
| signer: user, | ||
| strategyIdentifier: strategyIdentifier, | ||
| vaultIdentifier: flowTokenIdentifier, | ||
| amount: fundingAmount, | ||
| beFailed: false | ||
| ) | ||
|
|
||
| // Capture the actual position ID from the FlowCreditMarket.Opened event | ||
| var pid = (getLastPositionOpenedEvent(Test.eventsOfType(Type<FlowCreditMarket.Opened>())) as! FlowCreditMarket.Opened).pid | ||
| log("[TEST] Captured Position ID from event: \(pid)") | ||
|
|
||
| var yieldVaultIDs = getYieldVaultIDs(address: user.address) | ||
| log("[TEST] YieldVault ID: \(yieldVaultIDs![0])") | ||
| Test.assert(yieldVaultIDs != nil, message: "Expected user's YieldVault IDs to be non-nil but encountered nil") | ||
| Test.assertEqual(1, yieldVaultIDs!.length) | ||
|
|
||
| var yieldVaultBalance = getYieldVaultBalance(address: user.address, yieldVaultID: yieldVaultIDs![0]) | ||
|
|
||
| log("[TEST] Initial yield vault balance: \(yieldVaultBalance ?? 0.0)") | ||
|
|
||
| rebalanceYieldVault(signer: flowYieldVaultsAccount, id: yieldVaultIDs![0], force: true, beFailed: false) | ||
| rebalancePosition(signer: flowCreditMarketAccount, pid: pid, force: true, beFailed: false) | ||
|
|
||
| testSnapshot = getCurrentBlockHeight() | ||
|
|
||
| for flowPrice in flowPrices { | ||
| if (getCurrentBlockHeight() > testSnapshot) { | ||
| Test.reset(to: testSnapshot) | ||
| } | ||
| yieldVaultBalance = getYieldVaultBalance(address: user.address, yieldVaultID: yieldVaultIDs![0]) | ||
|
|
||
| log("[TEST] YieldVault balance before flow price \(flowPrice) \(yieldVaultBalance ?? 0.0)") | ||
|
|
||
| setBandOraclePrice(signer: bandOracleAccount, symbol: "FLOW", price: flowPrice) | ||
|
|
||
| yieldVaultBalance = getYieldVaultBalance(address: user.address, yieldVaultID: yieldVaultIDs![0]) | ||
|
|
||
| log("[TEST] YieldVault balance before flow price \(flowPrice) rebalance: \(yieldVaultBalance ?? 0.0)") | ||
|
|
||
| // Get yield token balance before rebalance | ||
| let yieldTokensBefore = getAutoBalancerBalance(id: yieldVaultIDs![0]) ?? 0.0 | ||
| let currentValueBefore = getAutoBalancerCurrentValue(id: yieldVaultIDs![0]) ?? 0.0 | ||
|
|
||
| rebalanceYieldVault(signer: flowYieldVaultsAccount, id: yieldVaultIDs![0], force: false, beFailed: false) | ||
| rebalancePosition(signer: flowCreditMarketAccount, pid: pid, force: false, beFailed: false) | ||
|
|
||
| yieldVaultBalance = getYieldVaultBalance(address: user.address, yieldVaultID: yieldVaultIDs![0]) | ||
|
|
||
| log("[TEST] YieldVault balance after flow before \(flowPrice): \(yieldVaultBalance ?? 0.0)") | ||
|
|
||
| // Get yield token balance after rebalance | ||
| let yieldTokensAfter = getAutoBalancerBalance(id: yieldVaultIDs![0]) ?? 0.0 | ||
| let currentValueAfter = getAutoBalancerCurrentValue(id: yieldVaultIDs![0]) ?? 0.0 | ||
|
|
||
| // Get expected yield tokens from Google sheet calculations | ||
| let expectedYieldTokens = expectedYieldTokenValues[flowPrice] ?? 0.0 | ||
|
|
||
| log("\n=== SCENARIO 1 DETAILS for Flow Price \(flowPrice) ===") | ||
| log("YieldVault Balance: \(yieldVaultBalance ?? 0.0)") | ||
| log("Yield Tokens Before: \(yieldTokensBefore)") | ||
| log("Yield Tokens After: \(yieldTokensAfter)") | ||
| log("Expected Yield Tokens: \(expectedYieldTokens)") | ||
| let precisionDiff = yieldTokensAfter > expectedYieldTokens ? yieldTokensAfter - expectedYieldTokens : expectedYieldTokens - yieldTokensAfter | ||
| let precisionSign = yieldTokensAfter > expectedYieldTokens ? "+" : "-" | ||
| log("Precision Difference: \(precisionSign)\(precisionDiff)") | ||
| let percentDiff = expectedYieldTokens > 0.0 ? (precisionDiff / expectedYieldTokens) * 100.0 : 0.0 | ||
| log("Percent Difference: \(precisionSign)\(percentDiff)%") | ||
|
|
||
| // check if percent difference is within tolerance | ||
| let percentToleranceCheck = equalAmounts(a: percentDiff, b: 0.0, tolerance: forkedPercentTolerance) | ||
| Test.assert(percentToleranceCheck, message: "Percent difference \(percentDiff)% is not within tolerance \(forkedPercentTolerance)%") | ||
| log("Percent difference \(percentDiff)% is within tolerance \(forkedPercentTolerance)%") | ||
|
|
||
| let yieldChange = yieldTokensAfter > yieldTokensBefore ? yieldTokensAfter - yieldTokensBefore : yieldTokensBefore - yieldTokensAfter | ||
| let yieldSign = yieldTokensAfter > yieldTokensBefore ? "+" : "-" | ||
| log("Yield Token Change: \(yieldSign)\(yieldChange)") | ||
| log("Current Value Before: \(currentValueBefore)") | ||
| log("Current Value After: \(currentValueAfter)") | ||
| let valueChange = currentValueAfter > currentValueBefore ? currentValueAfter - currentValueBefore : currentValueBefore - currentValueAfter | ||
| let valueSign = currentValueAfter > currentValueBefore ? "+" : "-" | ||
| log("Value Change: \(valueSign)\(valueChange)") | ||
| log("=============================================\n") | ||
| } | ||
|
|
||
| closeYieldVault(signer: user, id: yieldVaultIDs![0], beFailed: false) | ||
|
|
||
| let flowBalanceAfter = getBalance(address: user.address, vaultPublicPath: /public/flowTokenReceiver)! | ||
| log("[TEST] flow balance after \(flowBalanceAfter)") | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import "FlowCreditMarket" | ||
| import "MockOracle" | ||
| import "DeFiActions" | ||
|
|
||
| /// Updates the pool's price oracle to use MockOracle | ||
| /// This is useful for testing purposes where we want to control token prices | ||
| /// | ||
| transaction() { | ||
| let pool: auth(FlowCreditMarket.EGovernance) &FlowCreditMarket.Pool | ||
| let oracle: {DeFiActions.PriceOracle} | ||
|
|
||
| prepare(signer: auth(BorrowValue) &Account) { | ||
| self.pool = signer.storage.borrow<auth(FlowCreditMarket.EGovernance) &FlowCreditMarket.Pool>(from: FlowCreditMarket.PoolStoragePath) | ||
| ?? panic("Could not borrow reference to Pool from \(FlowCreditMarket.PoolStoragePath) - ensure a Pool has been configured") | ||
|
|
||
| // Create a MockOracle.PriceOracle - the unitOfAccount will be set based on the pool's default token | ||
| self.oracle = MockOracle.PriceOracle() | ||
| } | ||
|
|
||
| execute { | ||
| self.pool.setPriceOracle(self.oracle) | ||
| } | ||
| } | ||
|
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
expectedYieldTokenValuesare the debt notional (at target health factor) in the unit of account i.e MOET/USD:expectedYieldTokenValue = expectedDebt = fundingAmount * flowPrice * collateralFactor / targetHealthFactor. It doesn't not account for the fees associated with swapping (nor price impact) MOET to yieldToken on the DEX when we create the yieldVault (ie.yieldToMoetSwapperin thecreateStrategy), as a consequence:expectedYieldTokenValue < expectedDebt.The bridge fees are in FLOW and covered by the protocol.