Launchpad
0x1badc838aae6ac41829180744ea2e1c89b452aae
Verification
Verified
v0.8.20+commit.a1b79de6
Type
Contract
16,420 bytes
ABI entries
89
41 read · 19 write
License
none
Contract information
- Address
- 0x1badc838aae6ac41829180744ea2e1c89b452aae
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.20+commit.a1b79de6
- Optimization
- Enabled
- Creator
- 0xCB962B93BD…06c2D67929
- Creation tx
- 0x3a88c9929e…c40265f235
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (41)
FRACTION_DENOMINATOR() → uint256
INITIAL_SUPPLY() → uint256
MAX_BONDING_FRACTION() → uint256
MAX_BOOSTER_FRACTION() → uint256
MAX_CREATION_COST() → uint256
MAX_GAUGE_FEE() → uint256
accessRegistry() → address
bondingCurveFraction() → uint64
boosterFraction() → uint64
creationCost() → uint64
curve() → address
gaugeFees() → uint128, uint128
gaugeImplementation() → address
getAllTokens() → address[]
getAllTokensAndGauges() → address[], address[]
getAllTokensInfo() → tuple[]
getMostRecentTokens(uint256) → address[]
getMostRecentTokensAndGauges(uint256) → address[], address[]
getMostRecentTokensInfo(uint256) → tuple[]
getTokenInfo(address) → tuple
getTokens(uint256, uint256) → address[]
getTokensAndGauges(uint256, uint256) → address[], address[]
getTokensAndGaugesByCreator(address) → address[], address[]
getTokensByCreator(address) → address[]
getTokensCount() → uint256
getTokensCountByCreator(address) → uint256
getTokensInfo(uint256, uint256) → tuple[]
getTokensInfoByCreator(address) → tuple[]
lpReceiver() → address
owner() → address
quote(address, uint256, uint8) → tuple
quoteBuyExactEth(address, uint256) → uint256, uint256
quoteBuyExactTokens(address, uint256) → uint256, uint256
quoteSellExactEth(address, uint256) → uint256, uint256
quoteSellExactTokens(address, uint256) → uint256, uint256
tokenImplementation() → address
tokenToCreator(address) → address
tokenToGauge(address) → address
treasury() → address
yMax() → uint128
yMin() → uint128
Events (12)
AccessRegistrySetBondingCurveFractionSetBoosterFractionSetCreationCostSetCurveSetGaugeFeesSetGaugeImplementationSetLpReceiverSetNewTokenOwnershipTransferredTokenImplementationSetTreasurySet
ABI
[
{
"inputs": [
{
"internalType": "address",
"name": "_tokenImplementation",
"type": "address"
},
{
"internalType": "address",
"name": "_accessRegistry",
"type": "address"
},
{
"internalType": "address",
"name": "_curve",
"type": "address"
},
{
"internalType": "address",
"name": "_treasury",
"type": "address"
},
{
"internalType": "address",
"name": "_lpReceiver",
"type": "address"
},
{
"internalType": "uint64",
"name": "_creationCost",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "_boosterFraction",
"type": "uint64"
},
{
"internalType": "uint128",
"name": "_yMin",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "_yMax",
"type": "uint128"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "ERC1167FailedCreateClone",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__ExcessiveBondingFraction",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__ExcessiveBoosterFraction",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__ExcessiveCreationCost",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__ExcessiveGaugeFee",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__GaugeImplementationNotSet",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__InsufficientValue",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__InvalidIndex",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__InvalidToken",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__InvalidTotalSupply",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__TokenCreationNotAllowed",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__TransferFailure",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__Unauthorized",
"type": "error"
},
{
"inputs": [],
"name": "Launchpad__ZeroAddress",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newRegistry",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "oldRegistry",
"type": "address"
}
],
"name": "AccessRegistrySet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "newFraction",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "oldFraction",
"type": "uint256"
}
],
"name": "BondingCurveFractionSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "newFraction",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "oldFraction",
"type": "uint256"
}
],
"name": "BoosterFractionSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "newAmount",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "oldAmount",
"type": "uint256"
}
],
"name": "CreationCostSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newCurve",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "oldCurve",
"type": "address"
}
],
"name": "CurveSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "newBuyFee",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "oldBuyFee",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "newSellFee",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "oldSellFee",
"type": "uint256"
}
],
"name": "GaugeFeesSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newImpl",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "oldImpl",
"type": "address"
}
],
"name": "GaugeImplementationSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newReceiver",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "oldReceiver",
"type": "address"
}
],
"name": "LpReceiverSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "gauge",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "curve",
"type": "address"
}
],
"name": "NewToken",
"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": true,
"internalType": "address",
"name": "newImpl",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "oldImpl",
"type": "address"
}
],
"name": "TokenImplementationSet",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "newTreasury",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "oldTreasury",
"type": "address"
}
],
"name": "TreasurySet",
"type": "event"
},
{
"inputs": [],
"name": "FRACTION_DENOMINATOR",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "INITIAL_SUPPLY",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_BONDING_FRACTION",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_BOOSTER_FRACTION",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_CREATION_COST",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "MAX_GAUGE_FEE",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "accessRegistry",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "bondingCurveFraction",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "boosterFraction",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "minAmountOut",
"type": "uint256"
}
],
"name": "buyExactEth",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
}
],
"name": "buyExactTokens",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
}
],
"internalType": "struct LaunchpadToken.TokenConfig",
"name": "tokenConfig",
"type": "tuple"
},
{
"components": [
{
"internalType": "string",
"name": "ipfsHash",
"type": "string"
},
{
"internalType": "string",
"name": "website",
"type": "string"
},
{
"internalType": "string",
"name": "twitter",
"type": "string"
},
{
"internalType": "string",
"name": "telegram",
"type": "string"
},
{
"internalType": "string",
"name": "description",
"type": "string"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct LaunchpadToken.TokenMetadataConfig",
"name": "metadataConfig",
"type": "tuple"
},
{
"components": [
{
"internalType": "uint256",
"name": "minAmountOut",
"type": "uint256"
}
],
"internalType": "struct Launchpad.AutoSnipeConfig",
"name": "snipeConfig",
"type": "tuple"
}
],
"name": "createLaunchpadToken",
"outputs": [
{
"internalType": "contract LaunchpadToken",
"name": "",
"type": "address"
},
{
"internalType": "contract Gauge",
"name": "",
"type": "address"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "creationCost",
"outputs": [
{
"internalType": "uint64",
"name": "",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "curve",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "gaugeFees",
"outputs": [
{
"internalType": "uint128",
"name": "buyFee",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "sellFee",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "gaugeImplementation",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getAllTokens",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getAllTokensAndGauges",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getAllTokensInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "gauge",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bool",
"name": "gaugeActive",
"type": "bool"
},
{
"internalType": "bool",
"name": "gaugeClosable",
"type": "bool"
},
{
"internalType": "uint256",
"name": "tokenPurchased",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "tokenTarget",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "currentPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "ethPaid",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "buyFee",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "sellFee",
"type": "uint128"
},
{
"components": [
{
"internalType": "string",
"name": "ipfsHash",
"type": "string"
},
{
"internalType": "string",
"name": "website",
"type": "string"
},
{
"internalType": "string",
"name": "twitter",
"type": "string"
},
{
"internalType": "string",
"name": "telegram",
"type": "string"
},
{
"internalType": "string",
"name": "description",
"type": "string"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct LaunchpadToken.TokenMetadataConfig",
"name": "metadata",
"type": "tuple"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"internalType": "struct Launchpad.TokenInfo[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "getMostRecentTokens",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "getMostRecentTokensAndGauges",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "num",
"type": "uint256"
}
],
"name": "getMostRecentTokensInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "gauge",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bool",
"name": "gaugeActive",
"type": "bool"
},
{
"internalType": "bool",
"name": "gaugeClosable",
"type": "bool"
},
{
"internalType": "uint256",
"name": "tokenPurchased",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "tokenTarget",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "currentPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "ethPaid",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "buyFee",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "sellFee",
"type": "uint128"
},
{
"components": [
{
"internalType": "string",
"name": "ipfsHash",
"type": "string"
},
{
"internalType": "string",
"name": "website",
"type": "string"
},
{
"internalType": "string",
"name": "twitter",
"type": "string"
},
{
"internalType": "string",
"name": "telegram",
"type": "string"
},
{
"internalType": "string",
"name": "description",
"type": "string"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct LaunchpadToken.TokenMetadataConfig",
"name": "metadata",
"type": "tuple"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"internalType": "struct Launchpad.TokenInfo[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "getTokenInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "gauge",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bool",
"name": "gaugeActive",
"type": "bool"
},
{
"internalType": "bool",
"name": "gaugeClosable",
"type": "bool"
},
{
"internalType": "uint256",
"name": "tokenPurchased",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "tokenTarget",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "currentPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "ethPaid",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "buyFee",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "sellFee",
"type": "uint128"
},
{
"components": [
{
"internalType": "string",
"name": "ipfsHash",
"type": "string"
},
{
"internalType": "string",
"name": "website",
"type": "string"
},
{
"internalType": "string",
"name": "twitter",
"type": "string"
},
{
"internalType": "string",
"name": "telegram",
"type": "string"
},
{
"internalType": "string",
"name": "description",
"type": "string"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct LaunchpadToken.TokenMetadataConfig",
"name": "metadata",
"type": "tuple"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"internalType": "struct Launchpad.TokenInfo",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "start",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "end",
"type": "uint256"
}
],
"name": "getTokens",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "start",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "end",
"type": "uint256"
}
],
"name": "getTokensAndGauges",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "creator",
"type": "address"
}
],
"name": "getTokensAndGaugesByCreator",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "creator",
"type": "address"
}
],
"name": "getTokensByCreator",
"outputs": [
{
"internalType": "address[]",
"name": "",
"type": "address[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getTokensCount",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "creator",
"type": "address"
}
],
"name": "getTokensCountByCreator",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "start",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "end",
"type": "uint256"
}
],
"name": "getTokensInfo",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "gauge",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bool",
"name": "gaugeActive",
"type": "bool"
},
{
"internalType": "bool",
"name": "gaugeClosable",
"type": "bool"
},
{
"internalType": "uint256",
"name": "tokenPurchased",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "tokenTarget",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "currentPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "ethPaid",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "buyFee",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "sellFee",
"type": "uint128"
},
{
"components": [
{
"internalType": "string",
"name": "ipfsHash",
"type": "string"
},
{
"internalType": "string",
"name": "website",
"type": "string"
},
{
"internalType": "string",
"name": "twitter",
"type": "string"
},
{
"internalType": "string",
"name": "telegram",
"type": "string"
},
{
"internalType": "string",
"name": "description",
"type": "string"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct LaunchpadToken.TokenMetadataConfig",
"name": "metadata",
"type": "tuple"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"internalType": "struct Launchpad.TokenInfo[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "creator",
"type": "address"
}
],
"name": "getTokensInfoByCreator",
"outputs": [
{
"components": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "gauge",
"type": "address"
},
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "bool",
"name": "gaugeActive",
"type": "bool"
},
{
"internalType": "bool",
"name": "gaugeClosable",
"type": "bool"
},
{
"internalType": "uint256",
"name": "tokenPurchased",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "tokenTarget",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "totalSupply",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "currentPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "ethPaid",
"type": "uint256"
},
{
"internalType": "uint128",
"name": "buyFee",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "sellFee",
"type": "uint128"
},
{
"components": [
{
"internalType": "string",
"name": "ipfsHash",
"type": "string"
},
{
"internalType": "string",
"name": "website",
"type": "string"
},
{
"internalType": "string",
"name": "twitter",
"type": "string"
},
{
"internalType": "string",
"name": "telegram",
"type": "string"
},
{
"internalType": "string",
"name": "description",
"type": "string"
},
{
"internalType": "string",
"name": "metadata",
"type": "string"
}
],
"internalType": "struct LaunchpadToken.TokenMetadataConfig",
"name": "metadata",
"type": "tuple"
},
{
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"internalType": "address",
"name": "pool",
"type": "address"
}
],
"internalType": "struct Launchpad.TokenInfo[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "lpReceiver",
"outputs": [
{
"internalType": "address",
"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"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
},
{
"internalType": "enum Launchpad.QuoteType",
"name": "quoteType",
"type": "uint8"
}
],
"name": "quote",
"outputs": [
{
"components": [
{
"internalType": "uint256",
"name": "amountInEth",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountInToken",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountOutEth",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "amountOutToken",
"type": "uint256"
}
],
"internalType": "struct Launchpad.Quote",
"name": "",
"type": "tuple"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "quoteBuyExactEth",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "quoteBuyExactTokens",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "quoteSellExactEth",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "quoteSellExactTokens",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountOut",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxInput",
"type": "uint256"
}
],
"name": "sellExactEth",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "uint256",
"name": "amountIn",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "minAmountOut",
"type": "uint256"
}
],
"name": "sellExactTokens",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_accessRegistry",
"type": "address"
}
],
"name": "setAccessRegistry",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "_bondingCurveFraction",
"type": "uint64"
}
],
"name": "setBondingCurveFraction",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "_boosterFraction",
"type": "uint64"
}
],
"name": "setBoosterFraction",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint64",
"name": "_creationCost",
"type": "uint64"
}
],
"name": "setCreationCost",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_curve",
"type": "address"
}
],
"name": "setCurve",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "uint128",
"name": "buyFee",
"type": "uint128"
},
{
"internalType": "uint128",
"name": "sellFee",
"type": "uint128"
}
],
"internalType": "struct Gauge.FeeParameters",
"name": "_gaugeFees",
"type": "tuple"
}
],
"name": "setGaugeFees",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_gaugeImplementation",
"type": "address"
}
],
"name": "setGaugeImplementation",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_lpReceiver",
"type": "address"
}
],
"name": "setLpReceiver",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_tokenImplementation",
"type": "address"
}
],
"name": "setTokenImplementation",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_treasury",
"type": "address"
}
],
"name": "setTreasury",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint128",
"name": "_yMax",
"type": "uint128"
}
],
"name": "setYMax",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint128",
"name": "_yMin",
"type": "uint128"
}
],
"name": "setYMin",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "tokenImplementation",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "tokenToCreator",
"outputs": [
{
"internalType": "address",
"name": "creator",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "tokenToGauge",
"outputs": [
{
"internalType": "address",
"name": "gauge",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "treasury",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "yMax",
"outputs": [
{
"internalType": "uint128",
"name": "",
"type": "uint128"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "yMin",
"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 {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import {Gauge} from "./Gauge.sol";
import {LaunchpadToken} from "./LaunchpadToken.sol";
import {ICurve} from "./curves/ICurve.sol";
import {IAccessRegistry} from "./interfaces/IAccessRegistry.sol";
/**
* --------------------------------------------------------------------------------
*
* @title Launchpad
* @notice Platform entry point for creating and trading tokens
* @author BowTiedPickle
*
* --------------------------------------------------------------------------------
*/
contract Launchpad is Ownable {
////////////////////////////////////////////////////////////////////////////////
// LIBRARIES
////////////////////////////////////////////////////////////////////////////////
using EnumerableSet for EnumerableSet.AddressSet;
////////////////////////////////////////////////////////////////////////////////
// CONSTANTS
////////////////////////////////////////////////////////////////////////////////
/// @notice Maximum fraction of supply of a new token which can be reserved for booster program (1e18 = 100%)
uint256 public constant MAX_BOOSTER_FRACTION = 0.02e18; // 2%
/// @notice Maximum fraction of supply of a new token which can be used in the bonding curve (1e18 = 100%)
uint256 public constant MAX_BONDING_FRACTION = 0.98e18; // 98%
uint256 public constant FRACTION_DENOMINATOR = 1e18;
/// @notice Maximum creation cost which can be charged (wei of ETH)
uint256 public constant MAX_CREATION_COST = 0.1 ether;
/// @notice Maximum buy/sell fee which is allowed in a gauge
uint256 public constant MAX_GAUGE_FEE = 2.5e16; // 2.5%
/// @notice Initial Supply of the token
uint256 public constant INITIAL_SUPPLY = 1_000_000_000 ether;
/// @notice yMin value for the bonding curve
uint128 public yMin = 0;
/// @notice yMax value for the bonding curve
uint128 public yMax = 0;
////////////////////////////////////////////////////////////////////////////////
// CONFIGURATION
////////////////////////////////////////////////////////////////////////////////
/// @notice Address of the token implementation
address public tokenImplementation;
/// @notice Fraction of the initial token supply reserved for booster program
uint64 public boosterFraction;
/// @notice Address of the gauge implementation
address public gaugeImplementation;
/// @notice Address of the access registry
address public accessRegistry;
/// @notice Fraction of the initial token supply used in the bonding curve
uint64 public bondingCurveFraction = 0.8e18; // 80%
/// @notice Address of the bonding curve math implementation
address public curve;
/// @notice ETH-denominated cost to create a new token
uint64 public creationCost;
/// @notice Protocol treasury address
address public treasury;
/// @notice Address which will receive LP tokens when pools are created from a gauge
address public lpReceiver;
/// @notice Fee parameters applied to new gauges
Gauge.FeeParameters public gaugeFees;
////////////////////////////////////////////////////////////////////////////////
// TRACKING
////////////////////////////////////////////////////////////////////////////////
/// @notice Mapping of token address to gauge address
mapping(address token => address gauge) public tokenToGauge;
/// @notice Mapping of token address to creator address
mapping(address token => address creator) public tokenToCreator;
/// @dev Set of all created tokens
EnumerableSet.AddressSet internal tokens;
/// @dev Mapping of creator address to created tokens
mapping(address creator => EnumerableSet.AddressSet tokens)
internal creatorToTokens;
////////////////////////////////////////////////////////////////////////////////
// CONSTRUCTOR
////////////////////////////////////////////////////////////////////////////////
constructor(
address _tokenImplementation,
address _accessRegistry,
address _curve,
address _treasury,
address _lpReceiver,
uint64 _creationCost,
uint64 _boosterFraction,
uint128 _yMin,
uint128 _yMax
) Ownable(msg.sender) {
if (
_tokenImplementation == address(0) ||
_accessRegistry == address(0) ||
_curve == address(0) ||
_treasury == address(0) ||
_lpReceiver == address(0)
) revert Launchpad__ZeroAddress();
if (_creationCost > MAX_CREATION_COST)
revert Launchpad__ExcessiveCreationCost();
if (_boosterFraction > MAX_BOOSTER_FRACTION)
revert Launchpad__ExcessiveBoosterFraction();
tokenImplementation = _tokenImplementation;
curve = _curve;
accessRegistry = _accessRegistry;
treasury = _treasury;
lpReceiver = _lpReceiver;
creationCost = _creationCost;
boosterFraction = _boosterFraction;
yMin = _yMin;
yMax = _yMax;
}
////////////////////////////////////////////////////////////////////////////////
// CREATE TOKENS
////////////////////////////////////////////////////////////////////////////////
struct AutoSnipeConfig {
uint256 minAmountOut;
}
/**
* @notice Create a new token and gauge
* @param tokenConfig Token configuration
* @param metadataConfig Token metadata configuration
* @param snipeConfig Autosnipe configuration
* @dev Send more ETH than the creation cost to trigger an autosnipe with the excess
* @return token Token address
* @return gauge Gauge address
*/
function createLaunchpadToken(
LaunchpadToken.TokenConfig memory tokenConfig,
LaunchpadToken.TokenMetadataConfig memory metadataConfig,
AutoSnipeConfig memory snipeConfig
) external payable returns (LaunchpadToken, Gauge) {
if (!IAccessRegistry(accessRegistry).isTokenCreationAllowed(msg.sender)) {
revert Launchpad__TokenCreationNotAllowed();
}
if (msg.value < creationCost) revert Launchpad__InsufficientValue();
Gauge.CurveParameters memory curveParameters = Gauge.CurveParameters({
yMin: yMin,
yMax: yMax
});
// Create token and gauge
(LaunchpadToken token, Gauge gauge) = _createTokenAndGauge(
tokenConfig,
metadataConfig
);
{
uint256 boosterFractionAmount = (INITIAL_SUPPLY *
boosterFraction) / FRACTION_DENOMINATOR;
uint256 bondingCurveFractionAmount = (INITIAL_SUPPLY *
bondingCurveFraction) / FRACTION_DENOMINATOR;
gauge.initialize(
token,
ICurve(curve),
address(this),
lpReceiver,
INITIAL_SUPPLY -
boosterFractionAmount,
bondingCurveFractionAmount,
curveParameters,
gaugeFees
);
}
// Take creation cost - call used due to multisig recipient
(bool success, ) = payable(treasury).call{value: creationCost}("");
if (!success) revert Launchpad__TransferFailure();
emit NewToken(msg.sender, address(token), address(gauge), curve);
// Autosnipe
if (msg.value > creationCost) {
gauge.buyExactEth{value: msg.value - creationCost}(
msg.sender,
snipeConfig.minAmountOut
);
}
return (token, gauge);
}
/**
* @dev Internal function to create a token and gauge, and initialize the token.
* @dev Avoids stack too deep
*/
function _createTokenAndGauge(
LaunchpadToken.TokenConfig memory tokenConfig,
LaunchpadToken.TokenMetadataConfig memory metadataConfig
) internal returns (LaunchpadToken, Gauge) {
LaunchpadToken token = LaunchpadToken(
Clones.clone(tokenImplementation)
);
if(gaugeImplementation == address(0)){
revert Launchpad__GaugeImplementationNotSet();
}
Gauge gauge = Gauge(Clones.clone(gaugeImplementation));
tokenToGauge[address(token)] = address(gauge);
tokens.add(address(token));
creatorToTokens[msg.sender].add(address(token));
tokenToCreator[address(token)] = msg.sender;
token.initialize(tokenConfig, metadataConfig, address(gauge),INITIAL_SUPPLY);
uint256 boosterFractionAmount = (INITIAL_SUPPLY *
boosterFraction) / FRACTION_DENOMINATOR;
token.transfer(treasury, boosterFractionAmount);
// Max approval to enable router functions later
token.approve(address(gauge), type(uint256).max);
return (token, gauge);
}
////////////////////////////////////////////////////////////////////////////////
// TRADE TOKENS
////////////////////////////////////////////////////////////////////////////////
/**
* @notice Buy an exact amount of tokens
* @dev Allowable slippage is defined by msg.value
* @param token Token address
* @param amountOut Amount of tokens to buy
*/
function buyExactTokens(address token, uint256 amountOut) external payable {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
gauge.buyExactTokens{value: msg.value}(msg.sender, amountOut);
}
/**
* @notice Sell an exact amount of tokens
* @param token Token address
* @param amountIn Amount of tokens to sell
* @param minAmountOut Minimum amount of ETH to receive
*/
function sellExactTokens(
address token,
uint256 amountIn,
uint256 minAmountOut
) external {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
LaunchpadToken(token).transferFrom(msg.sender, address(this), amountIn);
gauge.sellExactTokens(msg.sender, amountIn, minAmountOut);
}
/**
* @notice Buy the maximum amount of tokens for an exact ETH input
* @param token Token address
* @param minAmountOut Minimum amount of tokens to receive
*/
function buyExactEth(address token, uint256 minAmountOut) external payable {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
gauge.buyExactEth{value: msg.value}(msg.sender, minAmountOut);
}
/**
* @notice Sell the minimum amount of tokens for an exact ETH output
* @param token Token address
* @param amountOut Amount of ETH to receive
* @param maxInput Maximum amount of tokens to sell
*/
function sellExactEth(
address token,
uint256 amountOut,
uint256 maxInput
) external {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
(uint256 amountIn, ) = gauge.quoteSellExactEth(amountOut);
LaunchpadToken(token).transferFrom(msg.sender, address(this), amountIn);
gauge.sellExactEth(msg.sender, amountOut, maxInput);
}
////////////////////////////////////////////////////////////////////////////////
// VIEWS
////////////////////////////////////////////////////////////////////////////////
// ---------- Quotes ----------
enum QuoteType {
BUY_EXACT_TOKENS,
SELL_EXACT_TOKENS,
BUY_EXACT_ETH,
SELL_EXACT_ETH
}
struct Quote {
// Wei of ETH the user will pay for the action
uint256 amountInEth;
// Wei of tokens the user will pay for the action
uint256 amountInToken;
// Wei of ETH the user will receive
uint256 amountOutEth;
// Wei of tokens the user will receive
uint256 amountOutToken;
}
/**
* @notice Get a quote for a trade at the prevailing conditions
* @dev The price may change from this value, set slippage accordingly
* @param token Token address
* @param amount Amount of tokens to buy/sell
* @param quoteType Type of trade to quote
* @return quote Quote struct
*/
function quote(
address token,
uint256 amount,
QuoteType quoteType
) external view returns (Quote memory) {
Quote memory result = Quote(0, 0, 0, 0);
uint256 value;
if (quoteType == QuoteType.BUY_EXACT_TOKENS) {
(amount, value) = quoteBuyExactTokens(token, amount);
result.amountInEth = value;
result.amountOutToken = amount;
} else if (quoteType == QuoteType.SELL_EXACT_TOKENS) {
(amount, value) = quoteSellExactTokens(token, amount);
result.amountInToken = amount;
result.amountOutEth = value;
} else if (quoteType == QuoteType.BUY_EXACT_ETH) {
(amount, value) = quoteBuyExactEth(token, amount);
result.amountInEth = amount;
result.amountOutToken = value;
} else if (quoteType == QuoteType.SELL_EXACT_ETH) {
(amount, value) = quoteSellExactEth(token, amount);
result.amountInToken = value;
result.amountOutEth = amount;
}
return result;
}
/**
* @notice Get the ETH cost of buying `amount` of tokens, inclusive of any fees
* @dev If `amount` exceeds the amount available to purchase, it will be clamped to the available amount
* @param token Token address
* @param amount Amount of tokens to buy
* @return amount: Amount of tokens being purchased
* @return total cost: Amount the user pays, in wei of ETH
*/
function quoteBuyExactTokens(
address token,
uint256 amount
) public view returns (uint256, uint256) {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
uint256 remaining = gauge.tokenTarget() - gauge.tokenPurchased();
amount = amount > remaining ? remaining : amount;
(uint256 result, ) = gauge.quoteBuyExactTokens(amount);
return (amount, result);
}
/**
* @notice Get the ETH proceeds of selling `amount` of tokens, inclusive of any fees
* @dev If `amount` exceeds the amount of tokens purchased, it will be clamped to the available amount
* @param token Token address
* @param amount Amount of tokens to sell
* @return total proceeds: Amount the user receives, in wei of ETH
*/
function quoteSellExactTokens(
address token,
uint256 amount
) public view returns (uint256, uint256) {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
uint256 available = gauge.tokenPurchased();
amount = amount > available ? available : amount;
(uint256 result, ) = gauge.quoteSellExactTokens(amount);
return (amount, result);
}
/**
* @notice Get the number of tokens which will cost `amount` of ETH, inclusive of any fees
* @param token Token address
* @param amount Amount of ETH to spend
* @return amountEth: Amount of ETH the user will pay
* @return tokensOut: Amount of tokens the user will receive
*/
function quoteBuyExactEth(
address token,
uint256 amount
) public view returns (uint256, uint256) {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
(uint256 result, ) = gauge.quoteBuyExactEth(amount);
uint256 remaining = gauge.tokenTarget() - gauge.tokenPurchased();
if (result > remaining) {
result = remaining;
(amount, ) = gauge.quoteBuyExactTokens(remaining);
}
return (amount, result);
}
/**
* @notice Get the number of tokens which must be sold to receive `amount` of ETH, inclusive of any fees
* @param token Token address
* @param amount Amount of ETH to receive
* @return tokensIn: Amount of tokens the user will pay
*/
function quoteSellExactEth(
address token,
uint256 amount
) public view returns (uint256, uint256) {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
(, uint256 sellFee) = gauge.feeParameters();
uint256 available = (gauge.ethPaid() *
(FRACTION_DENOMINATOR - sellFee)) / FRACTION_DENOMINATOR;
amount = amount > available ? available : amount;
(uint256 result, ) = gauge.quoteSellExactEth(amount);
return (amount, result);
}
// ---------- Tokens and Token Info ----------
struct TokenInfo {
// Token address
address token;
// Gauge address
address gauge;
// Token name
string name;
// Token symbol
string symbol;
// True if gauge is active
bool gaugeActive;
// True if gauge is closable
bool gaugeClosable;
// Number of tokens purchased in the gauge
uint256 tokenPurchased;
// Target number of tokens in the gauge
uint256 tokenTarget;
// Total supply of the token
uint256 totalSupply;
// Current price in wei of ETH per 1e18 wei of token
uint256 currentPrice;
// ETH paid into the gauge
uint256 ethPaid;
// Fractional fee charged on buy (1e18 = 100%)
uint128 buyFee;
// Fractional fee charged on sell (1e18 = 100%)
uint128 sellFee;
// Metadata
LaunchpadToken.TokenMetadataConfig metadata;
// Token creator address
address creator;
// Pool address
address pool;
}
/**
* @notice Get the current information of a given token and its gauge
* @param token Token address
* @return tokenInfo TokenInfo struct
*/
function getTokenInfo(
address token
) public view returns (TokenInfo memory) {
Gauge gauge = Gauge(tokenToGauge[token]);
if (address(gauge) == address(0)) revert Launchpad__InvalidToken();
(
bool active,
bool closable,
uint256 tokenPurchased,
uint256 tokenTarget,
uint256 totalSupply,
uint256 ethPaid,
uint256 currentPrice
) = gauge.getGaugeStatistics();
(uint128 buyFee, uint128 sellFee) = gauge.feeParameters();
return
TokenInfo({
token: token,
gauge: address(gauge),
name: LaunchpadToken(token).name(),
symbol: LaunchpadToken(token).symbol(),
gaugeActive: active,
gaugeClosable: closable,
tokenPurchased: tokenPurchased,
tokenTarget: tokenTarget,
totalSupply: totalSupply,
ethPaid: ethPaid,
currentPrice: currentPrice,
buyFee: buyFee,
sellFee: sellFee,
metadata: LaunchpadToken(token).getAllMetadata(),
creator: tokenToCreator[token],
pool: gauge.pool()
});
}
/**
* @notice Get current number of tokens deployed from this launchpad
* @return Number of tokens
*/
function getTokensCount() external view returns (uint256) {
return tokens.length();
}
/**
* @notice Get all tokens deployed from this launchpad
* @return Array of token addresses
*/
function getAllTokens() external view returns (address[] memory) {
return tokens.values();
}
/**
* @notice Get all tokens deployed from this launchpad and their corresponding gauges
* @return Array of token addresses
* @return Array of gauge addresses
*/
function getAllTokensAndGauges()
external
view
returns (address[] memory, address[] memory)
{
address[] memory _tokens = new address[](tokens.length());
address[] memory _gauges = new address[](tokens.length());
for (uint256 i; i < tokens.length(); ) {
address token = tokens.at(i);
_tokens[i] = token;
_gauges[i] = tokenToGauge[token];
unchecked {
++i;
}
}
return (_tokens, _gauges);
}
/**
* @notice Get all tokens deployed from this launchpad and their corresponding information
* @return Array of TokenInfo structs
*/
function getAllTokensInfo() external view returns (TokenInfo[] memory) {
TokenInfo[] memory data = new TokenInfo[](tokens.length());
for (uint256 i; i < tokens.length(); ) {
address token = tokens.at(i);
data[i] = getTokenInfo(token);
unchecked {
++i;
}
}
return data;
}
/**
* @notice Get a range of tokens deployed from this launchpad
* @param start Start index
* @param end End index (inclusive)
* @return Array of token addresses
*/
function getTokens(
uint256 start,
uint256 end
) public view returns (address[] memory) {
if (start > end || end > tokens.length() - 1)
revert Launchpad__InvalidIndex();
address[] memory _tokens = new address[](end - start + 1);
for (uint256 i = start; i <= end; ) {
_tokens[i - start] = tokens.at(i);
unchecked {
++i;
}
}
return _tokens;
}
/**
* @notice Get a range of tokens deployed from this launchpad and their corresponding gauges
* @param start Start index
* @param end End index
* @return Array of token addresses
* @return Array of gauge addresses
*/
function getTokensAndGauges(
uint256 start,
uint256 end
) external view returns (address[] memory, address[] memory) {
address[] memory _tokens = getTokens(start, end);
address[] memory _gauges = new address[](_tokens.length);
for (uint256 i; i < _tokens.length; ) {
_gauges[i] = tokenToGauge[_tokens[i]];
unchecked {
++i;
}
}
return (_tokens, _gauges);
}
/**
* @notice Get a range of tokens deployed from this launchpad and their corresponding information
* @param start Start index
* @param end End index
* @return Array of TokenInfo structs
*/
function getTokensInfo(
uint256 start,
uint256 end
) external view returns (TokenInfo[] memory) {
address[] memory _tokens = getTokens(start, end);
TokenInfo[] memory data = new TokenInfo[](_tokens.length);
for (uint256 i; i < _tokens.length; ) {
data[i] = getTokenInfo(_tokens[i]);
unchecked {
++i;
}
}
return data;
}
/**
* @notice Get `num` most recent tokens deployed from this launchpad
* @param num Number of tokens to return
* @return Array of token addresses
*/
function getMostRecentTokens(
uint256 num
) public view returns (address[] memory) {
if (num > tokens.length()) {
num = tokens.length();
}
address[] memory _tokens = new address[](num);
for (uint256 i; i < num; ) {
_tokens[i] = tokens.at(tokens.length() - 1 - i);
unchecked {
++i;
}
}
return _tokens;
}
/**
* @notice Get `num` most recent tokens deployed from this launchpad and their corresponding gauges
* @param num Number of tokens to return
* @return Array of token addresses
* @return Array of gauge addresses
*/
function getMostRecentTokensAndGauges(
uint256 num
) external view returns (address[] memory, address[] memory) {
if (num > tokens.length()) {
num = tokens.length();
}
address[] memory _tokens = getMostRecentTokens(num);
address[] memory _gauges = new address[](num);
for (uint256 i; i < num; ) {
_gauges[i] = tokenToGauge[_tokens[i]];
unchecked {
++i;
}
}
return (_tokens, _gauges);
}
/**
* @notice Get `num` most recent tokens deployed from this launchpad and their corresponding information
* @param num Number of tokens to return
* @return Array of TokenInfo structs
*/
function getMostRecentTokensInfo(
uint256 num
) external view returns (TokenInfo[] memory) {
if (num > tokens.length()) {
num = tokens.length();
}
address[] memory _tokens = getMostRecentTokens(num);
TokenInfo[] memory data = new TokenInfo[](num);
for (uint256 i; i < num; ) {
data[i] = getTokenInfo(_tokens[i]);
unchecked {
++i;
}
}
return data;
}
/**
* @notice Get the number of tokens deployed by a creator
* @param creator Creator address
* @return Number of tokens
*/
function getTokensCountByCreator(
address creator
) external view returns (uint256) {
return creatorToTokens[creator].length();
}
/**
* @notice Get all tokens deployed by a creator
* @param creator Creator address
* @return Array of token addresses
*/
function getTokensByCreator(
address creator
) public view returns (address[] memory) {
return creatorToTokens[creator].values();
}
/**
* @notice Get all tokens deployed by a creator and their corresponding gauges
* @param creator Creator address
* @return Array of token addresses
* @return Array of gauge addresses
*/
function getTokensAndGaugesByCreator(
address creator
) external view returns (address[] memory, address[] memory) {
address[] memory _tokens = getTokensByCreator(creator);
address[] memory _gauges = new address[](_tokens.length);
for (uint256 i; i < _tokens.length; ) {
_gauges[i] = tokenToGauge[_tokens[i]];
unchecked {
++i;
}
}
return (_tokens, _gauges);
}
/**
* @notice Get all tokens deployed by a creator and their corresponding information
* @param creator Creator address
* @return Array of TokenInfo structs
*/
function getTokensInfoByCreator(
address creator
) external view returns (TokenInfo[] memory) {
address[] memory _tokens = getTokensByCreator(creator);
TokenInfo[] memory data = new TokenInfo[](_tokens.length);
for (uint256 i; i < _tokens.length; ) {
data[i] = getTokenInfo(_tokens[i]);
unchecked {
++i;
}
}
return data;
}
////////////////////////////////////////////////////////////////////////////////
// ADMINISTRATION
////////////////////////////////////////////////////////////////////////////////
/**
* @notice Set the token implementation
* @param _tokenImplementation New token implementation address
*/
function setTokenImplementation(
address _tokenImplementation
) external onlyOwner {
if (_tokenImplementation == address(0)) revert Launchpad__ZeroAddress();
emit TokenImplementationSet(_tokenImplementation, tokenImplementation);
tokenImplementation = _tokenImplementation;
}
/**
* @notice Set the yMin value for the bonding curve
* @param _yMin New yMin value
*/
function setYMin(uint128 _yMin) external onlyOwner {
yMin = _yMin;
}
/**
* @notice Set the yMax value for the bonding curve
* @param _yMax New yMax value
*/
function setYMax(uint128 _yMax) external onlyOwner {
yMax = _yMax;
}
/**
* @notice Set the gauge implementation
* @param _gaugeImplementation New gauge implementation address
*/
function setGaugeImplementation(
address _gaugeImplementation
) external onlyOwner {
if (_gaugeImplementation == address(0)) revert Launchpad__ZeroAddress();
emit GaugeImplementationSet(_gaugeImplementation, gaugeImplementation);
gaugeImplementation = _gaugeImplementation;
}
/**
* @notice Set the access registry
* @param _accessRegistry New access registry address
*/
function setAccessRegistry(address _accessRegistry) external onlyOwner {
if (_accessRegistry == address(0)) revert Launchpad__ZeroAddress();
emit AccessRegistrySet(_accessRegistry, accessRegistry);
accessRegistry = _accessRegistry;
}
/**
* @notice Set the bonding curve math implementation
* @param _curve New curve implementation address
*/
function setCurve(address _curve) external onlyOwner {
if (_curve == address(0)) revert Launchpad__ZeroAddress();
emit CurveSet(_curve, curve);
curve = _curve;
}
/**
* @notice Set the treasury address
* @param _treasury The new treasury address
*/
function setTreasury(address _treasury) external onlyOwner {
if (_treasury == address(0)) revert Launchpad__ZeroAddress();
emit TreasurySet(_treasury, treasury);
treasury = _treasury;
}
/**
* @notice Set the LP receiver address
* @param _lpReceiver The new LP receiver address
*/
function setLpReceiver(address _lpReceiver) external onlyOwner {
if (_lpReceiver == address(0)) revert Launchpad__ZeroAddress();
emit LpReceiverSet(_lpReceiver, lpReceiver);
lpReceiver = _lpReceiver;
}
/**
* @notice Set the creation cost
* @param _creationCost The new creation cost
*/
function setCreationCost(uint64 _creationCost) external onlyOwner {
if (_creationCost > MAX_CREATION_COST)
revert Launchpad__ExcessiveCreationCost();
emit CreationCostSet(_creationCost, creationCost);
creationCost = _creationCost;
}
/**
* @notice Set the booster fraction
* @param _boosterFraction The new booster fraction
*/
function setBoosterFraction(uint64 _boosterFraction) external onlyOwner {
if (_boosterFraction > MAX_BOOSTER_FRACTION)
revert Launchpad__ExcessiveBoosterFraction();
emit BoosterFractionSet(_boosterFraction, boosterFraction);
boosterFraction = _boosterFraction;
}
/**
* @notice Set the gauge fees
* @param _gaugeFees The new gauge fees
*/
function setGaugeFees(
Gauge.FeeParameters calldata _gaugeFees
) external onlyOwner {
if (
_gaugeFees.buyFee > MAX_GAUGE_FEE ||
_gaugeFees.sellFee > MAX_GAUGE_FEE
) {
revert Launchpad__ExcessiveGaugeFee();
}
emit GaugeFeesSet(
_gaugeFees.buyFee,
gaugeFees.buyFee,
_gaugeFees.sellFee,
gaugeFees.sellFee
);
gaugeFees = _gaugeFees;
}
/**
* @notice Set the bonding curve fraction
* @param _bondingCurveFraction The new bonding curve fraction
*/
function setBondingCurveFraction(
uint64 _bondingCurveFraction
) external onlyOwner {
if (_bondingCurveFraction > MAX_BONDING_FRACTION)
revert Launchpad__ExcessiveBondingFraction();
emit BondingCurveFractionSet(
_bondingCurveFraction,
bondingCurveFraction
);
bondingCurveFraction = _bondingCurveFraction;
}
////////////////////////////////////////////////////////////////////////////////
// ERRORS
////////////////////////////////////////////////////////////////////////////////
error Launchpad__ZeroAddress();
error Launchpad__InvalidTotalSupply();
error Launchpad__GaugeImplementationNotSet();
error Launchpad__InsufficientValue();
error Launchpad__InvalidToken();
error Launchpad__ExcessiveCreationCost();
error Launchpad__ExcessiveBoosterFraction();
error Launchpad__ExcessiveGaugeFee();
error Launchpad__ExcessiveBondingFraction();
error Launchpad__InvalidIndex();
error Launchpad__TransferFailure();
error Launchpad__Unauthorized();
error Launchpad__TokenCreationNotAllowed();
////////////////////////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////////////////////////
event NewToken(
address indexed creator,
address indexed token,
address indexed gauge,
address curve
);
event TokenImplementationSet(
address indexed newImpl,
address indexed oldImpl
);
event GaugeImplementationSet(
address indexed newImpl,
address indexed oldImpl
);
event CurveSet(address indexed newCurve, address indexed oldCurve);
event TreasurySet(address indexed newTreasury, address indexed oldTreasury);
event LpReceiverSet(
address indexed newReceiver,
address indexed oldReceiver
);
event CreationCostSet(uint256 newAmount, uint256 oldAmount);
event BoosterFractionSet(uint256 newFraction, uint256 oldFraction);
event GaugeFeesSet(
uint256 newBuyFee,
uint256 oldBuyFee,
uint256 newSellFee,
uint256 oldSellFee
);
event BondingCurveFractionSet(uint256 newFraction, uint256 oldFraction);
event AccessRegistrySet(
address indexed newRegistry,
address indexed oldRegistry
);
}
Chain explorer4407msChain node84ms