ReferralRouter

0xc216662891de8eaf591cfc74e1b33abc1779eafb

Verification
Verified
v0.8.20+commit.a1b79de6
Type
Contract
4,611 bytes
ABI entries
19
5 read · 7 write
License
none

Contract information

Address
0xc216662891de8eaf591cfc74e1b33abc1779eafb
Chain
Robinhood Chain (4663)
Compiler
v0.8.20+commit.a1b79de6
Optimization
Enabled
Creation tx
0xcb2700bb94…bb9cd2cb6f

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (5)

PROTOCOL_REFERRAL_CODE()bytes32
ZERO_REFERRAL_CODE()bytes32
launchpad()address
owner()address
referralHandler()address

Events (2)

OwnershipTransferredReferralHandlerSet

ABI

[
  {
    "inputs": [
      {
        "internalType": "contract Launchpad",
        "name": "_launchpad",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      }
    ],
    "name": "OwnableInvalidOwner",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "OwnableUnauthorizedAccount",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReferralRouter__InvalidToken",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReferralRouter__ZeroAddress",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnershipTransferred",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "address",
        "name": "newReferralHandler",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "address",
        "name": "oldReferralHandler",
        "type": "address"
      }
    ],
    "name": "ReferralHandlerSet",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "PROTOCOL_REFERRAL_CODE",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "ZERO_REFERRAL_CODE",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "minAmountOut",
        "type": "uint256"
      },
      {
        "internalType": "bytes32",
        "name": "code",
        "type": "bytes32"
      }
    ],
    "name": "buyExactEth",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amountOut",
        "type": "uint256"
      },
      {
        "internalType": "bytes32",
        "name": "code",
        "type": "bytes32"
      }
    ],
    "name": "buyExactTokens",
    "outputs": [],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchpad",
    "outputs": [
      {
        "internalType": "contract Launchpad",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "referralHandler",
    "outputs": [
      {
        "internalType": "contract ReferralHandler",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "renounceOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amountOut",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "maxInput",
        "type": "uint256"
      },
      {
        "internalType": "bytes32",
        "name": "code",
        "type": "bytes32"
      }
    ],
    "name": "sellExactEth",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amountIn",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "minAmountOut",
        "type": "uint256"
      },
      {
        "internalType": "bytes32",
        "name": "code",
        "type": "bytes32"
      }
    ],
    "name": "sellExactTokens",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "contract ReferralHandler",
        "name": "_referralHandler",
        "type": "address"
      }
    ],
    "name": "setReferralHandler",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "transferOwnership",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

import { Gauge } from "./Gauge.sol";
import { Launchpad } from "./Launchpad.sol";
import { LaunchpadToken } from "./LaunchpadToken.sol";
import { ReferralHandler } from "./ReferralHandler.sol";


/**
 * --------------------------------------------------------------------------------
 *
 * @title   Referral Router
 * @notice  Atomically set referral and trade tokens
 * @author  BowTiedPickle
 *
 * --------------------------------------------------------------------------------
 */
contract ReferralRouter is Ownable {
    ////////////////////////////////////////////////////////////////////////////////
    // CONSTANTS AND IMMUTABLES
    ////////////////////////////////////////////////////////////////////////////////

    /// @dev The zero referral code is reserved for referral nonexistence
    bytes32 public constant ZERO_REFERRAL_CODE = bytes32(0);
    /// @dev The protocol referral code is reserved for protocol fees
    bytes32 public constant PROTOCOL_REFERRAL_CODE = ~bytes32(0);

    /// @notice Launchpad contract
    Launchpad public immutable launchpad;

    ////////////////////////////////////////////////////////////////////////////////
    // CONFIGURATION
    ////////////////////////////////////////////////////////////////////////////////

    /// @notice Referral handler contract
    ReferralHandler public referralHandler;

    ////////////////////////////////////////////////////////////////////////////////
    // CONSTRUCTOR
    ////////////////////////////////////////////////////////////////////////////////

    /**
     * @param   _launchpad  Launchpad contract
     */
    constructor(Launchpad _launchpad) Ownable(msg.sender) {
        if (address(_launchpad) == address(0)) revert ReferralRouter__ZeroAddress();
        launchpad = _launchpad;
    }

    ////////////////////////////////////////////////////////////////////////////////
    // TRADE TOKENS
    ////////////////////////////////////////////////////////////////////////////////

    /**
     * @notice  Buy an exact amount of tokens
     * @dev     Allowable slippage is defined by msg.value
     * @param   token       Token address
     * @param   amountOut   Amount of tokens to buy
     * @param   code        Referral code to set, bytes32(0) to leave unchanged
     */
    function buyExactTokens(address token, uint256 amountOut, bytes32 code) external payable {
        address gauge = launchpad.tokenToGauge(token);
        if (gauge == address(0)) revert ReferralRouter__InvalidToken();

        bytes32 existingReferral = referralHandler.getReferralCode(msg.sender);
        if (code != ZERO_REFERRAL_CODE && existingReferral == ZERO_REFERRAL_CODE) {
            referralHandler.setReferral(msg.sender, code);
        } else if (code == ZERO_REFERRAL_CODE && existingReferral == ZERO_REFERRAL_CODE) {
            referralHandler.setReferral(msg.sender, PROTOCOL_REFERRAL_CODE);
        }

        Gauge(gauge).buyExactTokens{ value: msg.value }(msg.sender, amountOut);
    }

    /**
     * @notice  Sell an exact amount of tokens
     * @param   token           Token address
     * @param   amountIn        Amount of tokens to sell
     * @param   minAmountOut    Minimum amount of ETH to receive
     * @param   code            Referral code to set, bytes32(0) to leave unchanged
     */
    function sellExactTokens(address token, uint256 amountIn, uint256 minAmountOut, bytes32 code) external {
        address gauge = launchpad.tokenToGauge(token);
        if (gauge == address(0)) revert ReferralRouter__InvalidToken();

        bytes32 existingReferral = referralHandler.getReferralCode(msg.sender);
        if (code != ZERO_REFERRAL_CODE && existingReferral == ZERO_REFERRAL_CODE) {
            referralHandler.setReferral(msg.sender, code);
        } else if (code == ZERO_REFERRAL_CODE && existingReferral == ZERO_REFERRAL_CODE) {
            referralHandler.setReferral(msg.sender, PROTOCOL_REFERRAL_CODE);
        }

        LaunchpadToken(token).transferFrom(msg.sender, address(this), amountIn);
        LaunchpadToken(token).approve(gauge, amountIn);
        Gauge(gauge).sellExactTokens(msg.sender, amountIn, minAmountOut);
    }

    /**
     * @notice  Buy the maximum amount of tokens for an exact ETH input
     * @param   token           Token address
     * @param   minAmountOut    Minimum amount of tokens to receive
     * @param   code            Referral code to set, bytes32(0) to leave unchanged
     */
    function buyExactEth(address token, uint256 minAmountOut, bytes32 code) external payable {
        address gauge = launchpad.tokenToGauge(token);
        if (gauge == address(0)) revert ReferralRouter__InvalidToken();

        bytes32 existingReferral = referralHandler.getReferralCode(msg.sender);
        if (code != ZERO_REFERRAL_CODE && existingReferral == ZERO_REFERRAL_CODE) {
            referralHandler.setReferral(msg.sender, code);
        } else if (code == ZERO_REFERRAL_CODE && existingReferral == ZERO_REFERRAL_CODE) {
            referralHandler.setReferral(msg.sender, PROTOCOL_REFERRAL_CODE);
        }

        Gauge(gauge).buyExactEth{ value: msg.value }(msg.sender, minAmountOut);
    }

    /**
     * @notice  Sell the minimum amount of tokens for an exact ETH output
     * @param   token       Token address
     * @param   amountOut   Amount of ETH to receive
     * @param   maxInput    Maximum amount of tokens to sell
     * @param   code        Referral code to set, bytes32(0) to leave unchanged
     */
    function sellExactEth(address token, uint256 amountOut, uint256 maxInput, bytes32 code) external {
        address gauge = launchpad.tokenToGauge(token);
        if (gauge == address(0)) revert ReferralRouter__InvalidToken();

        bytes32 existingReferral = referralHandler.getReferralCode(msg.sender);
        if (code != ZERO_REFERRAL_CODE && existingReferral == ZERO_REFERRAL_CODE) {
            referralHandler.setReferral(msg.sender, code);
        } else if (code == ZERO_REFERRAL_CODE && existingReferral == ZERO_REFERRAL_CODE) {
            referralHandler.setReferral(msg.sender, PROTOCOL_REFERRAL_CODE);
        }

        (uint256 amountIn, ) = Gauge(gauge).quoteSellExactEth(amountOut);
        LaunchpadToken(token).transferFrom(msg.sender, address(this), amountIn);
        LaunchpadToken(token).approve(gauge, amountIn);
        Gauge(gauge).sellExactEth(msg.sender, amountOut, maxInput);
    }

    ////////////////////////////////////////////////////////////////////////////////
    // ADMINISTRATION
    ////////////////////////////////////////////////////////////////////////////////

    /**
     * @notice  Set the referral handler
     * @param   _referralHandler    The new referral handler
     */
    function setReferralHandler(ReferralHandler _referralHandler) external onlyOwner {
        if (address(_referralHandler) == address(0)) revert ReferralRouter__ZeroAddress();

        emit ReferralHandlerSet(address(_referralHandler), address(referralHandler));

        referralHandler = _referralHandler;
    }

    ////////////////////////////////////////////////////////////////////////////////
    // ERRORS
    ////////////////////////////////////////////////////////////////////////////////

    error ReferralRouter__ZeroAddress();
    error ReferralRouter__InvalidToken();

    ////////////////////////////////////////////////////////////////////////////////
    // EVENTS
    ////////////////////////////////////////////////////////////////////////////////

    event ReferralHandlerSet(address newReferralHandler, address oldReferralHandler);
}
Chain explorer2587msChain node83ms