diff --git a/lib/pt-v5-prize-pool b/lib/pt-v5-prize-pool index 568ca55..5fd88ca 160000 --- a/lib/pt-v5-prize-pool +++ b/lib/pt-v5-prize-pool @@ -1 +1 @@ -Subproject commit 568ca55a911a9310bc767a173a0c8a734f7f158c +Subproject commit 5fd88ca597a1632f22dbc8c975cde4bf445c3120 diff --git a/lib/rETHERC4626 b/lib/rETHERC4626 index b746814..c2605b5 160000 --- a/lib/rETHERC4626 +++ b/lib/rETHERC4626 @@ -1 +1 @@ -Subproject commit b746814cd09b9ec6cb92d5842a979ebcbdcb04b2 +Subproject commit c2605b507606d32b0339f3a7599a259bf8d7d2f5 diff --git a/test/integration/BaseIntegration.t.sol b/test/integration/BaseIntegration.t.sol index 2101879..78b40f8 100644 --- a/test/integration/BaseIntegration.t.sol +++ b/test/integration/BaseIntegration.t.sol @@ -337,12 +337,14 @@ abstract contract BaseIntegration is Test, Permit { uint256 totalSupplyAfter = prizeVault.totalSupply(); assertEq(prizeVault.balanceOf(depositors[i]), amount, "shares minted"); - assertApproxEqAbs( - totalAssetsBefore + amount, - totalAssetsAfter, - 10 ** assetPrecisionLoss, - "assets accounted for with possible rounding error" - ); + if (totalAssetsAfter < totalAssetsBefore + amount) { + assertApproxEqAbs( + totalAssetsBefore + amount, + totalAssetsAfter, + 10 ** assetPrecisionLoss, + "assets accounted for with possible rounding error" + ); + } assertEq(totalSupplyBefore + amount, totalSupplyAfter, "supply increased by amount"); } } diff --git a/test/integration/beefy/BeefyOpSnxUsdc.t.sol b/test/integration/beefy/BeefyOpSnxUsdc.t.sol new file mode 100644 index 0000000..a30341a --- /dev/null +++ b/test/integration/beefy/BeefyOpSnxUsdc.t.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { BaseIntegration, IERC20, IERC4626 } from "../BaseIntegration.t.sol"; + +contract BeefyOpSnxUsdcIntegrationTest is BaseIntegration { + uint256 fork; + uint256 forkBlock = 123080680; + uint256 forkBlockTimestamp = 1721760137; + + address internal _beefyWrapper = address(0x182be93E1C0C4d305fe43bD093292F21fd679797); + + address internal _asset = address(0x894d6Ea97767EbeCEfE01c9410f6Bd67935AA952); + address internal _assetWhale = address(0xde4901634990888102A7A017f36c7bd2F1Dc2B1e); + address internal _yieldVault; + address internal _mooVault = address(0x6A058d02bfFBaf75d9a9bdF2AA3B0F691F7777D5); + address internal _mooYieldSource = address(0xe9E82973983951388C9B334A56D4Df26971e4Cdd); + + /* ============ setup ============ */ + + function setUpUnderlyingAsset() public virtual override returns (IERC20 asset, uint8 decimals, uint256 approxAssetUsdExchangeRate) { + // withdraw some assets from the moo vault so the whale balance is uncoupled from yield + vm.startPrank(_assetWhale); + (bool success2,) = _mooVault.call(abi.encodeWithSignature("withdrawAll()")); + require(success2, "withdraw failed"); + vm.stopPrank(); + require(IERC20(_asset).balanceOf(_assetWhale) > 0, "zero whale balance"); + return (IERC20(_asset), 18, 60_000_000e18); + } + + function setUpYieldVault() public virtual override returns (IERC4626) { + (bool success, bytes memory data) = _beefyWrapper.call(abi.encodeWithSignature("clone(address)", _mooVault)); + require(success, "beefy vault wrapper failed"); + (_yieldVault) = abi.decode(data, (address)); + return IERC4626(_yieldVault); + } + + function setUpFork() public virtual override { + fork = vm.createFork(vm.rpcUrl("optimism"), forkBlock); + vm.selectFork(fork); + vm.warp(forkBlockTimestamp); + } + + function beforeSetup() public virtual override { + lowGasPriceEstimate = 0.05 gwei; // just L2 gas, we ignore L1 costs for a super low estimate + ignoreLoss = true; // loss would occur on the LP token, not the reward contract + } + + function afterSetup() public virtual override { } + + /* ============ helpers to override ============ */ + + /// @dev The max amount of assets than can be dealt. + function maxDeal() public virtual override returns (uint256) { + return underlyingAsset.balanceOf(_assetWhale); + } + + /// @dev May revert if the amount requested exceeds the amount available to deal. + function dealAssets(address to, uint256 amount) public virtual override prankception(_assetWhale) { + underlyingAsset.transfer(to, amount); + } + + /// @dev Accrues yield by letting time pass and triggering multiple yield accruals + function _accrueYield() internal virtual override prankception(_assetWhale) { + // yield accrues on deposit / withdraw so we can do a deposit and withdraw to the yield vault directly to trigger some yield accrual + uint256 amount = maxDeal() / 100; // some small amount of assets + underlyingAsset.approve(_yieldVault, amount); + yieldVault.deposit(amount, _assetWhale); + vm.warp(block.timestamp + 1 days); // let 1 day pass by + uint256 maxRedeem = yieldVault.maxRedeem(_assetWhale); + yieldVault.redeem(maxRedeem, _assetWhale, _assetWhale); + + // we also call a deposit directly on the moo vault to ensure it triggers a yield accrual + underlyingAsset.approve(_mooVault, amount); + (bool success,) = _mooVault.call(abi.encodeWithSignature("deposit(uint256)", amount)); + assertEq(success, true, "moo vault deposit success"); + } + + function _simulateLoss() internal virtual override { + + } + +} \ No newline at end of file diff --git a/test/integration/beefy/BeefyOpUsdcOp.t.sol b/test/integration/beefy/BeefyOpUsdcOp.t.sol new file mode 100644 index 0000000..e176d77 --- /dev/null +++ b/test/integration/beefy/BeefyOpUsdcOp.t.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { BaseIntegration, IERC20, IERC4626 } from "../BaseIntegration.t.sol"; + +contract BeefyOpUsdcOpIntegrationTest is BaseIntegration { + uint256 fork; + uint256 forkBlock = 123080680; + uint256 forkBlockTimestamp = 1721760137; + + address internal _beefyWrapper = address(0x182be93E1C0C4d305fe43bD093292F21fd679797); + + address internal _asset = address(0x67F56Ac099F11aD5F65E2ec804f75F2cEa6ab8C5); + address internal _assetWhale = address(0x4DbD33be91F61d7101Fd455B8D5c783143817b8e); + address internal _yieldVault; + address internal _mooVault = address(0xC1CE18ee03bED17676021ca0B84F550339c66a24); + address internal _mooYieldSource = address(0xF355CCBbdFB8606d468b38BbF7830b7795F523A4); + + /* ============ setup ============ */ + + function setUpUnderlyingAsset() public virtual override returns (IERC20 asset, uint8 decimals, uint256 approxAssetUsdExchangeRate) { + return (IERC20(_asset), 18, 85720000e18); + } + + function setUpYieldVault() public virtual override returns (IERC4626) { + (bool success, bytes memory data) = _beefyWrapper.call(abi.encodeWithSignature("clone(address)", _mooVault)); + require(success, "beefy vault wrapper failed"); + (_yieldVault) = abi.decode(data, (address)); + return IERC4626(_yieldVault); + } + + function setUpFork() public virtual override { + fork = vm.createFork(vm.rpcUrl("optimism"), forkBlock); + vm.selectFork(fork); + vm.warp(forkBlockTimestamp); + } + + function beforeSetup() public virtual override { + lowGasPriceEstimate = 0.05 gwei; // just L2 gas, we ignore L1 costs for a super low estimate + ignoreLoss = true; // loss would occur on the LP token, not the reward contract + } + + function afterSetup() public virtual override { } + + /* ============ helpers to override ============ */ + + /// @dev The max amount of assets than can be dealt. + function maxDeal() public virtual override returns (uint256) { + return underlyingAsset.balanceOf(_assetWhale); + } + + /// @dev May revert if the amount requested exceeds the amount available to deal. + function dealAssets(address to, uint256 amount) public virtual override prankception(_assetWhale) { + underlyingAsset.transfer(to, amount); + } + + /// @dev Accrues yield by letting time pass and triggering multiple yield accruals + function _accrueYield() internal virtual override prankception(_assetWhale) { + // yield accrues on deposit / withdraw so we can do a deposit and withdraw to the yield vault directly to trigger some yield accrual + uint256 amount = maxDeal() / 100; // some small amount of assets + underlyingAsset.approve(_yieldVault, amount); + yieldVault.deposit(amount, _assetWhale); + vm.warp(block.timestamp + 1 days); // let 1 day pass by + uint256 maxRedeem = yieldVault.maxRedeem(_assetWhale); + yieldVault.redeem(maxRedeem, _assetWhale, _assetWhale); + + // we also call a deposit directly on the moo vault to ensure it triggers a yield accrual + underlyingAsset.approve(_mooVault, amount); + (bool success,) = _mooVault.call(abi.encodeWithSignature("deposit(uint256)", amount)); + assertEq(success, true, "moo vault deposit success"); + } + + function _simulateLoss() internal virtual override { + + } + +} \ No newline at end of file diff --git a/test/integration/beefy/BeefyOpVeloUsdc.t.sol b/test/integration/beefy/BeefyOpVeloUsdc.t.sol new file mode 100644 index 0000000..d6e8e7f --- /dev/null +++ b/test/integration/beefy/BeefyOpVeloUsdc.t.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { BaseIntegration, IERC20, IERC4626 } from "../BaseIntegration.t.sol"; + +contract BeefyOpVeloUsdcIntegrationTest is BaseIntegration { + uint256 fork; + uint256 forkBlock = 123080680; + uint256 forkBlockTimestamp = 1721760137; + + address internal _beefyWrapper = address(0x182be93E1C0C4d305fe43bD093292F21fd679797); + + address internal _asset = address(0xa0A215dE234276CAc1b844fD58901351a50fec8A); + address internal _assetWhale = address(0x83eBCFf62016D94b495ecA88217164876d7AE947); + address internal _yieldVault; + address internal _mooVault = address(0x65eCE72Cc6Aad88432366DdD96b83AE62f8B1a71); + address internal _mooYieldSource = address(0xfc4AaA220a3938FF6516eBf40c1945e73064cB0A); + + /* ============ setup ============ */ + + function setUpUnderlyingAsset() public virtual override returns (IERC20 asset, uint8 decimals, uint256 approxAssetUsdExchangeRate) { + return (IERC20(_asset), 18, 600000e18); + } + + function setUpYieldVault() public virtual override returns (IERC4626) { + (bool success, bytes memory data) = _beefyWrapper.call(abi.encodeWithSignature("clone(address)", _mooVault)); + require(success, "beefy vault wrapper failed"); + (_yieldVault) = abi.decode(data, (address)); + return IERC4626(_yieldVault); + } + + function setUpFork() public virtual override { + fork = vm.createFork(vm.rpcUrl("optimism"), forkBlock); + vm.selectFork(fork); + vm.warp(forkBlockTimestamp); + } + + function beforeSetup() public virtual override { + lowGasPriceEstimate = 0.05 gwei; // just L2 gas, we ignore L1 costs for a super low estimate + ignoreLoss = true; // loss would occur on the LP token, not the reward contract + } + + function afterSetup() public virtual override { } + + /* ============ helpers to override ============ */ + + /// @dev The max amount of assets than can be dealt. + function maxDeal() public virtual override returns (uint256) { + return underlyingAsset.balanceOf(_assetWhale); + } + + /// @dev May revert if the amount requested exceeds the amount available to deal. + function dealAssets(address to, uint256 amount) public virtual override prankception(_assetWhale) { + underlyingAsset.transfer(to, amount); + } + + /// @dev Accrues yield by letting time pass and triggering multiple yield accruals + function _accrueYield() internal virtual override prankception(_assetWhale) { + // yield accrues on deposit / withdraw so we can do a deposit and withdraw to the yield vault directly to trigger some yield accrual + uint256 amount = maxDeal() / 100; // some small amount of assets + underlyingAsset.approve(_yieldVault, amount); + yieldVault.deposit(amount, _assetWhale); + vm.warp(block.timestamp + 1 days); // let 1 day pass by + uint256 maxRedeem = yieldVault.maxRedeem(_assetWhale); + yieldVault.redeem(maxRedeem, _assetWhale, _assetWhale); + + // we also call a deposit directly on the moo vault to ensure it triggers a yield accrual + underlyingAsset.approve(_mooVault, amount); + (bool success,) = _mooVault.call(abi.encodeWithSignature("deposit(uint256)", amount)); + assertEq(success, true, "moo vault deposit success"); + } + + function _simulateLoss() internal virtual override { + + } + +} \ No newline at end of file diff --git a/test/integration/beefy/BeefyOpWethTBtc.t.sol b/test/integration/beefy/BeefyOpWethTBtc.t.sol new file mode 100644 index 0000000..2f75d8d --- /dev/null +++ b/test/integration/beefy/BeefyOpWethTBtc.t.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import { BaseIntegration, IERC20, IERC4626 } from "../BaseIntegration.t.sol"; + +contract BeefyOpWethTBtcIntegrationTest is BaseIntegration { + uint256 fork; + uint256 forkBlock = 123080680; + uint256 forkBlockTimestamp = 1721760137; + + address internal _beefyWrapper = address(0x182be93E1C0C4d305fe43bD093292F21fd679797); + + address internal _asset = address(0xadBB23Bcc3C1B9810491897cb0690Cf645B858b1); + address internal _assetWhale = address(0xA39bA2CD8658D0B69bA1880dcfBB65216ab33056); + address internal _yieldVault; + address internal _mooVault = address(0xfd3B30e3145069e272E6144A9d1F3EED0fCCb2f9); + address internal _mooYieldSource = address(0xe789Ff828eA77197c91a67f105dC1AF9A1699585); + + /* ============ setup ============ */ + + function setUpUnderlyingAsset() public virtual override returns (IERC20 asset, uint8 decimals, uint256 approxAssetUsdExchangeRate) { + // withdraw some assets from the moo vault so the whale balance is uncoupled from yield + vm.startPrank(_assetWhale); + (bool success2,) = _mooVault.call(abi.encodeWithSignature("withdrawAll()")); + require(success2, "withdraw failed"); + vm.stopPrank(); + require(IERC20(_asset).balanceOf(_assetWhale) > 0, "zero whale balance"); + return (IERC20(_asset), 18, 30200e18); + } + + function setUpYieldVault() public virtual override returns (IERC4626) { + (bool success, bytes memory data) = _beefyWrapper.call(abi.encodeWithSignature("clone(address)", _mooVault)); + require(success, "beefy vault wrapper failed"); + (_yieldVault) = abi.decode(data, (address)); + return IERC4626(_yieldVault); + } + + function setUpFork() public virtual override { + fork = vm.createFork(vm.rpcUrl("optimism"), forkBlock); + vm.selectFork(fork); + vm.warp(forkBlockTimestamp); + } + + function beforeSetup() public virtual override { + lowGasPriceEstimate = 0.05 gwei; // just L2 gas, we ignore L1 costs for a super low estimate + ignoreLoss = true; // loss would occur on the LP token, not the reward contract + assetPrecisionLoss = 2; // a few wei is lost during deposit / withdraw from vault so we can assume an extra decimal of precision is needed + } + + function afterSetup() public virtual override { } + + /* ============ helpers to override ============ */ + + /// @dev The max amount of assets than can be dealt. + function maxDeal() public virtual override returns (uint256) { + return IERC20(_asset).balanceOf(_assetWhale); + } + + /// @dev May revert if the amount requested exceeds the amount available to deal. + function dealAssets(address to, uint256 amount) public virtual override prankception(_assetWhale) { + underlyingAsset.transfer(to, amount); + } + + /// @dev Accrues yield by letting time pass and triggering multiple yield accruals + function _accrueYield() internal virtual override prankception(_assetWhale) { + // yield accrues on deposit / withdraw so we can do a deposit and withdraw to the yield vault directly to trigger some yield accrual + uint256 amount = maxDeal() / 100; // some small amount of assets + underlyingAsset.approve(_yieldVault, amount); + yieldVault.deposit(amount, _assetWhale); + vm.warp(block.timestamp + 1 days); // let 1 day pass by + uint256 maxRedeem = yieldVault.maxRedeem(_assetWhale); + yieldVault.redeem(maxRedeem, _assetWhale, _assetWhale); + + // we also call a deposit directly on the moo vault to ensure it triggers a yield accrual + underlyingAsset.approve(_mooVault, amount); + (bool success,) = _mooVault.call(abi.encodeWithSignature("deposit(uint256)", amount)); + assertEq(success, true, "moo vault deposit success"); + } + + function _simulateLoss() internal virtual override { + + } + +} \ No newline at end of file