FarmMigrationOrchestratorV3Executor

Description:

Decentralized Finance (DeFi) protocol contract providing Mintable, Swap, Liquidity, Factory, Oracle functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "contracts/FarmMigrationOrchestratorV3Executor.sol": {
      "content": "// SPDX-License-Identifier: -- BCOM --

pragma solidity ^0.8.26;

import "./FarmMigrationOrchestratorV3Router.sol";

/**
 * @title FarmMigrationOrchestratorV3Executor
 * @notice Executes the complete migration process from FarmA to FarmB
 * @dev Inherits from FarmMigrationOrchestratorV3Router to access all the core functionality
 */
contract FarmMigrationOrchestratorV3Executor is FarmMigrationOrchestratorV3Router {

    address public owner;
    address public proposedOwner;

    modifier onlyOwner() {
        require(
            msg.sender == owner,
            "INVALID_OWNER"
        );
        _;
    }

    event OwnerProposed(
        address indexed newOwner
    );

    event OwnerChanged(
        address indexed newOwner
    );

    event MigrationCompleted(
        address indexed user,
        uint256 verseWithdrawn,
        uint256 tbtcSwapped,
        uint256 lpTokensAcquired,
        uint256 lpTokensStaked
    );

    constructor(
        address _simpleFarmA,
        address _simpleFarmB,
        address _verseToken,
        address _tbtcToken,
        address _balancerPool,
        address _balancerRouter
    ) FarmMigrationOrchestratorV3Router(
        _simpleFarmA,
        _simpleFarmB,
        _verseToken,
        _tbtcToken,
        _balancerPool,
        _balancerRouter
    ) {
        owner = msg.sender;
    }

    /**
     * @notice Execute the complete migration process
     * @param _farmReceiptAmount Amount of SimpleFarmA receipt tokens to migrate
     * @param _verseToSwap Amount of VERSE to swap for tBTC
     * @param _minTbtcOut Minimum tBTC to receive from swap
     * @param _deadline Transaction deadline
     */
    function executeMigration(
        uint256 _farmReceiptAmount,
        uint256 _verseToSwap,
        uint256 _minTbtcOut,
        uint256 _deadline
    )
        external
    {
        simpleFarmA.transferFrom(
            msg.sender,
            address(this),
            _farmReceiptAmount
        );

        simpleFarmA.farmWithdraw(
            _farmReceiptAmount
        );

        uint256 verseBalance = verseToken.balanceOf(
            address(this)
        );

        require(
            verseBalance >= _verseToSwap,
            "INSUFFICIENT_VERSE"
        );

        uint256 verseToUse = verseBalance;
        uint256 verseToSwapAmount = verseToUse
            * 20
            / 100;

        require(
            block.timestamp <= _deadline,
            "DEADLINE_EXPIRED"
        );

        uint256 tbtcReceived = _swapVerseToTbtcViaRouter(
            verseToSwapAmount,
            _minTbtcOut,
            _deadline
        );

        uint256 remainingVerse = verseToUse
            - verseToSwapAmount;

        uint256 lpTokensReceived = _addLiquidity(
            remainingVerse,
            tbtcReceived,
            _deadline
        );

        if (lpTokensReceived > 0) {

            lpToken.approve(
                address(simpleFarmB),
                lpTokensReceived
            );

            simpleFarmB.farmDeposit(
                lpTokensReceived
            );

            uint256 farmBBalance = simpleFarmB.balanceOf(
                address(this)
            );

            simpleFarmB.transfer(
                msg.sender,
                farmBBalance
            );
        }

        uint256 finalVerseBalance = verseToken.balanceOf(
            address(this)
        );

        if (finalVerseBalance > 0) {
            safeTransfer(
                verseToken,
                msg.sender,
                finalVerseBalance
            );
        }

        uint256 remainingTbtc = tbtcToken.balanceOf(
            address(this)
        );

        if (remainingTbtc > 0) {
            safeTransfer(
                tbtcToken,
                msg.sender,
                remainingTbtc
            );
        }

        emit MigrationCompleted(
            msg.sender,
            _farmReceiptAmount,
            tbtcReceived,
            lpTokensReceived,
            lpTokensReceived > 0
                ? simpleFarmB.balanceOf(address(this))
                : 0
        );
    }

    /**
     * @notice Propose a new owner
     */
    function proposeOwner(
        address _proposedOwner
    )
        external
        onlyOwner
    {
        proposedOwner = _proposedOwner;

        emit OwnerProposed(
            _proposedOwner
        );
    }

    /**
     * @notice Accept ownership
     */
    function acceptOwnership()
        external
    {
        require(
            msg.sender == proposedOwner,
            "INVALID_PROPOSED_OWNER"
        );

        owner = msg.sender;
        proposedOwner = address(0x0);

        emit OwnerChanged(
            msg.sender
        );
    }

    /**
     * @notice Emergency withdraw function
     */
    function emergencyWithdraw(
        IERC20 _token,
        uint256 _amount
    )
        external
        onlyOwner
    {
        safeTransfer(
            _token,
            owner,
            _amount
        );
    }

    /**
     * @notice Get pool information
     */
    function getPoolInfo()
        external
        view
        returns (
            address[] memory tokens,
            uint256 totalSupply,
            uint256 poolBalance
        )
    {
        tokens = balancerPool.getTokens();
        totalSupply = balancerPool.totalSupply();

        poolBalance = balancerPool.balanceOf(
            address(this)
        );
    }
}
"
    },
    "contracts/FarmMigrationOrchestratorV3Router.sol": {
      "content": "// SPDX-License-Identifier: -- BCOM --

pragma solidity =0.8.26;

import "./IERC20.sol";
import "./SafeERC20.sol";
import "./IBalancerV3Router.sol";
import "./IPermit2.sol";
import "./ISimpleFarm.sol";
import "./IBalancerV3Pool.sol";

/**
 * @title FarmMigrationOrchestratorV3Router
 * @notice Orchestrates migration from SimpleFarmA to SimpleFarmB using Balancer V3 Router with ZAP functionality
 * @dev This version uses the Balancer V3 Router for swaps and ZAP-like liquidity addition
 */
contract FarmMigrationOrchestratorV3Router is SafeERC20 {

    // Farm contracts
    ISimpleFarm public immutable simpleFarmA;
    ISimpleFarm public immutable simpleFarmB;

    // Token addresses
    IERC20 public immutable verseToken;
    IERC20 public immutable tbtcToken;
    IERC20 public immutable lpToken;

    // Balancer V3 addresses
    IBalancerV3Router public immutable balancerRouter;
    IBalancerV3Pool public immutable balancerPool;
    address public constant BALANCER_VAULT = 0xbA1333333333a1BA1108E8412f11850A5C319bA9;
    address public constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    event LiquidityAdded(
        address indexed user,
        uint256 verseAmountIn,
        uint256 tbtcAmountIn,
        uint256 lpTokensOut,
        uint256 exactBptAmountOut
    );

    constructor(
        address _simpleFarmA,
        address _simpleFarmB,
        address _verseToken,
        address _tbtcToken,
        address _balancerPool,
        address _balancerRouter
    ) {
        simpleFarmA = ISimpleFarm(
            _simpleFarmA
        );

        simpleFarmB = ISimpleFarm(
            _simpleFarmB
        );

        verseToken = IERC20(
            _verseToken
        );

        tbtcToken = IERC20(
            _tbtcToken
        );

        lpToken = IERC20(
            _balancerPool
        );

        balancerPool = IBalancerV3Pool(
            _balancerPool
        );

        balancerRouter = IBalancerV3Router(
            _balancerRouter
        );
    }

    /**
     * @notice Swap VERSE to tBTC using Balancer V3 Router
     */
    function _swapVerseToTbtcViaRouter(
        uint256 _verseAmount,
        uint256 _minTbtcOut,
        uint256 _deadline
    )
        internal
        returns (uint256)
    {
        verseToken.approve(
            PERMIT2,
            type(uint256).max
        );

        IPermit2(PERMIT2).approve(
            address(verseToken),
            address(balancerRouter),
            uint160(_verseAmount),
            uint48(_deadline)
        );

        uint256 amountOut = balancerRouter.swapSingleTokenExactIn(
            address(balancerPool),
            verseToken,
            tbtcToken,
            _verseAmount,
            _minTbtcOut,
            _deadline,
            false, // wethIsEth
            "" // userData
        );

        return amountOut;
    }

    /**
     * @notice Swap tBTC tokens to VERSE via Balancer V3 Router
     * @param _tbtcAmount Amount of tBTC tokens to swap
     * @param _minVerseOut Minimum amount of VERSE to receive
     * @param _deadline Transaction deadline
     * @return amountOut Amount of VERSE received
     */
    function _swapTbtcToVerseViaRouter(
        uint256 _tbtcAmount,
        uint256 _minVerseOut,
        uint256 _deadline
    )
        internal
        returns (uint256)
    {
        tbtcToken.approve(
            PERMIT2,
            type(uint256).max
        );

        IPermit2(PERMIT2).approve(
            address(tbtcToken),
            address(balancerRouter),
            uint160(_tbtcAmount),
            uint48(_deadline)
        );

        uint256 amountOut = balancerRouter.swapSingleTokenExactIn(
            address(balancerPool),
            tbtcToken,
            verseToken,
            _tbtcAmount,
            _minVerseOut,
            _deadline,
            false, // wethIsEth
            "" // userData
        );

        return amountOut;
    }

    /**
     * @notice Add liquidity to Balancer pool using Router with proportional amounts
     * @dev Uses addLiquidityProportional with calculated exactBptAmountOut
     */
    function _addLiquidityViaRouter(
        uint256 _verseAmount,
        uint256 _tbtcAmount,
        uint256 _exactBptAmountOut,
        uint256 _deadline
    )
        internal
        returns (uint256)
    {
        verseToken.approve(
            PERMIT2,
            type(uint256).max
        );

        tbtcToken.approve(
            PERMIT2,
            type(uint256).max
        );

        IPermit2(PERMIT2).approve(
            address(verseToken),
            address(balancerRouter),
            uint160(_verseAmount),
            uint48(_deadline)
        );

        IPermit2(PERMIT2).approve(
            address(tbtcToken),
            address(balancerRouter),
            uint160(_tbtcAmount),
            uint48(_deadline)
        );

        address[] memory poolTokens = balancerPool.getTokens();

        // Prepare maxAmountsIn array with correct token order
        uint256[] memory maxAmountsIn = new uint256[](2);
        if (poolTokens[0] == address(verseToken)) {
            maxAmountsIn[0] = _verseAmount;  // VERSE first
            maxAmountsIn[1] = _tbtcAmount;   // tBTC second
        } else {
            maxAmountsIn[0] = _tbtcAmount;   // tBTC first
            maxAmountsIn[1] = _verseAmount;  // VERSE second
        }

        uint256[] memory amountsIn = balancerRouter.addLiquidityProportional(
            address(balancerPool),
            maxAmountsIn,
            _exactBptAmountOut,
            false, // wethIsEth
            "" // userData
        );

        uint256 bptAmountOut = lpToken.balanceOf(
            address(this)
        );

        uint256 actualVerseAmount;
        uint256 actualTbtcAmount;

        if (poolTokens[0] == address(verseToken)) {
            // VERSE is first in pool, tBTC is second
            actualVerseAmount = amountsIn[0];
            actualTbtcAmount = amountsIn[1];
        } else {
            // tBTC is first in pool, VERSE is second
            actualVerseAmount = amountsIn[1];
            actualTbtcAmount = amountsIn[0];
        }

        emit LiquidityAdded(
            msg.sender,
            actualVerseAmount,
            actualTbtcAmount,
            bptAmountOut,
            _exactBptAmountOut
        );

        return bptAmountOut;
    }

    /**
     * @notice Internal function for adding liquidity
     * @dev Assumes tokens are already in this contract
     */
    function _addLiquidity(
        uint256 _verseAmount,
        uint256 _tbtcAmount,
        uint256 _deadline
    )
        internal
        returns (uint256)
    {
        // Calculate expected LP tokens
        uint256 expectedLpTokens = calculateExpectedLpTokens(
            _verseAmount,
            _tbtcAmount
        );

        // Add liquidity with calculated exactBptAmountOut
        uint256 lpTokensReceived = _addLiquidityViaRouter(
            _verseAmount,
            _tbtcAmount,
            expectedLpTokens,
            _deadline
        );

        return lpTokensReceived;
    }

    /**
     * @notice Public function for users to add liquidity directly
     * @dev Users must have VERSE and tBTC tokens approved to this contract
     * @param _exactBptAmountOut Exact amount of LP tokens to receive (0 for auto-calculation)
     */
    function addLiquidityPublic(
        uint256 _verseAmount,
        uint256 _tbtcAmount,
        uint256 _exactBptAmountOut,
        uint256 _deadline
    )
        external
        returns (uint256)
    {
        verseToken.transferFrom(
            msg.sender,
            address(this),
            _verseAmount
        );

        tbtcToken.transferFrom(
            msg.sender,
            address(this),
            _tbtcAmount
        );

        // Add liquidity with specified exactBptAmountOut or auto-calculate if 0
        uint256 exactBptAmountOut = _exactBptAmountOut == 0
            ? calculateExpectedLpTokens(
                _verseAmount,
                _tbtcAmount
            )
            : _exactBptAmountOut;

        // Validate deadline
        require(
            block.timestamp <= _deadline,
            "FarmMigrationOrchestratorV3Router: DEADLINE_EXPIRED"
        );

        uint256 lpTokensReceived = _addLiquidityViaRouter(
            _verseAmount,
            _tbtcAmount,
            exactBptAmountOut,
            _deadline
        );

        // Check orchestrator balances after liquidity addition
        uint256 orchestratorVerseBalance = verseToken.balanceOf(address(this));
        uint256 orchestratorTbtcBalance = tbtcToken.balanceOf(address(this));

        // Transfer LP tokens back to user
        if (lpTokensReceived > 0) {
            lpToken.transfer(
                msg.sender,
                lpTokensReceived
            );
        }

        // Return any remaining tokens to user
        if (orchestratorVerseBalance > 0) {
            verseToken.transfer(
                msg.sender,
                orchestratorVerseBalance
            );
        }

        if (orchestratorTbtcBalance > 0) {
            tbtcToken.transfer(
                msg.sender,
                orchestratorTbtcBalance
            );
        }

        return lpTokensReceived;
    }

    /**
     * @notice Public function to add liquidity and stake LP tokens in FarmB
     * @dev Users must have VERSE and tBTC tokens approved to this contract
     * @param _verseAmount Amount of VERSE tokens to add as liquidity
     * @param _tbtcAmount Amount of tBTC tokens to add as liquidity
     * @param _slippageBps Slippage tolerance in basis points (e.g., 1000 = 10%)
     * @return farmBReceipts Amount of FarmB receipt tokens received
     */
    function addLiquidityAndStake(
        uint256 _verseAmount,
        uint256 _tbtcAmount,
        uint256 _slippageBps,
        uint256 _deadline
    )
        external
        returns (uint256 farmBReceipts)
    {
        verseToken.transferFrom(
            msg.sender,
            address(this),
            _verseAmount
        );

        tbtcToken.transferFrom(
            msg.sender,
            address(this),
            _tbtcAmount
        );

        uint256 exactBptAmountOut = calculateExpectedLpTokens(
            _verseAmount,
            _tbtcAmount
        );

        uint256 slippageAdjustedBpt = (
            exactBptAmountOut * (10000 - _slippageBps)
        ) / 10000;

        uint256 lpTokensReceived = _addLiquidityViaRouter(
            _verseAmount,
            _tbtcAmount,
            slippageAdjustedBpt,
            _deadline
        );

        uint256 orchestratorVerseBalance = verseToken.balanceOf(
            address(this)
        );

        uint256 orchestratorTbtcBalance = tbtcToken.balanceOf(
            address(this)
        );

        if (lpTokensReceived > 0) {

            lpToken.approve(
                address(simpleFarmB),
                lpTokensReceived
            );

            simpleFarmB.farmDeposit(
                lpTokensReceived
            );

            farmBReceipts = simpleFarmB.balanceOf(
                address(this)
            );

            if (farmBReceipts > 0) {
                simpleFarmB.transfer(
                    msg.sender,
                    farmBReceipts
                );
            }
        }

        // Return any remaining tokens to user
        if (orchestratorVerseBalance > 0) {
            verseToken.transfer(
                msg.sender,
                orchestratorVerseBalance
            );
        }

        if (orchestratorTbtcBalance > 0) {
            tbtcToken.transfer(
                msg.sender,
                orchestratorTbtcBalance
            );
        }

        return farmBReceipts;
    }

    /**
     * @notice Universal ZAP function: Add liquidity and stake using either VERSE or tBTC tokens
     * @dev Automatically swaps the necessary amount to maintain 80/20 ratio, then adds liquidity and stakes
     * @param _tokenIn Address of the input token (VERSE or tBTC)
     * @param _amountIn Amount of input tokens to use
     * @param _slippageBps Slippage tolerance in basis points (e.g., 1000 = 10%)
     * @param _deadline Transaction deadline
     * @return farmBReceipts Amount of FarmB receipt tokens received
     */
    function zapToFarmB(
        address _tokenIn,
        uint256 _amountIn,
        uint256 _slippageBps,
        uint256 _deadline
    )
        external
        returns (uint256 farmBReceipts)
    {
        // Validate deadline
        require(
            block.timestamp <= _deadline,
            "FarmMigrationOrchestratorV3Router: DEADLINE_EXPIRED"
        );

        // Validate input token
        require(
            _tokenIn == address(verseToken) || _tokenIn == address(tbtcToken),
            "Invalid input token - must be VERSE or tBTC"
        );

        bool isVerseInput = _tokenIn == address(
            verseToken
        );

        IERC20 tokenIn = IERC20(
            _tokenIn
        );

        tokenIn.transferFrom(
            msg.sender,
            address(this),
            _amountIn
        );

        uint256 verseForLiquidity;
        uint256 tbtcForLiquidity;

        if (isVerseInput) {
            // VERSE input: swap 20% to tBTC for 80/20 ratio
            uint256 verseToSwap = (_amountIn * 20) / 100; // 20% of VERSE
            verseForLiquidity = _amountIn - verseToSwap; // 80% of VERSE

            // Swap VERSE to tBTC
            tbtcForLiquidity = _swapVerseToTbtcViaRouter(
                verseToSwap,
                0, // minTbtcOut - no minimum for ZAP
                _deadline
            );
        } else {
            // tBTC input: swap 80% to VERSE for 80/20 ratio
            uint256 tbtcToSwap = (_amountIn * 80) / 100; // 80% of tBTC
            tbtcForLiquidity = _amountIn - tbtcToSwap; // 20% of tBTC

            // Swap tBTC to VERSE using the proper swap function
            verseForLiquidity = _swapTbtcToVerseViaRouter(
                tbtcToSwap,
                0, // minVerseOut - no minimum for ZAP
                _deadline
            );
        }

        uint256 exactBptAmountOut = calculateExpectedLpTokens(
            verseForLiquidity,
            tbtcForLiquidity
        );

        uint256 slippageAdjustedBpt = (
            exactBptAmountOut * (10000 - _slippageBps)
        ) / 10000;

        uint256 lpTokensReceived = _addLiquidityViaRouter(
            verseForLiquidity,
            tbtcForLiquidity,
            slippageAdjustedBpt,
            _deadline
        );

        // Check orchestrator balances after liquidity addition
        uint256 orchestratorVerseBalance = verseToken.balanceOf(
            address(this)
        );

        uint256 orchestratorTbtcBalance = tbtcToken.balanceOf(
            address(this)
        );

        if (lpTokensReceived > 0) {
            lpToken.approve(
                address(simpleFarmB),
                lpTokensReceived
            );

            simpleFarmB.farmDeposit(
                lpTokensReceived
            );

            farmBReceipts = simpleFarmB.balanceOf(
                address(this)
            );

            // Transfer FarmB receipt tokens to user
            if (farmBReceipts > 0) {
                simpleFarmB.transfer(
                    msg.sender,
                    farmBReceipts
                );
            }
        }

        // Return any remaining tokens to user
        if (orchestratorVerseBalance > 0) {
            verseToken.transfer(
                msg.sender,
                orchestratorVerseBalance
            );
        }

        if (orchestratorTbtcBalance > 0) {
            tbtcToken.transfer(
                msg.sender,
                orchestratorTbtcBalance
            );
        }

        return farmBReceipts;
    }

    /**
     * @notice Calculate expected LP tokens for given amounts using Balancer V3 Router query
     * @param _verseAmount Amount of VERSE tokens
     * @param _tbtcAmount Amount of tBTC tokens
     * @return expectedLpTokens Expected number of LP tokens to receive
     */
    function calculateExpectedLpTokens(
        uint256 _verseAmount,
        uint256 _tbtcAmount
    )
        public
        view
        returns (uint256 expectedLpTokens)
    {
        (
            uint256 tbtcBalance,
            uint256 verseBalance
        ) = getPoolBalances();

        uint256 lpTotalSupply = balancerPool.totalSupply();

        // Calculate LP tokens based on VERSE proportion (80% of pool)
        uint256 expectedLpTokensFromVerse = _verseAmount
            * lpTotalSupply
            / verseBalance;

        // Calculate LP tokens based on tBTC proportion (20% of pool)
        uint256 expectedLpTokensFromTbtc = _tbtcAmount
            * lpTotalSupply
            / tbtcBalance;

        // Use the smaller of the two to ensure we don't exceed either token's capacity
        expectedLpTokens = expectedLpTokensFromVerse < expectedLpTokensFromTbtc
            ? expectedLpTokensFromVerse
            : expectedLpTokensFromTbtc;

        return expectedLpTokens;
    }

    /**
     * @notice Get current pool balances
     */
    function getPoolBalances()
        public
        view
        returns (
            uint256 tbtcBalance,
            uint256 verseBalance
        )
    {
        bytes memory data = abi.encodeWithSignature(
            "getCurrentLiveBalances()"
        );

        (
            bool success,
            bytes memory result
        ) = address(balancerPool).staticcall(data);

        if (success && result.length >= 64) {
            uint256[] memory balances = abi.decode(
                result,
                (uint256[])
            );
            if (balances.length >= 2) {
                tbtcBalance = balances[0];
                verseBalance = balances[1];
            }
        }
    }
}
"
    },
    "contracts/IERC20.sol": {
      "content": "// SPDX-License-Identifier: -- BCOM --

pragma solidity =0.8.26;

interface IERC20 {

    /**
     * @dev Interface fo transfer function
     */
    function transfer(
        address _recipient,
        uint256 _amount
    )
        external
        returns (bool);

    /**
     * @dev Interface for transferFrom function
     */
    function transferFrom(
        address _sender,
        address _recipient,
        uint256 _amount
    )
        external
        returns (bool);

    /**
     * @dev Interface for approve function
     */
    function approve(
        address _spender,
        uint256 _amount
    )
        external
        returns (bool);

    function balanceOf(
        address _account
    )
        external
        view
        returns (uint256);

    function allowance(
        address _owner,
        address _spender
    )
        external
        view
        returns (uint256);

    function mint(
        address _user,
        uint256 _amount
    )
        external;
}
"
    },
    "contracts/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: -- BCOM --

pragma solidity =0.8.26;

import "./IERC20.sol";

error SafeERC20FailedOperation(
    address token
);

contract SafeERC20 {

    /**
     * @dev Allows to execute transfer for a token
     */
    function safeTransfer(
        IERC20 _token,
        address _to,
        uint256 _value
    )
        internal
    {
        _callOptionalReturn(
            _token,
            abi.encodeWithSelector(
                _token.transfer.selector,
                _to,
                _value
            )
        );
    }

    /**
     * @dev Allows to execute transferFrom for a token
     */
    function safeTransferFrom(
        IERC20 _token,
        address _from,
        address _to,
        uint256 _value
    )
        internal
    {
        _callOptionalReturn(
            _token,
            abi.encodeWithSelector(
                _token.transferFrom.selector,
                _from,
                _to,
                _value
            )
        );
    }

    /**
     * @dev Allows to execute approve for a token
     */
    function safeApprove(
        IERC20 _token,
        address _spender,
        uint256 _value
    )
        internal
    {
        _callOptionalReturn(
            _token,
            abi.encodeWithSelector(
                _token.approve.selector,
                _spender,
                _value
            )
        );
    }

    function _callOptionalReturn(
        IERC20 _token,
        bytes memory _data
    )
        private
    {
        uint256 returnSize;
        uint256 returnValue;

        assembly ("memory-safe") {

            let success := call(
                gas(),
                _token,
                0,
                add(_data, 0x20),
                mload(_data),
                0,
                0x20
            )

            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(
                    ptr,
                    0,
                    returndatasize()
                )
                revert(
                    ptr,
                    returndatasize()
                )
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0
            ? address(_token).code.length == 0
            : returnValue != 1
        ) {
            revert SafeERC20FailedOperation(
                address(_token)
            );
        }
    }
}
"
    },
    "contracts/IBalancerV3Router.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity =0.8.26;

import "./IERC20.sol";

// Balancer V3 Router Interface
// Based on the actual V3 Router deployed at 0xAE563E3f8219521950555F5962419C8919758Ea2
interface IBalancerV3Router {

    // Swap function for single token exact in
    function swapSingleTokenExactIn(
        address pool,
        IERC20 tokenIn,
        IERC20 tokenOut,
        uint256 exactAmountIn,
        uint256 minAmountOut,
        uint256 deadline,
        bool wethIsEth,
        bytes calldata userData
    ) external payable returns (uint256 amountOut);

    // Add liquidity unbalanced (for adding liquidity with custom amounts)
    function addLiquidityUnbalanced(
        address pool,
        uint256[] memory exactAmountsIn,
        uint256 minBptAmountOut,
        bool wethIsEth,
        bytes calldata userData
    ) external payable returns (uint256 bptAmountOut);

    // Add liquidity proportional
    function addLiquidityProportional(
        address pool,
        uint256[] memory maxAmountsIn,
        uint256 exactBptAmountOut,
        bool wethIsEth,
        bytes calldata userData
    ) external payable returns (uint256[] memory amountsIn);

    // Add liquidity single token exact out
    function addLiquiditySingleTokenExactOut(
        address pool,
        IERC20 tokenIn,
        uint256 maxAmountIn,
        uint256 exactBptAmountOut,
        bool wethIsEth,
        bytes calldata userData
    ) external payable returns (uint256 amountIn);
}
"
    },
    "contracts/IPermit2.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity =0.8.26;

interface IPermit2 {
    struct TokenPermissions {
        address token;
        uint256 amount;
    }
    
    struct PermitTransferFrom {
        TokenPermissions permitted;
        uint256 nonce;
        uint256 deadline;
    }
    
    struct SignatureTransferDetails {
        address to;
        uint256 requestedAmount;
    }
    
    function approve(
        address token,
        address spender,
        uint160 amount,
        uint48 expiration
    ) external;
    
    function transferFrom(
        address from,
        address to,
        uint160 amount,
        address token
    ) external;
}
"
    },
    "contracts/ISimpleFarm.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "./IERC20.sol";

/**
 * @title ISimpleFarm
 * @notice Interface for SimpleFarm contract
 */
interface ISimpleFarm {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function farmDeposit(uint256 amount) external;
    function farmWithdraw(uint256 amount) external;
    function initialize(
        address _stakeToken,
        address _rewardToken,
        uint256 _defaultDuration,
        address _owner,
        address _manager,
        string calldata _name,
        string calldata _symbol
    ) external;
    function setRewardRate(uint256 newRate) external;
    function rewardToken() external view returns (IERC20);
    function rewardDuration() external view returns (uint256);
}
"
    },
    "contracts/IBalancerV3Pool.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

/**
 * @title IBalancerV3Pool
 * @notice Interface for Balancer V3 Pool contract
 */
interface IBalancerV3Pool {
    function getTokens() external view returns (address[] memory);
    function balanceOf(address account) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function getNormalizedWeights() external view returns (uint256[] memory);
}
"
    }
  },
  "settings": {
    "remappings": [
      "@chainlink/=node_modules/@chainlink/",
      "@ensdomains/=node_modules/@ensdomains/",
      "@eth-optimism/=node_modules/@eth-optimism/",
      "@openzeppelin/=node_modules/@openzeppelin/",
      "ds-test/=lib/forge-std/lib/ds-test/src/",
      "eth-gas-reporter/=node_modules/eth-gas-reporter/",
      "forge-std/=lib/forge-std/src/",
      "hardhat/=node_modules/hardhat/",
      "truffle/=node_modules/truffle/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 9999999
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "cancun",
    "viaIR": false
  }
}}

Tags:
ERC20, DeFi, Mintable, Swap, Liquidity, Factory, Oracle|addr:0x1cdedb1e8e5701dad6f3a08dea28bf1657d8b3d5|verified:true|block:23436572|tx:0x6a2c00176a0197d514b0511e1d4baad0baebba3ad990deca61701c2d091cb435|first_check:1758789386

Submitted on: 2025-09-25 10:36:26

Comments

Log in to comment.

No comments yet.