// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Test} from "forge-std/Test.sol"; import {DBISEngineXIndexedLiquidityVault} from "../../contracts/flash/DBISEngineXIndexedLiquidityVault.sol"; import {MockMintableToken} from "../dbis/MockMintableToken.sol"; contract MockEngineXUniswapV3Pool { address public immutable token0; address public immutable token1; uint24 public immutable fee; uint160 public sqrtPriceX96; int24 public tick; uint128 public liquidity; constructor(address token0_, address token1_, uint24 fee_) { token0 = token0_; token1 = token1_; fee = fee_; } function setSlot0(uint160 sqrtPriceX96_, int24 tick_) external { sqrtPriceX96 = sqrtPriceX96_; tick = tick_; } function setLiquidity(uint128 liquidity_) external { liquidity = liquidity_; } function slot0() external view returns (uint160, int24, uint16, uint16, uint16, uint8, bool) { return (sqrtPriceX96, tick, 0, 0, 0, 0, true); } } contract DBISEngineXIndexedLiquidityVaultTest is Test { MockMintableToken internal cwusdc; MockMintableToken internal usdc; MockEngineXUniswapV3Pool internal pool; DBISEngineXIndexedLiquidityVault internal vault; address internal constant RECIPIENT = address(0xD00D); uint160 internal constant ONE_TO_ONE_SQRT_PRICE_X96 = 79_228_162_514_264_337_593_543_950_336; bytes32 internal constant PROOF_ID = bytes32("indexed-proof"); bytes32 internal constant SWAP_TX = bytes32(uint256(0xA1)); bytes32 internal constant LIQUIDITY_TX = bytes32(uint256(0xB1)); bytes32 internal constant ISO_HASH = bytes32(uint256(0x1001)); bytes32 internal constant AUDIT_HASH = bytes32(uint256(0x1002)); bytes32 internal constant PEG_HASH = bytes32(uint256(0x1003)); function setUp() public { cwusdc = new MockMintableToken("Wrapped cWUSDC", "cWUSDC", 6, address(this)); usdc = new MockMintableToken("USD Coin", "USDC", 6, address(this)); pool = new MockEngineXUniswapV3Pool(address(cwusdc), address(usdc), 100); pool.setSlot0(ONE_TO_ONE_SQRT_PRICE_X96, 0); pool.setLiquidity(1_000_000); cwusdc.mint(address(pool), 100_000_000); usdc.mint(address(pool), 100_000_000); vault = new DBISEngineXIndexedLiquidityVault( address(cwusdc), address(usdc), address(pool), address(this), 100, 1_000, 1_000_000 ); } function testRecordIndexedProofAnchorsPublicPoolState() public { DBISEngineXIndexedLiquidityVault.IndexedProof memory proof = _proof(PROOF_ID); (uint160 sqrtPriceX96, int24 tick, uint128 liquidity) = vault.recordIndexedProof(proof); assertEq(sqrtPriceX96, ONE_TO_ONE_SQRT_PRICE_X96, "sqrt price"); assertEq(tick, 0, "tick"); assertEq(liquidity, 1_000_000, "liquidity"); assertTrue(vault.usedProofIds(PROOF_ID), "proof consumed"); } function testRejectsDuplicateProofId() public { vault.recordIndexedProof(_proof(PROOF_ID)); vm.expectRevert(bytes("proof used")); vault.recordIndexedProof(_proof(PROOF_ID)); } function testRejectsTickDrift() public { pool.setSlot0(ONE_TO_ONE_SQRT_PRICE_X96, 101); vm.expectRevert(bytes("tick drift too high")); vault.recordIndexedProof(_proof(PROOF_ID)); } function testRejectsInsufficientLiquidity() public { pool.setLiquidity(999); vm.expectRevert(bytes("insufficient liquidity")); vault.recordIndexedProof(_proof(PROOF_ID)); } function testRejectsOversizedProofAmount() public { DBISEngineXIndexedLiquidityVault.IndexedProof memory proof = _proof(PROOF_ID); proof.exactOutputAmount = 1_000_001; vm.expectRevert(bytes("proof amount too high")); vault.recordIndexedProof(proof); } function testOperatorAllowlist() public { vault.setOperatorAllowlistEnabled(true); vm.expectRevert(bytes("operator not approved")); vm.prank(address(0xBEEF)); vault.recordIndexedProof(_proof(PROOF_ID)); vault.setOperatorApproved(address(0xBEEF), true); vm.prank(address(0xBEEF)); vault.recordIndexedProof(_proof(PROOF_ID)); assertTrue(vault.usedProofIds(PROOF_ID), "proof consumed"); } function testPauseBlocksProofs() public { vault.pause(); vm.expectRevert(bytes("paused")); vault.recordIndexedProof(_proof(PROOF_ID)); } function _proof(bytes32 proofId) internal pure returns (DBISEngineXIndexedLiquidityVault.IndexedProof memory) { return DBISEngineXIndexedLiquidityVault.IndexedProof({ proofId: proofId, publicSwapTxHash: SWAP_TX, liquidityTxHash: LIQUIDITY_TX, outputRecipient: RECIPIENT, exactOutputAmount: 100_000, iso20022DocumentHash: ISO_HASH, auditEnvelopeHash: AUDIT_HASH, pegProofHash: PEG_HASH }); } }