Created
March 3, 2026 12:37
-
-
Save vivekascoder/72515b564f15ebca0364cdbba865465c to your computer and use it in GitHub Desktop.
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
| // SPDX-License-Identifier: UNLICENSED | |
| pragma solidity 0.8.28; | |
| import {Test} from "forge-std/Test.sol"; | |
| import {console2} from "forge-std/console2.sol"; | |
| import {AutopoolETH, IAutopool} from "../contracts/tranches/strategies/autousd/IAutopoolETH.sol"; | |
| /** | |
| * @title Autopool APR Fork Test | |
| * @notice Forks Ethereum mainnet and computes the base APR for autoUSD | |
| * vault using its profit unlock mechanism. | |
| */ | |
| contract AutopoolAPRTest is Test { | |
| uint256 constant SECONDS_PER_YEAR = 365 days; | |
| uint256 constant MAX_BPS_PROFIT = 1_000_000_000; | |
| // Tokemak / Auto Finance autoUSD vault on Ethereum mainnet | |
| address constant AUTO_USD = 0xa7569A44f348d3D70d8ad5889e50F78E33d80D35; | |
| function setUp() public { | |
| vm.createSelectFork(vm.envString("MAINNET_RPC_URL")); | |
| } | |
| // ─── APR computation ──────────────────────────────────────────────── | |
| /// @notice Computes the base APR from the profit unlock mechanism | |
| /// @param vault The autopool vault address | |
| /// @return apr The annualized yield rate (scaled by 1e18, i.e. 1e18 = 100%) | |
| function _getAPRbase(address vault) internal view returns (uint256 apr) { | |
| AutopoolETH autopool = AutopoolETH(vault); | |
| // Get profit unlock settings | |
| IAutopool.ProfitUnlockSettings memory settings = autopool.getProfitUnlockSettings(); | |
| // If no unlock period or unlock already completed, APR is 0 | |
| if (settings.unlockPeriodInSeconds == 0 || settings.fullProfitUnlockTime <= block.timestamp) { | |
| return 0; | |
| } | |
| // Time remaining until all locked profit is fully unlocked | |
| uint256 timeRemaining = uint256(settings.fullProfitUnlockTime) - block.timestamp; | |
| // Remaining locked shares = profitUnlockRate * timeRemaining / MAX_BPS_PROFIT | |
| uint256 remainingLockedShares = settings.profitUnlockRate * timeRemaining / MAX_BPS_PROFIT; | |
| // Get current vault state | |
| uint256 totalAssets = autopool.totalAssets(); | |
| uint256 totalSupply = autopool.totalSupply(); | |
| if (totalSupply == 0 || totalAssets == 0) { | |
| return 0; | |
| } | |
| // Unvested profit in asset terms | |
| uint256 unvestedProfit = remainingLockedShares * totalAssets / totalSupply; | |
| // APR = (unvestedProfit / timeRemaining) * SECONDS_PER_YEAR / totalAssets | |
| // Rearranged: unvestedProfit * SECONDS_PER_YEAR * 1e18 / (timeRemaining * totalAssets) | |
| apr = unvestedProfit * SECONDS_PER_YEAR * 1e18 / (timeRemaining * totalAssets); | |
| } | |
| // ─── Tests ────────────────────────────────────────────────────────── | |
| function test_autoUSD_APR() public view { | |
| uint256 apr = _getAPRbase(AUTO_USD); | |
| console2.log("===== autoUSD ====="); | |
| console2.log("APR (1e18 = 100%):", apr); | |
| console2.log("APR (%) :", apr * 100 / 1e18); | |
| console2.log("APR (bps) :", apr * 10_000 / 1e18); | |
| _logVaultState(AUTO_USD); | |
| } | |
| // ─── Helpers ──────────────────────────────────────────────────────── | |
| function _logVaultState(address vault) internal view { | |
| AutopoolETH autopool = AutopoolETH(vault); | |
| IAutopool.ProfitUnlockSettings memory settings = autopool.getProfitUnlockSettings(); | |
| console2.log("--- Vault State ---"); | |
| console2.log("totalAssets :", autopool.totalAssets()); | |
| console2.log("totalSupply :", autopool.totalSupply()); | |
| console2.log("--- Profit Unlock Settings ---"); | |
| console2.log("unlockPeriod (s) :", uint256(settings.unlockPeriodInSeconds)); | |
| console2.log("fullProfitUnlock :", uint256(settings.fullProfitUnlockTime)); | |
| console2.log("lastProfitUnlock :", uint256(settings.lastProfitUnlockTime)); | |
| console2.log("profitUnlockRate :", settings.profitUnlockRate); | |
| console2.log("block.timestamp :", block.timestamp); | |
| if (settings.fullProfitUnlockTime > block.timestamp) { | |
| console2.log("timeRemaining (s):", uint256(settings.fullProfitUnlockTime) - block.timestamp); | |
| } else { | |
| console2.log("timeRemaining (s): 0 (unlock complete)"); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment