Robinhood MainnetChain ID: 4663
Contract detail

RobinPadRouter

RobinPadRouter is a verified Robinhood Chain smart contract at 0x94338247…d83a467a with 0 indexed transactions.

Address type
Smart contract
Transactions
0
History coverage
No indexed activity found
Emitted events
1
Verification
Verified
Compiler
v0.8.28+commit.7893614a
Verification match
full
Creation transaction
0x0f7044f7…d43bb64f
Created at block
#832956
Language
solidity
EVM version
cancun
License
none
Compiler optimization
Enabled · 1 runs
Verified contract

Contract source code

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./Interfaces.sol";

contract RobinPadRouter is Ownable, ReentrancyGuard {
    using SafeERC20 for IERC20;

    address public immutable weth;
    address public immutable swapRouter;
    address public immutable quoter;
    address public immutable factory;

    address public platformFeeRecipient;
    uint256 public feeBps = 50;
    uint24 public constant POOL_FEE = 10000;

    uint256 public constant MAX_FEE_BPS = 100;
    uint256 public constant BPS_DENOMINATOR = 10000;
    uint256 public constant PLATFORM_FEE_SHARE_BPS = 3000;

    event Buy(
        address indexed buyer,
        address indexed token,
        uint256 ethIn,
        uint256 tokensOut,
        uint256 fee,
        address indexed launchFeeRecipient,
        uint256 launchFee,
        uint256 platformFee
    );
    event Sell(
        address indexed seller,
        address indexed token,
        uint256 tokensIn,
        uint256 ethOut,
        uint256 fee,
        address indexed launchFeeRecipient,
        uint256 launchFee,
        uint256 platformFee
    );
    event PlatformFeeRecipientUpdated(address indexed oldRecipient, address indexed newRecipient);
    event FeeBpsUpdated(uint256 oldFeeBps, uint256 newFeeBps);

    constructor(
        address weth_,
        address swapRouter_,
        address quoter_,
        address factory_,
        address platformFeeRecipient_,
        address owner_
    ) Ownable(owner_) {
        require(weth_ != address(0), "Invalid WETH");
        require(swapRouter_ != address(0), "Invalid router");
        require(quoter_ != address(0), "Invalid quoter");
        require(factory_ != address(0), "Invalid factory");
        require(platformFeeRecipient_ != address(0), "Invalid fee recipient");

        weth = weth_;
        swapRouter = swapRouter_;
        quoter = quoter_;
        factory = factory_;
        platformFeeRecipient = platformFeeRecipient_;

        IERC20(weth_).approve(swapRouter_, type(uint256).max);
    }

    receive() external payable {}

    function robinBuy(
        address token,
        uint256 amountIn,
        uint256 minTokensOut
    ) external payable nonReentrant returns (uint256 tokensOut) {
        require(amountIn > 0, "Zero amount");
        require(token != address(0), "Invalid token");

        uint256 fee = (amountIn * feeBps) / BPS_DENOMINATOR;
        uint256 amountAfterFee = amountIn - fee;

        if (msg.value > 0) {
            require(msg.value >= amountIn, "Insufficient ETH");
            IWETH(weth).deposit{value: amountAfterFee}();

            if (fee > 0) {
                _transferEthFee(token, fee);
            }

            uint256 excess = msg.value - amountIn;
            if (excess > 0) {
                _sendEth(msg.sender, excess);
            }
        } else {
            IERC20(weth).safeTransferFrom(msg.sender, address(this), amountIn);
            if (fee > 0) {
                _transferWethFee(token, fee);
            }
        }

        tokensOut = ISwapRouter02(swapRouter).exactInputSingle(
            ISwapRouter02.ExactInputSingleParams({
                tokenIn: weth,
                tokenOut: token,
                fee: POOL_FEE,
                recipient: msg.sender,
                amountIn: amountAfterFee,
                amountOutMinimum: minTokensOut,
                sqrtPriceLimitX96: 0
            })
        );

        (address launchFeeRecipient, uint256 launchFee, uint256 platformFee) = _feeSplit(token, fee);
        emit Buy(msg.sender, token, amountIn, tokensOut, fee, launchFeeRecipient, launchFee, platformFee);
    }

    function robinSell(
        address token,
        uint256 tokenAmount,
        uint256 minEthOut
    ) external nonReentrant returns (uint256 ethOut) {
        require(tokenAmount > 0, "No tokens");
        require(token != address(0), "Invalid token");

        IERC20(token).safeTransferFrom(msg.sender, address(this), tokenAmount);

        if (IERC20(token).allowance(address(this), swapRouter) < tokenAmount) {
            IERC20(token).approve(swapRouter, type(uint256).max);
        }

        uint256 wethOut = ISwapRouter02(swapRouter).exactInputSingle(
            ISwapRouter02.ExactInputSingleParams({
                tokenIn: token,
                tokenOut: weth,
                fee: POOL_FEE,
                recipient: address(this),
                amountIn: tokenAmount,
                amountOutMinimum: 0,
                sqrtPriceLimitX96: 0
            })
        );

        uint256 ethBefore = address(this).balance;
        IWETH(weth).withdraw(wethOut);
        uint256 ethReceived = address(this).balance - ethBefore;

        uint256 fee = (ethReceived * feeBps) / BPS_DENOMINATOR;
        ethOut = ethReceived - fee;
        require(ethOut >= minEthOut, "Slippage exceeded");

        if (fee > 0) {
            _transferEthFee(token, fee);
        }

        _sendEth(msg.sender, ethOut);

        (address launchFeeRecipient, uint256 launchFee, uint256 platformFee) = _feeSplit(token, fee);
        emit Sell(msg.sender, token, tokenAmount, ethOut, fee, launchFeeRecipient, launchFee, platformFee);
    }

    function quoteBuy(address token, uint256 ethAmount) external returns (uint256 tokensOut, uint256 fee) {
        fee = (ethAmount * feeBps) / BPS_DENOMINATOR;
        uint256 amountAfterFee = ethAmount - fee;

        (tokensOut, , , ) = IQuoterV2(quoter).quoteExactInputSingle(
            IQuoterV2.QuoteExactInputSingleParams({
                tokenIn: weth,
                tokenOut: token,
                amountIn: amountAfterFee,
                fee: POOL_FEE,
                sqrtPriceLimitX96: 0
            })
        );
    }

    function quoteSell(address token, uint256 tokenAmount) external returns (uint256 ethOut, uint256 fee) {
        (uint256 wethOut, , , ) = IQuoterV2(quoter).quoteExactInputSingle(
            IQuoterV2.QuoteExactInputSingleParams({
                tokenIn: token,
                tokenOut: weth,
                amountIn: tokenAmount,
                fee: POOL_FEE,
                sqrtPriceLimitX96: 0
            })
        );

        fee = (wethOut * feeBps) / BPS_DENOMINATOR;
        ethOut = wethOut - fee;
    }

    function calculateMinOutput(uint256 expectedOut, uint256 slippageBps) external pure returns (uint256 minOut) {
        require(slippageBps <= 5000, "Slippage too high");
        minOut = (expectedOut * (BPS_DENOMINATOR - slippageBps)) / BPS_DENOMINATOR;
    }

    function setPlatformFeeRecipient(address platformFeeRecipient_) external onlyOwner {
        require(platformFeeRecipient_ != address(0), "Invalid address");
        emit PlatformFeeRecipientUpdated(platformFeeRecipient, platformFeeRecipient_);
        platformFeeRecipient = platformFeeRecipient_;
    }

    function setFeeBps(uint256 feeBps_) external onlyOwner {
        require(feeBps_ <= MAX_FEE_BPS, "Fee too high");
        emit FeeBpsUpdated(feeBps, feeBps_);
        feeBps = feeBps_;
    }

    function rescueTokens(address token, uint256 amount) external onlyOwner {
        IERC20(token).safeTransfer(owner(), amount);
    }

    function rescueETH() external onlyOwner {
        _sendEth(owner(), address(this).balance);
    }

    function _transferEthFee(address token, uint256 fee) internal {
        (address launchFeeRecipient, uint256 launchFee, uint256 platformFee) = _feeSplit(token, fee);
        if (launchFee > 0) {
            _sendEthOrWeth(launchFeeRecipient, launchFee);
        }
        if (platformFee > 0) {
            _sendEthOrWeth(platformFeeRecipient, platformFee);
        }
    }

    function _transferWethFee(address token, uint256 fee) internal {
        (address launchFeeRecipient, uint256 launchFee, uint256 platformFee) = _feeSplit(token, fee);
        if (launchFee > 0) {
            IERC20(weth).safeTransfer(launchFeeRecipient, launchFee);
        }
        if (platformFee > 0) {
            IERC20(weth).safeTransfer(platformFeeRecipient, platformFee);
        }
    }

    function _feeSplit(address token, uint256 fee)
        internal
        view
        returns (address launchFeeRecipient, uint256 launchFee, uint256 platformFee)
    {
        launchFeeRecipient = ILaunchFeeRecipientRegistry(factory).feeRecipientForToken(token);
        if (launchFeeRecipient == address(0)) {
            launchFeeRecipient = platformFeeRecipient;
        }
        launchFee = (fee * (BPS_DENOMINATOR - PLATFORM_FEE_SHARE_BPS)) / BPS_DENOMINATOR;
        platformFee = fee - launchFee;
    }

    function _sendEth(address recipient, uint256 amount) internal {
        (bool success, ) = recipient.call{value: amount}("");
        require(success, "ETH transfer failed");
    }

    function _sendEthOrWeth(address recipient, uint256 amount) internal {
        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            IWETH(weth).deposit{value: amount}();
            IERC20(weth).safeTransfer(recipient, amount);
        }
    }
}