Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ out/

# Dotenv file
.env

# Coverage file
lcov.info
8 changes: 6 additions & 2 deletions src/MaglevBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import {EVCUtil} from "evc/utils/EVCUtil.sol";
import {IEVC} from "evc/interfaces/IEthereumVaultConnector.sol";
import {IEVault, IERC20, IBorrowing, IERC4626, IRiskManager} from "evk/EVault/IEVault.sol";
import {IUniswapV2Callee} from "./interfaces/IUniswapV2Callee.sol";
import {IMaglevBase} from "./interfaces/IMaglevBase.sol";

abstract contract MaglevBase is EVCUtil {
abstract contract MaglevBase is IMaglevBase, EVCUtil {
address public immutable vault0;
address public immutable vault1;
address public immutable asset0;
Expand Down Expand Up @@ -51,6 +52,9 @@ abstract contract MaglevBase is EVCUtil {
vault1 = params.vault1;
asset0 = IEVault(vault0).asset();
asset1 = IEVault(vault1).asset();

require(asset0 != asset1, UnsupportedPair());

myAccount = params.myAccount;
reserve0 = offsetReserve(params.debtLimit0, vault0);
reserve1 = offsetReserve(params.debtLimit1, vault1);
Expand Down Expand Up @@ -82,7 +86,7 @@ abstract contract MaglevBase is EVCUtil {

// Invoke callback

if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(_msgSender(), amount0Out, amount1Out, data);

// Deposit all available funds, adjust received amounts downward to collect fees

Expand Down
3 changes: 2 additions & 1 deletion src/MaglevEulerSwap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ pragma solidity ^0.8.27;

import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {MaglevBase} from "./MaglevBase.sol";
import {IMaglevEulerSwap} from "./interfaces/IMaglevEulerSwap.sol";

contract MaglevEulerSwap is MaglevBase {
contract MaglevEulerSwap is IMaglevEulerSwap, MaglevBase {
uint256 public immutable priceX;
uint256 public immutable priceY;
uint256 public immutable concentrationX;
Expand Down
20 changes: 20 additions & 0 deletions src/interfaces/IMaglevBase.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

interface IMaglevBase {
function configure() external;
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
function quoteExactInput(address tokenIn, address tokenOut, uint256 amountIn) external view returns (uint256);
function quoteExactOutput(address tokenIn, address tokenOut, uint256 amountOut) external view returns (uint256);

function vault0() external view returns (address);
function vault1() external view returns (address);
function asset0() external view returns (address);
function asset1() external view returns (address);
function myAccount() external view returns (address);
function debtLimit0() external view returns (uint112);
function debtLimit1() external view returns (uint112);
function feeMultiplier() external view returns (uint256);
function reserve0() external view returns (uint112);
function reserve1() external view returns (uint112);
}
13 changes: 13 additions & 0 deletions src/interfaces/IMaglevEulerSwap.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.0;

import {IMaglevBase} from "./IMaglevBase.sol";

interface IMaglevEulerSwap is IMaglevBase {
function priceX() external view returns (uint256);
function priceY() external view returns (uint256);
function concentrationX() external view returns (uint256);
function concentrationY() external view returns (uint256);
function initialReserve0() external view returns (uint112);
function initialReserve1() external view returns (uint112);
}
83 changes: 83 additions & 0 deletions test/UniswapV2Call.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.24;

import {IUniswapV2Callee} from "../src/interfaces/IUniswapV2Callee.sol";
// import {Test, console} from "forge-std/Test.sol";
import {MaglevTestBase} from "./MaglevTestBase.t.sol";
import {MaglevEulerSwap as Maglev} from "../src/MaglevEulerSwap.sol";

contract UniswapV2CallTest is MaglevTestBase {
Maglev public maglev;
SwapCallbackTest swapCallback;

function setUp() public virtual override {
super.setUp();

createMaglev(50e18, 50e18, 0, 1e18, 1e18, 0.4e18, 0.85e18);

swapCallback = new SwapCallbackTest();
}

function createMaglev(
uint112 debtLimit0,
uint112 debtLimit1,
uint256 fee,
uint256 px,
uint256 py,
uint256 cx,
uint256 cy
) internal {
vm.prank(creator);
maglev = new Maglev(
getMaglevBaseParams(debtLimit0, debtLimit1, fee),
Maglev.EulerSwapParams({priceX: px, priceY: py, concentrationX: cx, concentrationY: cy})
);

vm.prank(holder);
evc.setAccountOperator(holder, address(maglev), true);

vm.prank(anyone);
maglev.configure();
}

function test_callback() public {
uint256 amountIn = 1e18;
uint256 amountOut = maglev.quoteExactInput(address(assetTST), address(assetTST2), amountIn);
assertApproxEqAbs(amountOut, 0.9974e18, 0.0001e18);

assetTST.mint(address(this), amountIn);
assetTST.transfer(address(maglev), amountIn);

uint256 randomBalance = 3e18;
vm.prank(anyone);
swapCallback.executeSwap(maglev, 0, amountOut, abi.encode(randomBalance));
assertEq(assetTST2.balanceOf(address(swapCallback)), amountOut);
assertEq(swapCallback.callbackSender(), address(swapCallback));
assertEq(swapCallback.callbackAmount0(), 0);
assertEq(swapCallback.callbackAmount1(), amountOut);
assertEq(swapCallback.randomBalance(), randomBalance);
}
}

contract SwapCallbackTest is IUniswapV2Callee {
address public callbackSender;
uint256 public callbackAmount0;
uint256 public callbackAmount1;
uint256 public randomBalance;

function executeSwap(Maglev maglev, uint256 amountIn, uint256 amountOut, bytes calldata data) external {
maglev.swap(amountIn, amountOut, address(this), data);
}

function uniswapV2Call(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external {
randomBalance = abi.decode(data, (uint256));

callbackSender = sender;
callbackAmount0 = amount0;
callbackAmount1 = amount1;
}

function test_avoid_coverage() public pure {
return;
}
}
Loading