RobintownLaunchpad
0x7a9fd5255570f47c11261faa639de4e7083b2e65
Verification
Verified
v0.8.20+commit.a1b79de6
Type
Contract
13,079 bytes
ABI entries
37
20 read · 9 write
License
none
Contract information
- Address
- 0x7a9fd5255570f47c11261faa639de4e7083b2e65
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.20+commit.a1b79de6
- Optimization
- Enabled
- Creator
- 0x86E1DCcc11…B68F972c77
- Creation tx
- 0xba704315fc…8ecf68b9df
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (20)
BPS() → uint256
LP_SUPPLY() → uint256
TOTAL_SUPPLY() → uint256
VIRTUAL_TOKEN_SEED() → uint256
allTokens(uint256) → address
allTradingPaused() → bool
buysPaused() → bool
creationPaused() → bool
creatorFees(address) → uint256
creatorOf(address) → address
curves(address) → uint128, uint128, uint128, uint128, address, bool, bool, uint16, bool
distributor() → address
migrator() → address
owner() → address
progressBps(address) → uint256
protocolFees() → uint256
quoteBuy(address, uint256) → uint256, uint256
tokenCount() → uint256
tradeFeeBps() → uint16
virtualEthSeed() → uint128
Events (7)
GraduatedMigratedOwnershipTransferredPauseStateSetTokenCreatedTokenTradingPauseSetTrade
ABI
[
{
"inputs": [
{
"internalType": "uint128",
"name": "virtualEthSeed_",
"type": "uint128"
},
{
"internalType": "uint16",
"name": "tradeFeeBps_",
"type": "uint16"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "raisedEth",
"type": "uint256"
}
],
"name": "Graduated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethLiquidity",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokenLiquidity",
"type": "uint256"
}
],
"name": "Migrated",
"type": "event"
},
{
"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": "bool",
"name": "creationPaused",
"type": "bool"
},
{
"indexed": false,
"internalType": "bool",
"name": "buysPaused",
"type": "bool"
},
{
"indexed": false,
"internalType": "bool",
"name": "allTradingPaused",
"type": "bool"
}
],
"name": "PauseStateSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "string",
"name": "name",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"indexed": false,
"internalType": "uint16",
"name": "keyAllocationBps",
"type": "uint16"
},
{
"indexed": false,
"internalType": "uint48",
"name": "snapshotBlock",
"type": "uint48"
},
{
"indexed": false,
"internalType": "uint256",
"name": "curveSupply",
"type": "uint256"
}
],
"name": "TokenCreated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "paused",
"type": "bool"
}
],
"name": "TokenTradingPauseSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "trader",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "isBuy",
"type": "bool"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokenAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"name": "Trade",
"type": "event"
},
{
"inputs": [],
"name": "BPS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "LP_SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TOTAL_SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "VIRTUAL_TOKEN_SEED",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "allTokens",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "allTradingPaused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "minTokensOut",
"type": "uint256"
}
],
"name": "buy",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "buysPaused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "uint16",
"name": "keyAllocationBps",
"type": "uint16"
},
{
"internalType": "uint256",
"name": "minTokensOut",
"type": "uint256"
}
],
"name": "createToken",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "creationPaused",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "creatorFees",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "creatorOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"name": "curves",
"outputs": [
{
"internalType": "uint128",
"name": "virtualEth",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "virtualTokens",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "realEth",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "realTokens",
"type": "uint128"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "bool",
"name": "graduated",
"type": "bool"
},
{
"internalType": "bool",
"name": "migrated",
"type": "bool"
},
{
"internalType": "uint16",
"name": "keyAllocationBps",
"type": "uint16"
},
{
"internalType": "bool",
"name": "tradingPaused",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "distributor",
"outputs": [
{
"internalType": "contract RobintownKeyDistributor",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "migrator",
"outputs": [
{
"internalType": "contract RobintownMigrator",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "progressBps",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "protocolFees",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "ethIn",
"type": "uint256"
}
],
"name": "quoteBuy",
"outputs": [
{
"internalType": "uint256",
"name": "tokensOut",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "fee",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "minEthOut",
"type": "uint256"
}
],
"name": "sell",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "value",
"type": "address"
}
],
"name": "setDistributor",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "value",
"type": "address"
}
],
"name": "setMigrator",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "bool",
"name": "creation",
"type": "bool"
},
{
"internalType": "bool",
"name": "buys",
"type": "bool"
},
{
"internalType": "bool",
"name": "allTrading",
"type": "bool"
}
],
"name": "setPauseState",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "bool",
"name": "paused",
"type": "bool"
}
],
"name": "setTokenTradingPaused",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "tokenCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tradeFeeBps",
"outputs": [
{
"internalType": "uint16",
"name": "",
"type": "uint16"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "virtualEthSeed",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {RobintownToken} from "./RobintownToken.sol";
import {RobintownMigrator} from "./RobintownMigrator.sol";
import {RobintownKeyDistributor} from "./RobintownKeyDistributor.sol";
/// @notice Robintown fair-launch virtual-reserve bonding curve.
contract RobintownLaunchpad is Ownable, ReentrancyGuard {
uint256 public constant TOTAL_SUPPLY = 1_000_000e18;
uint256 public constant LP_SUPPLY = 200_000e18;
uint256 public constant VIRTUAL_TOKEN_SEED = 1_145_000e18;
uint256 public constant BPS = 10_000;
struct Curve {
uint128 virtualEth;
uint128 virtualTokens;
uint128 realEth;
uint128 realTokens;
address creator;
bool graduated;
bool migrated;
uint16 keyAllocationBps;
bool tradingPaused;
}
uint128 public immutable virtualEthSeed;
uint16 public immutable tradeFeeBps;
RobintownMigrator public migrator;
RobintownKeyDistributor public distributor;
bool public creationPaused;
bool public buysPaused;
bool public allTradingPaused;
mapping(address => Curve) public curves;
mapping(address => uint256) public creatorFees;
uint256 public protocolFees;
address[] public allTokens;
event TokenCreated(address indexed token, address indexed creator, string name, string symbol, uint16 keyAllocationBps, uint48 snapshotBlock, uint256 curveSupply);
event Trade(address indexed token, address indexed trader, bool isBuy, uint256 ethAmount, uint256 tokenAmount, uint256 fee);
event Graduated(address indexed token, uint256 raisedEth);
event Migrated(address indexed token, address indexed pool, uint256 ethLiquidity, uint256 tokenLiquidity);
event PauseStateSet(bool creationPaused, bool buysPaused, bool allTradingPaused);
event TokenTradingPauseSet(address indexed token, bool paused);
constructor(uint128 virtualEthSeed_, uint16 tradeFeeBps_) {
require(virtualEthSeed_ != 0 && tradeFeeBps_ <= 500, "BAD_CONFIG");
virtualEthSeed = virtualEthSeed_;
tradeFeeBps = tradeFeeBps_;
}
function setMigrator(address value) external onlyOwner {
require(address(migrator) == address(0) && value != address(0), "MIGRATOR_LOCKED");
migrator = RobintownMigrator(value);
}
function setDistributor(address value) external onlyOwner {
require(address(distributor) == address(0) && value != address(0), "DISTRIBUTOR_LOCKED");
distributor = RobintownKeyDistributor(value);
}
function setPauseState(bool creation, bool buys, bool allTrading) external onlyOwner {
creationPaused = creation; buysPaused = buys; allTradingPaused = allTrading;
emit PauseStateSet(creation, buys, allTrading);
}
function setTokenTradingPaused(address token, bool paused) external onlyOwner {
require(curves[token].creator != address(0), "UNKNOWN_TOKEN");
curves[token].tradingPaused = paused;
emit TokenTradingPauseSet(token, paused);
}
function createToken(string calldata name, string calldata symbol, uint16 keyAllocationBps, uint256 minTokensOut)
external payable nonReentrant returns (address token)
{
require(!creationPaused && keyAllocationBps >= 100 && keyAllocationBps <= 1000, "CREATION_UNAVAILABLE");
require(address(distributor) != address(0), "NO_DISTRIBUTOR");
uint256 keySupply = TOTAL_SUPPLY * keyAllocationBps / BPS;
uint256 curveSupply = TOTAL_SUPPLY - LP_SUPPLY - keySupply;
token = address(new RobintownToken(name, symbol, TOTAL_SUPPLY, address(this)));
uint256 scaledVirtualTokens = VIRTUAL_TOKEN_SEED * curveSupply / (TOTAL_SUPPLY - LP_SUPPLY);
curves[token] = Curve(virtualEthSeed, uint128(scaledVirtualTokens), 0, uint128(curveSupply), msg.sender, false, false, keyAllocationBps, false);
allTokens.push(token);
RobintownToken(token).approve(address(distributor), keySupply);
distributor.register(token, msg.sender, uint48(block.number), keyAllocationBps, keySupply);
emit TokenCreated(token, msg.sender, name, symbol, keyAllocationBps, uint48(block.number), curveSupply);
if (msg.value != 0) _buy(token, msg.sender, msg.value, minTokensOut);
else require(minTokensOut == 0, "SLIPPAGE");
}
function buy(address token, uint256 minTokensOut) external payable nonReentrant {
require(msg.value != 0, "ZERO_AMOUNT");
require(!buysPaused && !allTradingPaused && !curves[token].tradingPaused, "TRADING_PAUSED");
_buy(token, msg.sender, msg.value, minTokensOut);
}
function sell(address token, uint256 amount, uint256 minEthOut) external nonReentrant {
Curve storage c = curves[token];
require(!allTradingPaused && !c.tradingPaused, "TRADING_PAUSED");
require(c.creator != address(0) && !c.graduated && amount != 0, "NOT_LIVE");
uint256 ethOut = uint256(c.virtualEth) - Math.ceilDiv(uint256(c.virtualEth) * c.virtualTokens, uint256(c.virtualTokens) + amount);
uint256 fee = ethOut * tradeFeeBps / BPS;
uint256 payout = ethOut - fee;
require(payout >= minEthOut && payout != 0, "SLIPPAGE");
c.virtualEth -= uint128(ethOut);
c.virtualTokens += uint128(amount);
c.realEth -= uint128(ethOut);
c.realTokens += uint128(amount);
_accrueFee(token, fee);
require(RobintownToken(token).transferFrom(msg.sender, address(this), amount), "TRANSFER_FAILED");
(bool ok,) = msg.sender.call{value: payout}("");
require(ok, "ETH_TRANSFER_FAILED");
emit Trade(token, msg.sender, false, payout, amount, fee);
}
function _buy(address token, address recipient, uint256 ethIn, uint256 minTokensOut) internal {
Curve storage c = curves[token];
require(!buysPaused && !allTradingPaused && !c.tradingPaused, "TRADING_PAUSED");
require(c.creator != address(0) && !c.graduated, "NOT_LIVE");
uint256 fee = ethIn * tradeFeeBps / BPS;
uint256 curveEth = ethIn - fee;
uint256 tokensOut = uint256(c.virtualTokens) - uint256(c.virtualEth) * c.virtualTokens / (uint256(c.virtualEth) + curveEth);
uint256 refund;
if (tokensOut >= c.realTokens) {
tokensOut = c.realTokens;
uint256 exactEth = Math.ceilDiv(uint256(c.virtualEth) * c.virtualTokens, uint256(c.virtualTokens) - tokensOut) - c.virtualEth;
uint256 gross = Math.ceilDiv(exactEth * BPS, BPS - tradeFeeBps);
if (gross > ethIn) gross = ethIn;
curveEth = exactEth;
fee = gross - exactEth;
refund = ethIn - gross;
}
require(tokensOut >= minTokensOut && tokensOut != 0, "SLIPPAGE");
c.virtualEth += uint128(curveEth);
c.virtualTokens -= uint128(tokensOut);
c.realEth += uint128(curveEth);
c.realTokens -= uint128(tokensOut);
_accrueFee(token, fee);
require(RobintownToken(token).transfer(recipient, tokensOut), "TRANSFER_FAILED");
emit Trade(token, recipient, true, curveEth + fee, tokensOut, fee);
if (c.realTokens == 0) {
require(address(migrator) != address(0), "NO_MIGRATOR");
c.graduated = true;
c.migrated = true;
uint256 liquidityEth = c.realEth;
c.realEth = 0;
RobintownToken(token).approve(address(migrator), LP_SUPPLY);
address pool = migrator.migrate{value: liquidityEth}(token, LP_SUPPLY);
emit Graduated(token, liquidityEth);
emit Migrated(token, pool, liquidityEth, LP_SUPPLY);
}
if (refund != 0) {
(bool ok,) = recipient.call{value: refund}("");
require(ok, "REFUND_FAILED");
}
}
function _accrueFee(address token, uint256 fee) internal {
uint256 creatorCut = fee * 8_000 / BPS;
creatorFees[token] += creatorCut;
protocolFees += fee - creatorCut;
}
function quoteBuy(address token, uint256 ethIn) external view returns (uint256 tokensOut, uint256 fee) {
Curve memory c = curves[token];
fee = ethIn * tradeFeeBps / BPS;
tokensOut = uint256(c.virtualTokens) - uint256(c.virtualEth) * c.virtualTokens / (uint256(c.virtualEth) + ethIn - fee);
if (tokensOut > c.realTokens) tokensOut = c.realTokens;
}
function progressBps(address token) external view returns (uint256) {
Curve memory c = curves[token];
uint256 initial = TOTAL_SUPPLY - LP_SUPPLY - TOTAL_SUPPLY * c.keyAllocationBps / BPS;
return (initial - c.realTokens) * BPS / initial;
}
function tokenCount() external view returns (uint256) { return allTokens.length; }
function creatorOf(address token) external view returns (address) { return curves[token].creator; }
}
Chain explorer4023msChain node97ms