SingleSidedLauncher
0xa3a71925be892c609ac4be4efe918dc9c35fc5e8
Verification
Verified
v0.8.28+commit.7893614a
Type
Contract
19,098 bytes
ABI entries
40
23 read · 6 write
License
none
Contract information
- Address
- 0xa3a71925be892c609ac4be4efe918dc9c35fc5e8
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.28+commit.7893614a
- Optimization
- Enabled
- Creator
- 0xCEaf36e4f7…cD3561770B
- Creation tx
- 0x075975a89c…75f7b29d9b
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (23)
LP_FEE() → uint24
MAX_TREASURY_BPS() → uint256
OPEN_SQRT_PRICE() → uint160
TICK_LOWER() → int24
TICK_UPPER() → int24
TOTAL_SUPPLY() → uint256
distributorOf(address) → address
dividendsOf(address, address) → uint256
launchFeeWei() → uint256
launches(address) → address, uint256, uint8, address, address, bool
owner() → address
poolOf(address) → address
positionManager() → address
priceUsd(address, uint256) → uint256
rwaTreasuryBps() → uint256
swapRouter() → address
tokenNonce() → uint256
treasury() → address
treasuryBps() → uint256
usdg() → address
usdgWethFee() → uint24
v3Factory() → address
weth() → address
Events (7)
CreatorFeePaidFeesHarvestedLaunchFeeSetLaunchedToDEXTokenBoughtTokenCreatedTreasuryBpsSet
ABI
[
{
"inputs": [
{
"internalType": "contract IWETH9",
"name": "_weth",
"type": "address"
},
{
"internalType": "contract IERC20",
"name": "_usdg",
"type": "address"
},
{
"internalType": "contract INonfungiblePositionManager",
"name": "_pm",
"type": "address"
},
{
"internalType": "contract ISwapRouter02",
"name": "_router",
"type": "address"
},
{
"internalType": "contract IV3Factory",
"name": "_factory",
"type": "address"
},
{
"internalType": "uint24",
"name": "_usdgWethFee",
"type": "uint24"
},
{
"internalType": "address",
"name": "_treasury",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "SafeERC20FailedOperation",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokenAmt",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "wethAmt",
"type": "uint256"
}
],
"name": "CreatorFeePaid",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "tokenFee",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "wethFee",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "dest",
"type": "address"
}
],
"name": "FeesHarvested",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "wei_",
"type": "uint256"
}
],
"name": "LaunchFeeSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "eth",
"type": "uint256"
}
],
"name": "LaunchedToDEX",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "ts",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "buyer",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "eth",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "fee",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "postPrice",
"type": "uint256"
}
],
"name": "TokenBought",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "ts",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "nonce",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "string",
"name": "name",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"indexed": false,
"internalType": "string",
"name": "meta",
"type": "string"
}
],
"name": "TokenCreated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "bps",
"type": "uint256"
}
],
"name": "TreasuryBpsSet",
"type": "event"
},
{
"inputs": [],
"name": "LP_FEE",
"outputs": [
{
"internalType": "uint24",
"name": "",
"type": "uint24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_TREASURY_BPS",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "OPEN_SQRT_PRICE",
"outputs": [
{
"internalType": "uint160",
"name": "",
"type": "uint160"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TICK_LOWER",
"outputs": [
{
"internalType": "int24",
"name": "",
"type": "int24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TICK_UPPER",
"outputs": [
{
"internalType": "int24",
"name": "",
"type": "int24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "TOTAL_SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "distributorOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "holder",
"type": "address"
}
],
"name": "dividendsOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "harvestFees",
"outputs": [
{
"internalType": "uint256",
"name": "tokenFee",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "wethFee",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "meta",
"type": "string"
},
{
"internalType": "address",
"name": "feeWallet",
"type": "address"
}
],
"name": "launch",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokensBought",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "launchFeeWei",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "string",
"name": "meta",
"type": "string"
}
],
"name": "launchRwa",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokensBought",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "launches",
"outputs": [
{
"internalType": "address",
"name": "pool",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "enum SingleSidedLauncher.Mode",
"name": "mode",
"type": "uint8"
},
{
"internalType": "address",
"name": "feeWallet",
"type": "address"
},
{
"internalType": "address",
"name": "distributor",
"type": "address"
},
{
"internalType": "bool",
"name": "exists",
"type": "bool"
}
],
"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": "poolOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "positionManager",
"outputs": [
{
"internalType": "contract INonfungiblePositionManager",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "ethUsdWad",
"type": "uint256"
}
],
"name": "priceUsd",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "rwaTreasuryBps",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "wei_",
"type": "uint256"
}
],
"name": "setLaunchFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "bps",
"type": "uint256"
}
],
"name": "setRwaTreasuryBps",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "bps",
"type": "uint256"
}
],
"name": "setTreasuryBps",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "swapRouter",
"outputs": [
{
"internalType": "contract ISwapRouter02",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "tokenNonce",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "treasury",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "treasuryBps",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "usdg",
"outputs": [
{
"internalType": "contract IERC20",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "usdgWethFee",
"outputs": [
{
"internalType": "uint24",
"name": "",
"type": "uint24"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "v3Factory",
"outputs": [
{
"internalType": "contract IV3Factory",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "weth",
"outputs": [
{
"internalType": "contract IWETH9",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {MemeToken} from "./MemeToken.sol";
import {DividendMemeToken} from "./DividendMemeToken.sol";
import {DividendDistributor} from "./DividendDistributor.sol";
import {IWETH9} from "./interfaces/IWETH9.sol";
import {
INonfungiblePositionManager,
IUniswapV3PoolMinimal,
ISwapRouter02
} from "./interfaces/IUniswapV3.sol";
interface IV3Factory {
function getPool(address a, address b, uint24 fee) external view returns (address);
}
/// REAL — single-sided liquidity launchpad (noxa-style, no bonding curve).
///
/// Every launch, in ONE tx: mint a fixed 1B supply, create a real Uniswap v3
/// token/WETH pool at the 1% tier, deposit the ENTIRE supply as single-sided
/// token-only liquidity from the opening price upward, and LOCK the position NFT
/// here forever (never decreaseLiquidity → principal locked, only fees harvest).
/// An optional atomic dev-buy makes the creator's first buy provably first.
///
/// The single-sided v3 position IS the "bonding curve". Three modes differ ONLY
/// in where the harvested 1% fees go:
/// NORMAL → 100% treasury
/// BAGS → creator wallet (minus a treasury cut)
/// RWA → USDG dividends streamed pro-rata to holders (fees → USDG →
/// DividendDistributor); stock reserves pluggable later.
contract SingleSidedLauncher is ReentrancyGuard {
using SafeERC20 for IERC20;
address private constant DEAD = 0x000000000000000000000000000000000000dEaD;
IWETH9 public immutable weth;
IERC20 public immutable usdg;
INonfungiblePositionManager public immutable positionManager;
ISwapRouter02 public immutable swapRouter;
IV3Factory public immutable v3Factory;
uint24 public immutable usdgWethFee; // WETH->USDG swap tier for RWA dividends
uint24 public constant LP_FEE = 10_000; // 1% tier
int24 public constant TICK_LOWER = -194_800; // ~$6,024 open FDV @ ETH $1,736
int24 public constant TICK_UPPER = 887_200; // full range up (tickSpacing 200)
uint160 public constant OPEN_SQRT_PRICE = 4667268838450426450913011; // sqrtRatioAtTick(-194800)
uint256 public constant TOTAL_SUPPLY = 1_000_000_000e18;
enum Mode { NORMAL, BAGS, RWA }
struct Launch {
address pool;
uint256 tokenId;
Mode mode;
address feeWallet; // BAGS creator
address distributor; // RWA dividends
bool exists;
}
mapping(address token => Launch) public launches;
uint256 public tokenNonce;
address public immutable treasury;
address public immutable owner;
uint256 public launchFeeWei = 0.0005 ether;
uint256 public treasuryBps = 2000; // treasury cut on BAGS harvest
uint256 public rwaTreasuryBps = 5000; // treasury cut on RWA harvest (default 50/50 holders/treasury)
uint256 public constant MAX_TREASURY_BPS = 5000;
event TokenCreated(
uint256 ts, address creator, uint256 nonce, address token, string name, string symbol, string meta
);
event LaunchedToDEX(address token, address pool, uint256 amount, uint256 eth);
event TokenBought(
uint256 ts, address token, address buyer, uint256 amount, uint256 eth, uint256 fee, uint256 postPrice
);
event CreatorFeePaid(address indexed token, address indexed recipient, uint256 tokenAmt, uint256 wethAmt);
event FeesHarvested(address indexed token, uint256 tokenFee, uint256 wethFee, address dest);
event LaunchFeeSet(uint256 wei_);
event TreasuryBpsSet(uint256 bps);
constructor(
IWETH9 _weth,
IERC20 _usdg,
INonfungiblePositionManager _pm,
ISwapRouter02 _router,
IV3Factory _factory,
uint24 _usdgWethFee,
address _treasury
) {
require(_treasury != address(0), "zero treasury");
weth = _weth;
usdg = _usdg;
positionManager = _pm;
swapRouter = _router;
v3Factory = _factory;
usdgWethFee = _usdgWethFee;
treasury = _treasury;
owner = msg.sender;
}
// ── launch ────────────────────────────────────────────────────────────────
/// NORMAL (feeWallet == 0) or BAGS (feeWallet = creator). Send >= launchFeeWei;
/// extra ETH is an atomic dev-buy to msg.sender.
function launch(string calldata name, string calldata symbol, string calldata meta, address feeWallet)
external
payable
nonReentrant
returns (address token, address pool, uint256 tokensBought)
{
require(msg.value >= launchFeeWei, "launch fee");
Mode mode = feeWallet == address(0) ? Mode.NORMAL : Mode.BAGS;
bytes memory init =
abi.encodePacked(type(MemeToken).creationCode, abi.encode(name, symbol, TOTAL_SUPPLY, address(this)));
bytes32 salt = _mineSalt(keccak256(init));
token = address(new MemeToken{salt: salt}(name, symbol, TOTAL_SUPPLY, address(this)));
uint256 tokenId;
(pool, tokenId) = _openPool(token);
launches[token] = Launch(pool, tokenId, mode, feeWallet, address(0), true);
emit TokenCreated(block.timestamp, msg.sender, ++tokenNonce, token, name, symbol, meta);
tokensBought = _finish(token, pool);
}
/// RWA dividend coin: holders earn USDG streamed from trading fees.
function launchRwa(string calldata name, string calldata symbol, string calldata meta)
external
payable
nonReentrant
returns (address token, address pool, uint256 tokensBought)
{
require(msg.value >= launchFeeWei, "launch fee");
bytes memory init = abi.encodePacked(
type(DividendMemeToken).creationCode,
abi.encode(name, symbol, TOTAL_SUPPLY, address(this), address(this))
);
bytes32 salt = _mineSalt(keccak256(init));
token = address(new DividendMemeToken{salt: salt}(name, symbol, TOTAL_SUPPLY, address(this), address(this)));
DividendDistributor dist = new DividendDistributor(usdg, token, address(this));
DividendMemeToken(token).setDistributor(address(dist));
uint256 tokenId;
(pool, tokenId) = _openPool(token);
// only real circulating holders earn — exclude the pool, the locked LP,
// and the burn address from dividends.
dist.setExcluded(pool, true);
dist.setExcluded(address(this), true);
dist.setExcluded(DEAD, true);
launches[token] = Launch(pool, tokenId, Mode.RWA, address(0), address(dist), true);
emit TokenCreated(block.timestamp, msg.sender, ++tokenNonce, token, name, symbol, meta);
tokensBought = _finish(token, pool);
}
/// Create+initialize the pool and mint the full supply as single-sided
/// token0 liquidity, locking the NFT here.
function _openPool(address token) internal returns (address pool, uint256 tokenId) {
require(token < address(weth), "ordering");
pool = positionManager.createAndInitializePoolIfNecessary(token, address(weth), LP_FEE, OPEN_SQRT_PRICE);
IERC20(token).forceApprove(address(positionManager), TOTAL_SUPPLY);
(tokenId,,,) = positionManager.mint(
INonfungiblePositionManager.MintParams({
token0: token,
token1: address(weth),
fee: LP_FEE,
tickLower: TICK_LOWER,
tickUpper: TICK_UPPER,
amount0Desired: TOTAL_SUPPLY,
amount1Desired: 0,
amount0Min: 0,
amount1Min: 0,
recipient: address(this),
deadline: block.timestamp
})
);
}
/// launch fee to treasury; any remaining ETH is an atomic dev-buy.
function _finish(address token, address pool) internal returns (uint256 bought) {
if (launchFeeWei > 0) _sendEth(treasury, launchFeeWei);
uint256 devEth = msg.value - launchFeeWei;
if (devEth > 0) {
weth.deposit{value: devEth}();
IERC20(address(weth)).forceApprove(address(swapRouter), devEth);
bought = swapRouter.exactInputSingle(
ISwapRouter02.ExactInputSingleParams({
tokenIn: address(weth),
tokenOut: token,
fee: LP_FEE,
recipient: msg.sender,
amountIn: devEth,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
})
);
emit TokenBought(block.timestamp, token, msg.sender, bought, devEth, 0, 0);
}
emit LaunchedToDEX(token, pool, TOTAL_SUPPLY, devEth);
}
/// Mine a CREATE2 salt so the token address sorts below WETH (token0==token).
function _mineSalt(bytes32 initHash) internal view returns (bytes32) {
for (uint256 s = 0; s < 512; s++) {
address predicted = address(
uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(s), initHash))))
);
if (predicted < address(weth)) return bytes32(s);
}
revert("no salt");
}
// ── harvest ─────────────────────────────────────────────────────────────
/// Collect the locked position's 1% swap fees and route by mode. Permissionless.
function harvestFees(address token) external nonReentrant returns (uint256 tokenFee, uint256 wethFee) {
Launch memory L = launches[token];
require(L.exists, "unknown token");
(tokenFee, wethFee) = positionManager.collect(
INonfungiblePositionManager.CollectParams({
tokenId: L.tokenId,
recipient: address(this),
amount0Max: type(uint128).max,
amount1Max: type(uint128).max
})
);
if (L.mode == Mode.NORMAL) {
if (tokenFee > 0) IERC20(token).safeTransfer(treasury, tokenFee);
if (wethFee > 0) IERC20(address(weth)).safeTransfer(treasury, wethFee);
emit FeesHarvested(token, tokenFee, wethFee, treasury);
} else if (L.mode == Mode.BAGS) {
_splitToTreasuryAnd(token, L.feeWallet, tokenFee, wethFee);
emit CreatorFeePaid(token, L.feeWallet, tokenFee, wethFee);
emit FeesHarvested(token, tokenFee, wethFee, L.feeWallet);
} else {
// RWA: 100% of the 1% pool fee becomes USDG dividends for holders —
// the effective "1% buy + 1% sell tax to dividends". Buy-side fees
// accrue in WETH, sell-side fees accrue in the token; convert BOTH to
// USDG so every buy AND every sell fully feeds the dividend. No
// treasury cut on RWA (the launchpad earns via the launch fee).
uint256 wethForDiv = wethFee;
if (tokenFee > 0) {
IERC20(token).forceApprove(address(swapRouter), tokenFee);
wethForDiv += swapRouter.exactInputSingle(
ISwapRouter02.ExactInputSingleParams({
tokenIn: token,
tokenOut: address(weth),
fee: LP_FEE,
recipient: address(this),
amountIn: tokenFee,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
})
);
}
if (wethForDiv > 0 && rwaTreasuryBps > 0) {
uint256 cut = wethForDiv * rwaTreasuryBps / 10_000;
if (cut > 0) {
IERC20(address(weth)).safeTransfer(treasury, cut);
wethForDiv -= cut;
}
}
if (wethForDiv > 0) {
IERC20(address(weth)).forceApprove(address(swapRouter), wethForDiv);
uint256 usdgOut = swapRouter.exactInputSingle(
ISwapRouter02.ExactInputSingleParams({
tokenIn: address(weth),
tokenOut: address(usdg),
fee: usdgWethFee,
recipient: address(this),
amountIn: wethForDiv,
amountOutMinimum: 0,
sqrtPriceLimitX96: 0
})
);
if (usdgOut > 0) {
usdg.safeTransfer(L.distributor, usdgOut);
DividendDistributor(L.distributor).distribute(usdgOut);
}
}
emit FeesHarvested(token, tokenFee, wethFee, L.distributor);
}
}
function _splitToTreasuryAnd(address token, address dest, uint256 tokenFee, uint256 wethFee) internal {
require(dest != address(0), "no dest");
if (tokenFee > 0) {
uint256 t = tokenFee * treasuryBps / 10_000;
if (t > 0) IERC20(token).safeTransfer(treasury, t);
if (tokenFee - t > 0) IERC20(token).safeTransfer(dest, tokenFee - t);
}
if (wethFee > 0) {
uint256 t = wethFee * treasuryBps / 10_000;
if (t > 0) IERC20(address(weth)).safeTransfer(treasury, t);
if (wethFee - t > 0) IERC20(address(weth)).safeTransfer(dest, wethFee - t);
}
}
// ── views ─────────────────────────────────────────────────────────────────
function poolOf(address token) external view returns (address) {
return launches[token].pool;
}
function distributorOf(address token) external view returns (address) {
return launches[token].distributor;
}
/// Live claimable USDG dividends for a holder of an RWA coin (0 for others).
function dividendsOf(address token, address holder) external view returns (uint256) {
address d = launches[token].distributor;
return d == address(0) ? 0 : DividendDistributor(d).withdrawableDividendOf(holder);
}
function priceUsd(address token, uint256 ethUsdWad) external view returns (uint256) {
address pool = launches[token].pool;
if (pool == address(0)) return 0;
(uint160 sp,,,,,,) = IUniswapV3PoolMinimal(pool).slot0();
uint256 wethPerToken = uint256(sp) * sp * 1e18 >> 192;
return wethPerToken * ethUsdWad / 1e18;
}
// ── admin ─────────────────────────────────────────────────────────────────
function setLaunchFee(uint256 wei_) external {
require(msg.sender == owner, "not owner");
launchFeeWei = wei_;
emit LaunchFeeSet(wei_);
}
function setTreasuryBps(uint256 bps) external {
require(msg.sender == owner, "not owner");
require(bps <= MAX_TREASURY_BPS, "cap 50%");
treasuryBps = bps;
emit TreasuryBpsSet(bps);
}
/// Treasury cut on RWA harvest, in bps. 0 (default) = 100% of the 1% fee to
/// holder dividends; raise it to also route part of RWA volume to treasury.
function setRwaTreasuryBps(uint256 bps) external {
require(msg.sender == owner, "not owner");
require(bps <= MAX_TREASURY_BPS, "cap 50%");
rwaTreasuryBps = bps;
emit TreasuryBpsSet(bps);
}
function _sendEth(address to, uint256 amt) internal {
(bool ok,) = to.call{value: amt}("");
require(ok, "eth send");
}
receive() external payable {
require(msg.sender == address(weth), "direct eth");
}
}
Chain explorer1884msChain node72ms