Files
openlaunch/contracts/script/dev/SeedLaunchpadLocal.s.sol
Kevin Codex 312489a7b4 Initial commit
openlaunch — launch a token. Free. Open source. On Base or Robinhood Chain.
Contracts (LaunchFactory / LaunchLocker / LaunchToken, Foundry), the site (Next.js),
brand assets. No platform fee, liquidity locked forever.
2026-09-07 11:28:24 +08:00

156 lines
6.7 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {Script, console} from "forge-std/Script.sol";
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
import {SwapParams} from "@uniswap/v4-core/src/types/PoolOperation.sol";
import {PoolSwapTest} from "@uniswap/v4-core/src/test/PoolSwapTest.sol";
import {IPositionManager} from "@uniswap/v4-periphery/src/interfaces/IPositionManager.sol";
import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol";
import {LaunchFactory} from "src/LaunchFactory.sol";
import {LaunchLocker} from "src/LaunchLocker.sol";
import {LaunchToken} from "src/LaunchToken.sol";
/// LOCAL DEV ONLY (anvil fork of Base). Deploys the factory, launches a few
/// tokens with different fee/beneficiary setups, and trades them through a
/// PoolSwapTest so the app has real events to index. Never run against mainnet.
contract SeedLaunchpadLocal is Script {
address constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
address constant USDG = 0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168; // Robinhood Chain stablecoin (6 dec)
function run() external {
address PM;
address POSM;
if (block.chainid == 8453) {
(PM, POSM) = (0x498581fF718922c3f8e6A244956aF099B2652b2b, 0x7C5f5A4bBd8fD63184577525326123B519429bDc);
} else if (block.chainid == 4663) {
(PM, POSM) = (0x8366a39CC670B4001A1121B8F6A443A643e40951, 0x58daec3116aae6D93017bAAea7749052E8a04fA7);
} else {
revert("base or robinhood fork only");
}
uint256 pk = vm.envUint("DEPLOYER_PRIVATE_KEY");
address me = vm.addr(pk);
vm.startBroadcast(pk);
LaunchFactory factory = new LaunchFactory(IPoolManager(PM), IPositionManager(POSM), IAllowanceTransfer(PERMIT2));
PoolSwapTest router = new PoolSwapTest(IPoolManager(PM));
// 1. fully free: 0% fee, no beneficiary
LaunchFactory.LaunchParams memory p;
p.name = "Clear Sky";
p.symbol = "SKY";
p.metadataURI = "";
p.startTick = 184_200;
p.lpFee = 0;
p.salt = keccak256("sky");
(address sky,) = factory.launch(p);
// 2. 1% fee, all fees burned (no beneficiary)
p.name = "Burnie";
p.symbol = "BURN";
p.lpFee = 10_000;
p.salt = keccak256("burn");
p.startTick = 190_000;
(address burn, uint256 burnId) = factory.launch(p);
// 3. 1% fee → launcher
LaunchLocker.Recipient[] memory r = new LaunchLocker.Recipient[](1);
r[0] = LaunchLocker.Recipient(me, 10_000);
p.name = "Builder Coin";
p.symbol = "BUILD";
p.recipients = r;
p.salt = keccak256("build");
p.startTick = 178_000;
(address build, uint256 buildId) = factory.launch(p);
// 4. 3% fee, 50/50 launcher + burn
LaunchLocker.Recipient[] memory r2 = new LaunchLocker.Recipient[](2);
r2[0] = LaunchLocker.Recipient(me, 5_000);
r2[1] = LaunchLocker.Recipient(0x000000000000000000000000000000000000dEaD, 5_000);
p.name = "Half Burn";
p.symbol = "HALF";
p.recipients = r2;
p.lpFee = 30_000;
p.salt = keccak256("half");
p.startTick = 184_200;
(address half,) = factory.launch(p);
if (block.chainid == 4663) {
// 5. USDG-quoted launch (Robinhood default): 1% fee → launcher
LaunchFactory.LaunchParams memory q;
q.name = "Dollar Dog";
q.symbol = "DDOG";
q.quote = USDG;
q.startTick = 0; // set below via findSalt-compatible tick: 1 USDG (1e6) = 1.0001^tick token-wei... use ~$10k fdv
q.lpFee = 10_000;
LaunchLocker.Recipient[] memory rq = new LaunchLocker.Recipient[](1);
rq[0] = LaunchLocker.Recipient(me, 10_000);
q.recipients = rq;
// 1B supply (1e27 wei) at $10,000 FDV → 1e5 tokens per USDG = 1e23 wei per 1e6 micro → 1e17 per unit → tick ≈ ln(1e17)/ln(1.0001) ≈ 391,400
q.startTick = 391_400;
(bytes32 salt,) = factory.findSalt(me, keccak256("ddog"), q.name, q.symbol, 0, "", USDG, 64);
q.salt = salt;
(address ddog,) = factory.launch(q);
console.log("DDOG", ddog);
// 6. AAPL-quoted launch (Robinhood Stock Token), 1% fee to launcher; 1B supply at ~100 AAPL FDV
LaunchFactory.LaunchParams memory a;
a.name = "Apple Fan";
a.symbol = "AFAN";
a.quote = 0xaF3D76f1834A1d425780943C99Ea8A608f8a93f9;
a.startTick = 161_200;
a.lpFee = 10_000;
a.recipients = rq;
(bytes32 asalt,) = factory.findSalt(me, keccak256("afan"), a.name, a.symbol, 0, "", a.quote, 64);
a.salt = asalt;
(address afan,) = factory.launch(a);
console.log("AFAN", afan);
}
// trades
_buy(router, factory, sky, 0.05 ether);
_buy(router, factory, burn, 0.2 ether);
_buy(router, factory, burn, 0.35 ether);
_buy(router, factory, build, 1 ether);
_buy(router, factory, build, 0.4 ether);
_sell(router, factory, build, LaunchToken(build).balanceOf(me) / 3);
_buy(router, factory, half, 0.1 ether);
factory.locker().collect(burnId);
factory.locker().collect(buildId);
vm.stopBroadcast();
console.log("FACTORY", address(factory));
console.log("LOCKER", address(factory.locker()));
console.log("ROUTER", address(router));
console.log("SKY", sky);
console.log("BURN", burn);
console.log("BUILD", build);
console.log("HALF", half);
}
function _buy(PoolSwapTest router, LaunchFactory f, address token, uint256 ethIn) internal {
router.swap{value: ethIn}(
f.poolKeyOf(token),
SwapParams({
zeroForOne: true, amountSpecified: -int256(ethIn), sqrtPriceLimitX96: TickMath.MIN_SQRT_PRICE + 1
}),
PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false}),
""
);
}
function _sell(PoolSwapTest router, LaunchFactory f, address token, uint256 amt) internal {
LaunchToken(token).approve(address(router), amt);
router.swap(
f.poolKeyOf(token),
SwapParams({
zeroForOne: false, amountSpecified: -int256(amt), sqrtPriceLimitX96: TickMath.MAX_SQRT_PRICE - 1
}),
PoolSwapTest.TestSettings({takeClaims: false, settleUsingBurn: false}),
""
);
}
}