Files
smom-dbis-138/test/flash/DBISEngineXSingleSidedDodoCwusdcVault.t.sol
defiQUG 76143a8fe3 feat(token-aggregation): reports, PMM quotes, config; Engine X flash vaults
- Expand token-aggregation API (report routes), canonical tokens, pools
- Add flash vault contracts + tests (indexed, DODO cwUSDC, XAUT borrow)
- PMM pools JSON, deploy/export scripts, metamask verified list

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 12:56:30 -07:00

180 lines
6.5 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Test} from "forge-std/Test.sol";
import {DBISEngineXSingleSidedDodoCwusdcVault} from
"../../contracts/flash/DBISEngineXSingleSidedDodoCwusdcVault.sol";
import {MockMintableToken} from "../dbis/MockMintableToken.sol";
contract MockDodoPool {
using SafeERC20 for IERC20;
address public immutable base;
address public immutable quote;
uint256 public baseReserve;
uint256 public quoteReserve;
constructor(address base_, address quote_) {
base = base_;
quote = quote_;
}
function _BASE_TOKEN_() external view returns (address) {
return base;
}
function _QUOTE_TOKEN_() external view returns (address) {
return quote;
}
function querySellBase(address, uint256 payBaseAmount) external pure returns (uint256 receiveQuoteAmount, uint256 mtFee) {
return (payBaseAmount, 0);
}
function querySellQuote(address, uint256 payQuoteAmount) external pure returns (uint256 receiveBaseAmount, uint256 mtFee) {
return (payQuoteAmount, 0);
}
function getVaultReserve() external view returns (uint256, uint256) {
return (baseReserve, quoteReserve);
}
function buyShares(address) external returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare) {
uint256 baseBalance = IERC20(base).balanceOf(address(this));
uint256 quoteBalance = IERC20(quote).balanceOf(address(this));
baseShare = baseBalance - baseReserve;
quoteShare = quoteBalance - quoteReserve;
baseReserve = baseBalance;
quoteReserve = quoteBalance;
lpShare = baseShare < quoteShare ? baseShare : quoteShare;
}
}
contract MockDodoIntegration {
using SafeERC20 for IERC20;
function addLiquidity(address pool, uint256 baseAmount, uint256 quoteAmount)
external
returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare)
{
require(baseAmount > 0 && quoteAmount > 0, "zero amount");
address base = MockDodoPool(pool)._BASE_TOKEN_();
address quote = MockDodoPool(pool)._QUOTE_TOKEN_();
IERC20(base).safeTransferFrom(msg.sender, pool, baseAmount);
IERC20(quote).safeTransferFrom(msg.sender, pool, quoteAmount);
return MockDodoPool(pool).buyShares(msg.sender);
}
}
contract DBISEngineXSingleSidedDodoCwusdcVaultTest is Test {
MockMintableToken internal cwusdc;
MockMintableToken internal weth;
MockDodoIntegration internal integration;
MockDodoPool internal pool;
DBISEngineXSingleSidedDodoCwusdcVault internal vault;
address internal constant FUNDER = address(0xF00D);
address internal constant OWNER = address(0xA11CE);
function setUp() public {
cwusdc = new MockMintableToken("Wrapped cWUSDC", "cWUSDC", 6, address(this));
weth = new MockMintableToken("Wrapped Ether", "WETH", 18, address(this));
integration = new MockDodoIntegration();
pool = new MockDodoPool(address(cwusdc), address(weth));
vault = new DBISEngineXSingleSidedDodoCwusdcVault(address(cwusdc), address(weth), address(integration), OWNER);
cwusdc.mint(FUNDER, 100_000_000);
weth.mint(FUNDER, 1 ether);
vm.startPrank(FUNDER);
cwusdc.approve(address(vault), type(uint256).max);
weth.approve(address(vault), type(uint256).max);
vm.stopPrank();
}
function testAcceptsSingleSidedCwusdcAsInventoryButNotExecutable() public {
vm.prank(FUNDER);
vault.depositCwusdc(10_000_000);
(
uint256 cwusdcBalance,
uint256 quoteBalance,
uint256 cwusdcInventory,
uint256 quoteInventory,
bool solvent,
bool executable
) = vault.solvencyState();
assertEq(cwusdcBalance, 10_000_000, "cw balance");
assertEq(quoteBalance, 0, "quote balance");
assertEq(cwusdcInventory, 10_000_000, "cw inventory");
assertEq(quoteInventory, 0, "quote inventory");
assertTrue(solvent, "single-sided inventory is solvent");
assertFalse(executable, "single-sided inventory is not executable DODO liquidity");
}
function testPromoteRequiresTwoSidedInventory() public {
vm.prank(OWNER);
vault.setDodoPool(address(pool));
vm.prank(OWNER);
vault.setCanary(1_000, 1_000, 1_000, 1_000);
vm.prank(FUNDER);
vault.depositCwusdc(10_000_000);
vm.expectRevert(bytes("two-sided required"));
vm.prank(OWNER);
vault.promoteToDodo(1_000_000, 0, 0, 0, 0);
vm.expectRevert(bytes("insufficient quote inventory"));
vm.prank(OWNER);
vault.promoteToDodo(1_000_000, 1, 0, 0, 0);
}
function testPromotesTwoSidedInventoryAndPassesCanary() public {
vm.prank(OWNER);
vault.setDodoPool(address(pool));
vm.prank(OWNER);
vault.setCanary(1_000, 1_000, 1_000, 1_000);
vm.startPrank(FUNDER);
vault.depositCwusdc(10_000_000);
vault.depositQuote(1 ether);
vm.stopPrank();
vm.prank(OWNER);
(uint256 baseShare, uint256 quoteShare, uint256 lpShare) =
vault.promoteToDodo(2_000_000, 2_000_000, 2_000_000, 2_000_000, 2_000_000);
assertEq(baseShare, 2_000_000, "base share");
assertEq(quoteShare, 2_000_000, "quote share");
assertEq(lpShare, 2_000_000, "lp share");
assertEq(vault.accountedCwusdcInventory(), 8_000_000, "remaining cw inventory");
assertEq(vault.accountedQuoteInventory(), 1 ether - 2_000_000, "remaining quote inventory");
assertEq(cwusdc.balanceOf(address(pool)), 2_000_000, "pool cw balance");
assertEq(weth.balanceOf(address(pool)), 2_000_000, "pool quote balance");
assertTrue(vault.canaryPasses(), "canary passes");
}
function testCannotRescueAccountedInventory() public {
vm.prank(FUNDER);
vault.depositCwusdc(10_000_000);
vm.expectRevert(bytes("cwusdc insolvent"));
vm.prank(OWNER);
vault.rescueUnaccountedToken(address(cwusdc), OWNER, 1);
}
function testOwnerCanWithdrawAccountedInventory() public {
vm.prank(FUNDER);
vault.depositCwusdc(10_000_000);
vm.prank(OWNER);
vault.withdrawCwusdcInventory(OWNER, 4_000_000);
assertEq(vault.accountedCwusdcInventory(), 6_000_000, "inventory decremented");
assertEq(cwusdc.balanceOf(OWNER), 4_000_000, "owner received");
}
}