Balance
16.658721 LIMO
- Created by tx
- 0xc3f9d60c…373e54d2
Verified contractVerified
- Contract name
- SqueezeFactory
- Verified
- Fully verified · 2026-07-03 16:23:07 UTC
- Compiler
- 0.8.24+commit.e11b9ed9.Emscripten.clang
- Optimization
- Yes (200 runs)
- EVM version
- shanghai
- License
- -
Source code
// ===== File: src/Squeeze.sol =====
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
// ─────────────────────────────────────────────────────────────────────────────
// SQUEEZE — a toy bonding-curve launchpad for the Limonata TESTNET (chainId 10777).
//
// SANDBOX ONLY. Every token created here is play-money: it trades against
// *testnet* LIMO, which has NO monetary value and NO path to value (no fiat
// on-ramp, no bridge, no mainnet listing). This exists to demo a pump.fun-style
// launch + AMM UX on Limonata. It is a game, not an investment.
// ─────────────────────────────────────────────────────────────────────────────
/// @notice Minimal standalone ERC-20. The full supply is minted to the curve
/// (the factory) at birth; users only ever obtain tokens by buying off
/// the curve. The factory is a trusted spender (it can pull a seller's
/// tokens with no approval) so selling is one popup-free transaction.
contract SqueezeToken {
string public name;
string public symbol;
uint8 public constant decimals = 18;
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
address public immutable curve; // the SqueezeFactory
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
constructor(string memory _name, string memory _symbol, uint256 _supply, address _curve) {
name = _name;
symbol = _symbol;
curve = _curve;
totalSupply = _supply;
balanceOf[_curve] = _supply;
emit Transfer(address(0), _curve, _supply);
}
function transfer(address to, uint256 v) external returns (bool) {
// Donating tokens straight to the curve would corrupt its reserve accounting,
// so block it; the curve only ever receives tokens via the sell() pull path.
require(to != curve, "curve");
_move(msg.sender, to, v);
return true;
}
function approve(address sp, uint256 v) external returns (bool) {
allowance[msg.sender][sp] = v;
emit Approval(msg.sender, sp, v);
return true;
}
function transferFrom(address from, address to, uint256 v) external returns (bool) {
// The curve is trusted: it can only ever pull `from == msg.sender of sell()`,
// so no approval is needed for the popup-free sell path.
if (msg.sender != curve) {
uint256 a = allowance[from][msg.sender];
if (a != type(uint256).max) {
require(a >= v, "allowance");
allowance[from][msg.sender] = a - v;
}
}
_move(from, to, v);
return true;
}
function _move(address from, address to, uint256 v) internal {
require(to != address(0), "zero");
require(balanceOf[from] >= v, "balance");
unchecked {
balanceOf[from] -= v;
balanceOf[to] += v;
}
emit Transfer(from, to, v);
}
}
/// @notice The launchpad + AMM. One contract holds every token's native LIMO
/// reserve and runs a constant-product curve with virtual reserves
/// (the pump.fun model): price starts low, rises as supply is bought.
contract SqueezeFactory {
uint256 public constant SUPPLY = 1_000_000_000 ether; // 1B tokens per launch
uint256 public constant VIRT_LIMO = 30 ether; // virtual native reserve (curve depth / price anchor)
uint256 public constant K = VIRT_LIMO * SUPPLY; // constant product (same for every pool)
uint256 public constant GRAD_LIMO = 85 ether; // graduation milestone (pump.fun-style "bonded" target)
uint256 public constant FEE_BPS = 100; // 1% trade fee, taken on each buy and sell
uint256 public constant CREATOR_FEE_BPS = 50; // of FEE_BPS: half to the token's creator, half to treasury
uint256 public constant DEV_BUY_CAP_BPS = 2000; // creator's launch buy may take at most 20% of supply (anti-snipe)
address public immutable treasury; // collects the protocol half of every fee
struct Pool {
bool exists;
bool graduated; // crossed GRAD_LIMO (milestone only — trading continues)
address creator;
uint256 realLimo; // native LIMO actually held for this token (post-fee)
uint256 createdAt;
}
mapping(address => Pool) public pools;
mapping(address => uint256) public pendingFees; // pull-pattern fee accrual (creator + treasury)
address[] public allTokens;
event Launched(address indexed token, address indexed creator, string name, string symbol, uint256 supply, uint256 createdAt);
event Trade(address indexed token, address indexed trader, bool isBuy, uint256 limoAmount, uint256 tokenAmount, uint256 priceX1e18, uint256 ts);
event Graduated(address indexed token, uint256 realLimo, uint256 ts);
event FeesClaimed(address indexed who, uint256 amount);
constructor() {
treasury = msg.sender;
}
function tokenCount() external view returns (uint256) {
return allTokens.length;
}
/// @notice List a page of launched tokens, newest first.
function tokensPage(uint256 offset, uint256 limit) external view returns (address[] memory out) {
uint256 n = allTokens.length;
if (offset >= n) return new address[](0);
uint256 end = offset + limit;
if (end > n) end = n;
out = new address[](end - offset);
for (uint256 i = 0; i < out.length; i++) {
out[i] = allTokens[n - 1 - offset - i]; // newest first
}
}
/// @notice Create a new token + curve. Optional msg.value does an initial buy.
/// @dev The initial buy carries no slippage/deadline guard (the token is born in
/// this same tx, so there is no pool state to front-run) but IS capped to
/// DEV_BUY_CAP_BPS of supply so a creator can't snipe their own launch.
function create(string calldata name_, string calldata symbol_) external payable returns (address token) {
SqueezeToken t = new SqueezeToken(name_, symbol_, SUPPLY, address(this));
token = address(t);
pools[token] = Pool({ exists: true, graduated: false, creator: msg.sender, realLimo: 0, createdAt: block.timestamp });
allTokens.push(token);
emit Launched(token, msg.sender, name_, symbol_, SUPPLY, block.timestamp);
if (msg.value > 0) _buy(token, msg.sender, 0, true);
}
/// @notice Buy off the curve with native LIMO.
/// @param minTokensOut Revert if fewer than this many tokens would be received
/// (mainnet-style on-chain slippage protection — enforced at mining time,
/// not just in the client, so it holds even if other trades land first).
/// @param deadline Revert if mined after this unix timestamp (staleness guard).
function buy(address token, uint256 minTokensOut, uint256 deadline) external payable {
require(block.timestamp <= deadline, "expired");
_buy(token, msg.sender, minTokensOut, false);
}
function _buy(address token, address to, uint256 minTokensOut, bool isCreate) internal {
Pool storage p = pools[token];
require(p.exists, "no pool");
require(msg.value > 0, "no value");
uint256 fee = msg.value * FEE_BPS / 10000;
uint256 inAmt = msg.value - fee;
uint256 resLimo = VIRT_LIMO + p.realLimo;
uint256 resTok = SqueezeToken(token).balanceOf(address(this));
// Round the new token reserve UP so the buyer's `out` is rounded DOWN — dust
// accrues to the pool, never the trader (the Uniswap-safe direction).
uint256 denom = resLimo + inAmt;
uint256 newResTok = (K + denom - 1) / denom;
uint256 out = resTok - newResTok;
require(out > 0, "dust"); // never take LIMO and hand back zero tokens
if (isCreate) require(out <= SUPPLY * DEV_BUY_CAP_BPS / 10000, "dev cap");
require(out >= minTokensOut, "slippage");
p.realLimo += inAmt;
_accrue(p.creator, fee);
SqueezeToken(token).transfer(to, out);
emit Trade(token, to, true, msg.value, out, _price(token), block.timestamp);
if (!p.graduated && p.realLimo >= GRAD_LIMO) {
p.graduated = true;
emit Graduated(token, p.realLimo, block.timestamp);
}
}
/// @notice Sell `amount` tokens back to the curve for native LIMO. No approval needed.
/// @param minLimoOut Revert if less than this much LIMO would be received (on-chain slippage guard, fee-inclusive).
/// @param deadline Revert if mined after this unix timestamp (staleness guard).
function sell(address token, uint256 amount, uint256 minLimoOut, uint256 deadline) external {
require(block.timestamp <= deadline, "expired");
Pool storage p = pools[token];
require(p.exists, "no pool");
require(amount > 0, "no amount");
SqueezeToken t = SqueezeToken(token);
require(t.transferFrom(msg.sender, address(this), amount), "pull");
uint256 resLimo = VIRT_LIMO + p.realLimo;
uint256 resTok = t.balanceOf(address(this)); // already includes pulled `amount`
// Round the new LIMO reserve UP so the seller's gross is rounded DOWN (pool-favoured).
uint256 newResLimo = (K + resTok - 1) / resTok;
uint256 gross = resLimo - newResLimo;
require(gross <= p.realLimo, "drain"); // never touch the virtual reserve
uint256 fee = gross * FEE_BPS / 10000;
uint256 netOut = gross - fee;
require(netOut >= minLimoOut, "slippage");
// checks-effects-interactions: shrink the pool + book the fee BEFORE paying out.
p.realLimo -= gross;
_accrue(p.creator, fee);
(bool ok, ) = payable(msg.sender).call{ value: netOut }("");
require(ok, "send");
emit Trade(token, msg.sender, false, netOut, amount, _price(token), block.timestamp);
}
/// @dev Split a collected fee between the token's creator and the protocol treasury,
/// accrued for pull-payment (no external call on the hot path).
function _accrue(address creator, uint256 fee) internal {
if (fee == 0) return;
uint256 creatorCut = fee * CREATOR_FEE_BPS / FEE_BPS;
pendingFees[creator] += creatorCut;
pendingFees[treasury] += fee - creatorCut;
}
/// @notice Withdraw accrued trade fees (creators and the treasury).
function claimFees() external {
uint256 amt = pendingFees[msg.sender];
require(amt > 0, "none");
pendingFees[msg.sender] = 0;
(bool ok, ) = payable(msg.sender).call{ value: amt }("");
require(ok, "send");
emit FeesClaimed(msg.sender, amt);
}
function _price(address token) internal view returns (uint256) {
uint256 resTok = SqueezeToken(token).balanceOf(address(this));
if (resTok == 0) return 0;
return (VIRT_LIMO + pools[token].realLimo) * 1e18 / resTok; // LIMO per token, 1e18-scaled
}
function price(address token) external view returns (uint256) {
return _price(token);
}
function quoteBuy(address token, uint256 limoIn) external view returns (uint256 tokensOut) {
Pool storage p = pools[token];
if (!p.exists) return 0;
uint256 inAmt = limoIn - (limoIn * FEE_BPS / 10000); // fee-inclusive, matches buy()
uint256 resLimo = VIRT_LIMO + p.realLimo;
uint256 resTok = SqueezeToken(token).balanceOf(address(this));
uint256 denom = resLimo + inAmt;
tokensOut = resTok - (K + denom - 1) / denom;
}
function quoteSell(address token, uint256 tokIn) external view returns (uint256 limoOut) {
Pool storage p = pools[token];
if (!p.exists) return 0;
uint256 resLimo = VIRT_LIMO + p.realLimo;
uint256 resTok = SqueezeToken(token).balanceOf(address(this));
uint256 denom = resTok + tokIn;
uint256 gross = resLimo - (K + denom - 1) / denom;
limoOut = gross - (gross * FEE_BPS / 10000); // fee-inclusive, matches sell()
}
/// @notice Everything the UI needs about a pool in one call.
function poolInfo(address token)
external
view
returns (
address creator,
uint256 realLimo,
uint256 reserveTok,
uint256 priceX1e18,
uint256 marketCapX1e18,
uint256 createdAt,
bool graduated,
uint256 gradLimo
)
{
Pool storage p = pools[token];
creator = p.creator;
realLimo = p.realLimo;
reserveTok = SqueezeToken(token).balanceOf(address(this));
priceX1e18 = _price(token);
marketCapX1e18 = priceX1e18 * SUPPLY / 1e18; // notional, in LIMO
createdAt = p.createdAt;
graduated = p.graduated;
gradLimo = GRAD_LIMO;
}
}
ABI
26[
{
"type": "constructor",
"inputs": [],
"stateMutability": "nonpayable"
},
{
"name": "FeesClaimed",
"type": "event",
"inputs": [
{
"name": "who",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "Graduated",
"type": "event",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "realLimo",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "ts",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "Launched",
"type": "event",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "creator",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "name",
"type": "string",
"indexed": false,
"internalType": "string"
},
{
"name": "symbol",
"type": "string",
"indexed": false,
"internalType": "string"
},
{
"name": "supply",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "createdAt",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "Trade",
"type": "event",
"inputs": [
{
"name": "token",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "trader",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "isBuy",
"type": "bool",
"indexed": false,
"internalType": "bool"
},
{
"name": "limoAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "tokenAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "priceX1e18",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "ts",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "CREATOR_FEE_BPS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "DEV_BUY_CAP_BPS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "FEE_BPS",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "GRAD_LIMO",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "K",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "SUPPLY",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "VIRT_LIMO",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "allTokens",
"type": "function",
"inputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "buy",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "minTokensOut",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "payable"
},
{
"name": "claimFees",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "create",
"type": "function",
"inputs": [
{
"name": "name_",
"type": "string",
"internalType": "string"
},
{
"name": "symbol_",
"type": "string",
"internalType": "string"
}
],
"outputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "payable"
},
{
"name": "pendingFees",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "poolInfo",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "creator",
"type": "address",
"internalType": "address"
},
{
"name": "realLimo",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "reserveTok",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "priceX1e18",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "marketCapX1e18",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "createdAt",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "graduated",
"type": "bool",
"internalType": "bool"
},
{
"name": "gradLimo",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "pools",
"type": "function",
"inputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "exists",
"type": "bool",
"internalType": "bool"
},
{
"name": "graduated",
"type": "bool",
"internalType": "bool"
},
{
"name": "creator",
"type": "address",
"internalType": "address"
},
{
"name": "realLimo",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "createdAt",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "price",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "quoteBuy",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "limoIn",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "tokensOut",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "quoteSell",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "tokIn",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "limoOut",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "sell",
"type": "function",
"inputs": [
{
"name": "token",
"type": "address",
"internalType": "address"
},
{
"name": "amount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "minLimoOut",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "deadline",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "tokenCount",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "tokensPage",
"type": "function",
"inputs": [
{
"name": "offset",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "limit",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "out",
"type": "address[]",
"internalType": "address[]"
}
],
"stateMutability": "view"
},
{
"name": "treasury",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
}
]