AtomicGMEMERelaunch
0xcff179cb6e8b0de7968daf4870b6424a63762c47
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
873 bytes
ABI entries
23
13 read · 0 write
License
none
Contract information
- Address
- 0xcff179cb6e8b0de7968daf4870b6424a63762c47
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0xD9255e7Bf5…efAab88950
- Creation tx
- 0x5d50cb1d75…555f4d6161
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (13)
CANONICAL_GME() → address
DEAD() → address
LP_FEE() → uint24
PERMIT2() → address
POSITION_MANAGER() → address
ROBINHOOD_CHAIN_ID() → uint256
TICK_SPACING() → int24
UNIVERSAL_ROUTER() → address
ethPositionTokenId() → uint256
feeCollector() → address
gmePositionTokenId() → uint256
launchRecipient() → address
token() → address
Events (1)
AtomicLaunch
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"internalType": "address",
"name": "collector",
"type": "address"
},
{
"internalType": "int24",
"name": "mainAbsoluteTick",
"type": "int24"
},
{
"internalType": "int24",
"name": "ethPreBuyTick",
"type": "int24"
},
{
"internalType": "uint128",
"name": "ethLiquidityBudget",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "initialBuyETH",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "minimumTokensBought",
"type": "uint128"
}
],
"stateMutability": "payable",
"type": "constructor"
},
{
"inputs": [],
"name": "InitialBuyFailed",
"type": "error"
},
{
"inputs": [],
"name": "InvalidFeeCollector",
"type": "error"
},
{
"inputs": [],
"name": "InvalidRecipient",
"type": "error"
},
{
"inputs": [
{
"internalType": "int24",
"name": "tick",
"type": "int24"
}
],
"name": "InvalidTick",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "supplied",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "required",
"type": "uint256"
}
],
"name": "InvalidValue",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "PositionNotLocked",
"type": "error"
},
{
"inputs": [],
"name": "TransferFailed",
"type": "error"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "actual",
"type": "uint256"
}
],
"name": "WrongChain",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "launchRecipient",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "feeCollector",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "ethPositionTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "gmePositionTokenId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "initialBuyETH",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokensBought",
"type": "uint256"
}
],
"name": "AtomicLaunch",
"type": "event"
},
{
"inputs": [],
"name": "CANONICAL_GME",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "DEAD",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "LP_FEE",
"outputs": [
{
"internalType": "uint24",
"name": "",
"type": "uint24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "PERMIT2",
"outputs": [
{
"internalType": "contract IAllowanceTransfer",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "POSITION_MANAGER",
"outputs": [
{
"internalType": "contract IPositionManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ROBINHOOD_CHAIN_ID",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TICK_SPACING",
"outputs": [
{
"internalType": "int24",
"name": "",
"type": "int24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "UNIVERSAL_ROUTER",
"outputs": [
{
"internalType": "contract IUniversalRouterGMEME",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ethPositionTokenId",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "feeCollector",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "gmePositionTokenId",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "launchRecipient",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "token",
"outputs": [
{
"internalType": "contract GameStopMemeStock",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {Pool} from "@uniswap/v4-core/src/libraries/Pool.sol";
import {IPositionManager} from "@uniswap/v4-periphery/src/interfaces/IPositionManager.sol";
import {Actions} from "@uniswap/v4-periphery/src/libraries/Actions.sol";
import {LiquidityAmounts} from "@uniswap/v4-periphery/src/libraries/LiquidityAmounts.sol";
import {PositionFeesForwarder} from "@uniswap/liquidity-launcher/src/periphery/PositionFeesForwarder.sol";
import {GameStopMemeStock} from "./GameStopMemeStock.sol";
interface IUniversalRouterGMEME {
function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable;
}
/// @notice One-shot GMEME relaunch. The constructor atomically deploys the token, creates and permanently
/// locks both pools, performs the initial market buy, and refunds unused ETH. It has no callable admin logic.
contract AtomicGMEMERelaunch {
uint256 public constant ROBINHOOD_CHAIN_ID = 4663;
uint24 public constant LP_FEE = 10_000;
int24 public constant TICK_SPACING = 200;
address public constant CANONICAL_GME = 0x1b0E319c6A659F002271B69dB8A7df2F911c153E;
IPositionManager public constant POSITION_MANAGER =
IPositionManager(0x58daec3116aae6D93017bAAea7749052E8a04fA7);
IAllowanceTransfer public constant PERMIT2 =
IAllowanceTransfer(0x000000000022D473030F116dDEE9F6B43aC78BA3);
IUniversalRouterGMEME public constant UNIVERSAL_ROUTER =
IUniversalRouterGMEME(0x8876789976dEcBfCbBbe364623C63652db8C0904);
address public constant DEAD = 0x000000000000000000000000000000000000dEaD;
GameStopMemeStock public immutable token;
address public immutable launchRecipient;
address public immutable feeCollector;
uint256 public immutable ethPositionTokenId;
uint256 public immutable gmePositionTokenId;
struct RouterExactInputSingleParams {
PoolKey poolKey;
bool zeroForOne;
uint128 amountIn;
uint128 amountOutMinimum;
uint256 minHopPriceX36;
bytes hookData;
}
event AtomicLaunch(
address indexed token,
address indexed launchRecipient,
address indexed feeCollector,
uint256 ethPositionTokenId,
uint256 gmePositionTokenId,
uint256 initialBuyETH,
uint256 tokensBought
);
error WrongChain(uint256 actual);
error InvalidRecipient();
error InvalidFeeCollector();
error InvalidValue(uint256 supplied, uint256 required);
error InvalidTick(int24 tick);
error PositionNotLocked(uint256 tokenId);
error InitialBuyFailed();
error TransferFailed();
constructor(
address recipient,
address collector,
int24 mainAbsoluteTick,
int24 ethPreBuyTick,
uint128 ethLiquidityBudget,
uint128 initialBuyETH,
uint128 minimumTokensBought
) payable {
if (block.chainid != ROBINHOOD_CHAIN_ID) revert WrongChain(block.chainid);
if (
recipient == address(0) || recipient == address(1) || recipient == address(2)
|| recipient.code.length != 0
) revert InvalidRecipient();
if (msg.value != uint256(ethLiquidityBudget) + uint256(initialBuyETH)) {
revert InvalidValue(msg.value, uint256(ethLiquidityBudget) + uint256(initialBuyETH));
}
if (mainAbsoluteTick <= 0 || mainAbsoluteTick % TICK_SPACING != 0) revert InvalidTick(mainAbsoluteTick);
if (ethPreBuyTick <= 0) revert InvalidTick(ethPreBuyTick);
PositionFeesForwarder forwarder = PositionFeesForwarder(payable(collector));
if (
collector.code.length == 0 || address(forwarder.positionManager()) != address(POSITION_MANAGER)
|| forwarder.operator() != DEAD || forwarder.timelockBlockNumber() != type(uint256).max
|| forwarder.feeRecipient() != recipient
) revert InvalidFeeCollector();
launchRecipient = recipient;
feeCollector = collector;
token = new GameStopMemeStock(address(this));
if (!IERC20(address(token)).approve(address(PERMIT2), type(uint256).max)) revert TransferFailed();
PERMIT2.approve(address(token), address(POSITION_MANAGER), type(uint160).max, type(uint48).max);
PoolKey memory ethKey = PoolKey(
Currency.wrap(address(0)), Currency.wrap(address(token)), LP_FEE, TICK_SPACING, IHooks(address(0))
);
uint160 ethSqrtPriceX96 = TickMath.getSqrtPriceAtTick(ethPreBuyTick);
if (POSITION_MANAGER.initializePool(ethKey, ethSqrtPriceX96) != ethPreBuyTick) {
revert InvalidTick(ethPreBuyTick);
}
uint128 ethLiquidity = LiquidityAmounts.getLiquidityForAmount0(
ethSqrtPriceX96,
TickMath.getSqrtPriceAtTick(TickMath.maxUsableTick(TICK_SPACING)),
ethLiquidityBudget
);
uint128 maxPerTick = Pool.tickSpacingToMaxLiquidityPerTick(TICK_SPACING);
if (ethLiquidity > maxPerTick) ethLiquidity = maxPerTick;
ethPositionTokenId = POSITION_MANAGER.nextTokenId();
_mintPosition(
ethKey,
TickMath.minUsableTick(TICK_SPACING),
TickMath.maxUsableTick(TICK_SPACING),
ethLiquidity,
ethLiquidityBudget,
type(uint128).max,
collector,
ethLiquidityBudget
);
bool tokenIsCurrency0 = address(token) < CANONICAL_GME;
int24 mainPoolTick = tokenIsCurrency0 ? -mainAbsoluteTick : mainAbsoluteTick;
PoolKey memory gmeKey = tokenIsCurrency0
? PoolKey(
Currency.wrap(address(token)),
Currency.wrap(CANONICAL_GME),
LP_FEE,
TICK_SPACING,
IHooks(address(0))
)
: PoolKey(
Currency.wrap(CANONICAL_GME),
Currency.wrap(address(token)),
LP_FEE,
TICK_SPACING,
IHooks(address(0))
);
uint160 mainSqrtPriceX96 = TickMath.getSqrtPriceAtTick(mainPoolTick);
if (POSITION_MANAGER.initializePool(gmeKey, mainSqrtPriceX96) != mainPoolTick) {
revert InvalidTick(mainPoolTick);
}
uint256 mainTokenAmount = token.balanceOf(address(this));
int24 mainLower = tokenIsCurrency0 ? mainPoolTick : TickMath.minUsableTick(TICK_SPACING);
int24 mainUpper = tokenIsCurrency0 ? TickMath.maxUsableTick(TICK_SPACING) : mainPoolTick;
uint128 mainLiquidity = tokenIsCurrency0
? LiquidityAmounts.getLiquidityForAmount0(
TickMath.getSqrtPriceAtTick(mainLower), TickMath.getSqrtPriceAtTick(mainUpper), mainTokenAmount
)
: LiquidityAmounts.getLiquidityForAmount1(
TickMath.getSqrtPriceAtTick(mainLower), TickMath.getSqrtPriceAtTick(mainUpper), mainTokenAmount
);
if (mainLiquidity > maxPerTick) mainLiquidity = maxPerTick;
gmePositionTokenId = POSITION_MANAGER.nextTokenId();
_mintPosition(
gmeKey,
mainLower,
mainUpper,
mainLiquidity,
tokenIsCurrency0 ? uint128(mainTokenAmount) : uint128(0),
tokenIsCurrency0 ? uint128(0) : uint128(mainTokenAmount),
collector,
0
);
uint256 roundingRemainder = token.balanceOf(address(this));
if (roundingRemainder != 0 && !token.transfer(DEAD, roundingRemainder)) revert TransferFailed();
_initialBuy(ethKey, initialBuyETH, minimumTokensBought);
uint256 bought = token.balanceOf(address(this));
if (bought < minimumTokensBought || !token.transfer(recipient, bought)) revert InitialBuyFailed();
if (IERC721(address(POSITION_MANAGER)).ownerOf(ethPositionTokenId) != collector) {
revert PositionNotLocked(ethPositionTokenId);
}
if (IERC721(address(POSITION_MANAGER)).ownerOf(gmePositionTokenId) != collector) {
revert PositionNotLocked(gmePositionTokenId);
}
emit AtomicLaunch(address(token), recipient, collector, ethPositionTokenId, gmePositionTokenId, initialBuyETH, bought);
}
function _mintPosition(
PoolKey memory key,
int24 tickLower,
int24 tickUpper,
uint128 liquidity,
uint128 amount0Max,
uint128 amount1Max,
address owner,
uint256 nativeValue
) private {
bytes memory actions = abi.encodePacked(uint8(Actions.MINT_POSITION), uint8(Actions.SETTLE_PAIR));
bytes[] memory params = new bytes[](2);
params[0] = abi.encode(key, tickLower, tickUpper, liquidity, amount0Max, amount1Max, owner, bytes(""));
params[1] = abi.encode(key.currency0, key.currency1);
POSITION_MANAGER.modifyLiquidities{value: nativeValue}(
abi.encode(actions, params), block.timestamp + 10 minutes
);
}
function _initialBuy(PoolKey memory ethKey, uint128 amountIn, uint128 minimumOut) private {
bytes memory actions = abi.encodePacked(
uint8(Actions.SWAP_EXACT_IN_SINGLE), uint8(Actions.SETTLE_ALL), uint8(Actions.TAKE_ALL)
);
bytes[] memory params = new bytes[](3);
params[0] = abi.encode(
RouterExactInputSingleParams({
poolKey: ethKey,
zeroForOne: true,
amountIn: amountIn,
amountOutMinimum: minimumOut,
minHopPriceX36: 0,
hookData: bytes("")
})
);
params[1] = abi.encode(Currency.wrap(address(0)), uint256(amountIn));
params[2] = abi.encode(Currency.wrap(address(token)), uint256(minimumOut));
bytes[] memory inputs = new bytes[](1);
inputs[0] = abi.encode(actions, params);
UNIVERSAL_ROUTER.execute{value: amountIn}(hex"10", inputs, block.timestamp + 10 minutes);
}
}
Chain explorer3435msChain node79ms