WIP: Chain138 deployment scripts, flash receivers, HYBX OMNL recovery
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
import {Test} from "forge-std/Test.sol";
|
||||
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
||||
import {
|
||||
AaveUniV2CwStableRebalanceFlashReceiver
|
||||
} from "../../contracts/flash/AaveUniV2CwStableRebalanceFlashReceiver.sol";
|
||||
|
||||
contract AaveUniV2CwStableRebalanceFlashReceiverMainnetForkTest is Test {
|
||||
address constant AAVE_POOL = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2;
|
||||
address constant PAIR = 0xC28706F899266b36BC43cc072b3a921BDf2C48D9;
|
||||
address constant ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
|
||||
address constant CWUSDC = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a;
|
||||
address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
|
||||
address constant TOKEN_JAR = 0xf38521f130fcCF29dB1961597bc5d2B60F995f85;
|
||||
|
||||
bool internal forkAvailable;
|
||||
AaveUniV2CwStableRebalanceFlashReceiver internal receiver;
|
||||
|
||||
modifier skipIfNoFork() {
|
||||
if (!forkAvailable) return;
|
||||
_;
|
||||
}
|
||||
|
||||
function setUp() public {
|
||||
string memory rpcUrl = vm.envOr("ETHEREUM_MAINNET_RPC", string(""));
|
||||
if (bytes(rpcUrl).length == 0) {
|
||||
forkAvailable = false;
|
||||
return;
|
||||
}
|
||||
try vm.createSelectFork(rpcUrl) {
|
||||
forkAvailable = true;
|
||||
} catch {
|
||||
forkAvailable = false;
|
||||
return;
|
||||
}
|
||||
receiver = new AaveUniV2CwStableRebalanceFlashReceiver(AAVE_POOL, address(this));
|
||||
}
|
||||
|
||||
function testFork_flashRebalanceRemove_withTokenJarLp() public skipIfNoFork {
|
||||
uint256 lpBal = IERC20(PAIR).balanceOf(TOKEN_JAR);
|
||||
if (lpBal == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
(uint112 r0, uint112 r1,) = _reserves();
|
||||
uint256 baseRaw = address(IERC20(CWUSDC)) < address(IERC20(USDC)) ? r0 : r1;
|
||||
uint256 quoteRaw = address(IERC20(CWUSDC)) < address(IERC20(USDC)) ? r1 : r0;
|
||||
if (quoteRaw == 0 || baseRaw <= quoteRaw) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint256 flashIn = _quoteInToEqualize(baseRaw, quoteRaw);
|
||||
uint256 premium = (flashIn * 5 + 9999) / 10000;
|
||||
uint256 lpUse = lpBal;
|
||||
|
||||
vm.prank(TOKEN_JAR);
|
||||
IERC20(PAIR).transfer(address(receiver), lpUse);
|
||||
|
||||
uint256 minCwRebalance = 1;
|
||||
uint256 minCwRemove = 1;
|
||||
uint256 minStableRemove = 1;
|
||||
uint256 cwToSell = flashIn + premium + 50_000;
|
||||
uint256 minStableRepay = flashIn + premium;
|
||||
|
||||
address recipient = address(0xBEEF);
|
||||
receiver.runRebalanceRemove(
|
||||
USDC,
|
||||
flashIn,
|
||||
AaveUniV2CwStableRebalanceFlashReceiver.RebalanceRemoveParams({
|
||||
router: ROUTER,
|
||||
pair: PAIR,
|
||||
cwToken: CWUSDC,
|
||||
stableToken: USDC,
|
||||
lpAmount: lpUse,
|
||||
rebalanceStableIn: flashIn,
|
||||
minCwFromRebalance: minCwRebalance,
|
||||
minStableFromRemove: minStableRemove,
|
||||
minCwFromRemove: minCwRemove,
|
||||
cwToSellForRepay: cwToSell,
|
||||
minStableFromRepaySwap: minStableRepay,
|
||||
recipient: recipient
|
||||
})
|
||||
);
|
||||
|
||||
assertEq(IERC20(PAIR).balanceOf(address(receiver)), 0, "LP consumed");
|
||||
assertGt(IERC20(USDC).balanceOf(recipient) + IERC20(CWUSDC).balanceOf(recipient), 0, "recipient funded");
|
||||
}
|
||||
|
||||
function _reserves() internal view returns (uint112 r0, uint112 r1, uint32 ts) {
|
||||
(r0, r1, ts) = _getReserves(PAIR);
|
||||
}
|
||||
|
||||
function _getReserves(address pair) internal view returns (uint112, uint112, uint32) {
|
||||
(bool ok, bytes memory data) = pair.staticcall(abi.encodeWithSignature("getReserves()"));
|
||||
require(ok, "getReserves failed");
|
||||
return abi.decode(data, (uint112, uint112, uint32));
|
||||
}
|
||||
|
||||
function _quoteInToEqualize(uint256 baseRaw, uint256 quoteRaw) internal pure returns (uint256) {
|
||||
uint256 y = quoteRaw;
|
||||
uint256 x = baseRaw;
|
||||
// Integer approximation of closed-form quote-in (matches planner within rounding).
|
||||
uint256 xy = x * y;
|
||||
uint256 target = _isqrt(xy);
|
||||
if (target <= y) return y + 1;
|
||||
uint256 need = target - y;
|
||||
return (need * 1005) / 997 + 1;
|
||||
}
|
||||
|
||||
function _isqrt(uint256 n) internal pure returns (uint256) {
|
||||
if (n == 0) return 0;
|
||||
uint256 x = n;
|
||||
uint256 z = (x + 1) / 2;
|
||||
while (z < x) {
|
||||
x = z;
|
||||
z = (x + n / x) / 2;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user