KitchenSushi
0x9e0551a4b4b51f6259cb1f169e9bda1e7cac12e6
Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
13,566 bytes
ABI entries
21
4 read · 6 write
License
none
Contract information
- Address
- 0x9e0551a4b4b51f6259cb1f169e9bda1e7cac12e6
- Chain
- Robinhood Chain (4663)
- Compiler
- v0.8.26+commit.8a97fa7a
- Optimization
- Enabled
- Creator
- 0x7B7DE29bc1…C6b0DaB694
- Creation tx
- 0x9cd48dfe7c…0db290fdf7
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (4)
POSITION_COUNT() → uint256
factory() → address
owner() → address
totalLaunches() → uint256
Events (3)
AdvancedLaunchedDirectLaunchedOwnershipTransferred
ABI
[
{
"inputs": [
{
"internalType": "contract SushiV3Factory",
"name": "_factory",
"type": "address"
},
{
"internalType": "address",
"name": "_owner",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "DirectMustHaveNoLimits",
"type": "error"
},
{
"inputs": [],
"name": "FeeSplitMustBeEmptyForSteak",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "OwnableInvalidOwner",
"type": "error"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
}
],
"name": "OwnableUnauthorizedAccount",
"type": "error"
},
{
"inputs": [],
"name": "ReentrancyGuardReentrantCall",
"type": "error"
},
{
"inputs": [],
"name": "ZeroAddress",
"type": "error"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "address",
"name": "proofOfSteak",
"type": "address"
}
],
"name": "AdvancedLaunched",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "creator",
"type": "address"
},
{
"indexed": false,
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
},
{
"indexed": false,
"internalType": "address",
"name": "proofOfSteak",
"type": "address"
}
],
"name": "DirectLaunched",
"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"
},
{
"inputs": [],
"name": "POSITION_COUNT",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "beneficiary",
"type": "address"
},
{
"internalType": "uint256",
"name": "targetMcapETH",
"type": "uint256"
},
{
"internalType": "enum SushiV3Factory.FeeClaimMode",
"name": "feeClaimMode",
"type": "uint8"
},
{
"components": [
{
"internalType": "address[5]",
"name": "wallets",
"type": "address[5]"
},
{
"internalType": "uint16[5]",
"name": "percentages",
"type": "uint16[5]"
},
{
"internalType": "uint8",
"name": "count",
"type": "uint8"
}
],
"internalType": "struct SushiV3Factory.FeeSplit",
"name": "feeSplit",
"type": "tuple"
},
{
"internalType": "bool",
"name": "isBranded",
"type": "bool"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "devBuyEth",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isLimited",
"type": "bool"
},
{
"components": [
{
"internalType": "uint64",
"name": "maxTxInterval",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "maxWalletInterval",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "maxTxStart",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxTxStep",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxWalletStart",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxWalletStep",
"type": "uint256"
}
],
"internalType": "struct TimeLimits.TimeConfig",
"name": "limits",
"type": "tuple"
}
],
"internalType": "struct SushiV3Factory.CreateParams",
"name": "params",
"type": "tuple"
}
],
"name": "createAdvanced",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "beneficiary",
"type": "address"
},
{
"internalType": "uint256",
"name": "targetMcapETH",
"type": "uint256"
},
{
"internalType": "enum SushiV3Factory.FeeClaimMode",
"name": "feeClaimMode",
"type": "uint8"
},
{
"components": [
{
"internalType": "address[5]",
"name": "wallets",
"type": "address[5]"
},
{
"internalType": "uint16[5]",
"name": "percentages",
"type": "uint16[5]"
},
{
"internalType": "uint8",
"name": "count",
"type": "uint8"
}
],
"internalType": "struct SushiV3Factory.FeeSplit",
"name": "feeSplit",
"type": "tuple"
},
{
"internalType": "bool",
"name": "isBranded",
"type": "bool"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "devBuyEth",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isLimited",
"type": "bool"
},
{
"components": [
{
"internalType": "uint64",
"name": "maxTxInterval",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "maxWalletInterval",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "maxTxStart",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxTxStep",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxWalletStart",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxWalletStep",
"type": "uint256"
}
],
"internalType": "struct TimeLimits.TimeConfig",
"name": "limits",
"type": "tuple"
}
],
"internalType": "struct SushiV3Factory.CreateParams",
"name": "params",
"type": "tuple"
}
],
"name": "createAdvancedWithSteak",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "proofOfSteak",
"type": "address"
},
{
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "beneficiary",
"type": "address"
},
{
"internalType": "uint256",
"name": "targetMcapETH",
"type": "uint256"
},
{
"internalType": "enum SushiV3Factory.FeeClaimMode",
"name": "feeClaimMode",
"type": "uint8"
},
{
"components": [
{
"internalType": "address[5]",
"name": "wallets",
"type": "address[5]"
},
{
"internalType": "uint16[5]",
"name": "percentages",
"type": "uint16[5]"
},
{
"internalType": "uint8",
"name": "count",
"type": "uint8"
}
],
"internalType": "struct SushiV3Factory.FeeSplit",
"name": "feeSplit",
"type": "tuple"
},
{
"internalType": "bool",
"name": "isBranded",
"type": "bool"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "devBuyEth",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isLimited",
"type": "bool"
},
{
"components": [
{
"internalType": "uint64",
"name": "maxTxInterval",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "maxWalletInterval",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "maxTxStart",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxTxStep",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxWalletStart",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxWalletStep",
"type": "uint256"
}
],
"internalType": "struct TimeLimits.TimeConfig",
"name": "limits",
"type": "tuple"
}
],
"internalType": "struct SushiV3Factory.CreateParams",
"name": "params",
"type": "tuple"
}
],
"name": "createDirect",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "symbol",
"type": "string"
},
{
"internalType": "address",
"name": "beneficiary",
"type": "address"
},
{
"internalType": "uint256",
"name": "targetMcapETH",
"type": "uint256"
},
{
"internalType": "enum SushiV3Factory.FeeClaimMode",
"name": "feeClaimMode",
"type": "uint8"
},
{
"components": [
{
"internalType": "address[5]",
"name": "wallets",
"type": "address[5]"
},
{
"internalType": "uint16[5]",
"name": "percentages",
"type": "uint16[5]"
},
{
"internalType": "uint8",
"name": "count",
"type": "uint8"
}
],
"internalType": "struct SushiV3Factory.FeeSplit",
"name": "feeSplit",
"type": "tuple"
},
{
"internalType": "bool",
"name": "isBranded",
"type": "bool"
},
{
"internalType": "bytes32",
"name": "salt",
"type": "bytes32"
},
{
"internalType": "uint256",
"name": "devBuyEth",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isLimited",
"type": "bool"
},
{
"components": [
{
"internalType": "uint64",
"name": "maxTxInterval",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "maxWalletInterval",
"type": "uint64"
},
{
"internalType": "uint256",
"name": "maxTxStart",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxTxStep",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxWalletStart",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxWalletStep",
"type": "uint256"
}
],
"internalType": "struct TimeLimits.TimeConfig",
"name": "limits",
"type": "tuple"
}
],
"internalType": "struct SushiV3Factory.CreateParams",
"name": "params",
"type": "tuple"
}
],
"name": "createDirectWithSteak",
"outputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address",
"name": "proofOfSteak",
"type": "address"
},
{
"internalType": "bytes32",
"name": "poolId",
"type": "bytes32"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "factory",
"outputs": [
{
"internalType": "contract SushiV3Factory",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "totalLaunches",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
/*
// 🥩 STEAKHOUSE FINANCE — KITCHEN SUSHI CONTROLLER (Sushi V3 / clAMM)
Single point of launch for the SteakHouse Sushi V3 ecosystem. Two routes,
each with an optional Proof of Steak add-on:
DIRECT — plain no-limit token, static 1% pool fee, concentrated liquidity.
(mirrors the Uniswap V4 DIRECT launch)
createDirect() / createDirectWithSteak()
ADVANCED — token with configurable time-based maxTx / maxWallet limits.
createAdvanced() / createAdvancedWithSteak()
Both routes share ONE SushiV3Factory. The only difference is the token type
the factory deploys (DirectToken vs LimitedToken) and whether the dev-supplied
`limits` are applied. The Kitchen forces `isLimited` per route so the route and
the token type can never mismatch.
Proof of Steak (POS): the Kitchen deploys a fresh ProofOfSteak staking
contract, registers it as the 100% LP-fee recipient, links it to the pool's
fee source (the factory) and renounces POS ownership so the link is immutable.
*/
pragma solidity ^0.8.26;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import {SushiV3Factory} from "./SushiV3Factory.sol";
import {ProofOfSteak} from "./ProofOfSteak.sol";
import {TimeLimits} from "../libraries/TimeLimits.sol";
/// @dev Thin launcher interface so the Kitchen creates on behalf of the real dev
/// EOA (createLaunchFor).
interface ISushiLauncher {
function createLaunchFor(SushiV3Factory.CreateParams calldata params, address creator)
external
payable
returns (address token, bytes32 poolId);
}
contract KitchenSushi is Ownable, ReentrancyGuard {
uint256 public constant POSITION_COUNT = 5;
SushiV3Factory public immutable factory;
event DirectLaunched(address indexed token, address indexed creator, bytes32 poolId, address proofOfSteak);
event AdvancedLaunched(address indexed token, address indexed creator, bytes32 poolId, address proofOfSteak);
error ZeroAddress();
error FeeSplitMustBeEmptyForSteak();
error DirectMustHaveNoLimits();
constructor(SushiV3Factory _factory, address _owner) Ownable(_owner) {
if (address(_factory) == address(0)) revert ZeroAddress();
factory = _factory;
}
// =====================================================
// DIRECT — plain no-limit token, 1% pool fee
// =====================================================
/// @notice DIRECT launch. Forces isLimited=false; `params.limits` must be
/// all-zero (a DIRECT token has no limit code, so a non-zero config
/// would be a silent no-op).
function createDirect(SushiV3Factory.CreateParams calldata params)
external
payable
nonReentrant
returns (address token, bytes32 poolId)
{
SushiV3Factory.CreateParams memory p = _asDirect(params);
(token, poolId) = ISushiLauncher(address(factory)).createLaunchFor{value: msg.value}(p, msg.sender);
emit DirectLaunched(token, msg.sender, poolId, address(0));
}
/// @notice DIRECT launch + Proof of Steak (POS is the 100% fee recipient).
function createDirectWithSteak(SushiV3Factory.CreateParams calldata params)
external
payable
nonReentrant
returns (address token, address proofOfSteak, bytes32 poolId)
{
if (params.feeSplit.count != 0) revert FeeSplitMustBeEmptyForSteak();
SushiV3Factory.CreateParams memory p = _asDirect(params);
(token, proofOfSteak, poolId) = _launchWithSteak(p);
emit DirectLaunched(token, msg.sender, poolId, proofOfSteak);
}
// =====================================================
// ADVANCED — configurable time-based limits
// =====================================================
/// @notice ADVANCED launch. Forces isLimited=true; `params.limits` is the
/// dev-supplied maxTx/maxWallet curve (validated by the factory).
function createAdvanced(SushiV3Factory.CreateParams calldata params)
external
payable
nonReentrant
returns (address token, bytes32 poolId)
{
SushiV3Factory.CreateParams memory p = params;
p.isLimited = true;
(token, poolId) = ISushiLauncher(address(factory)).createLaunchFor{value: msg.value}(p, msg.sender);
emit AdvancedLaunched(token, msg.sender, poolId, address(0));
}
/// @notice ADVANCED launch + Proof of Steak.
function createAdvancedWithSteak(SushiV3Factory.CreateParams calldata params)
external
payable
nonReentrant
returns (address token, address proofOfSteak, bytes32 poolId)
{
if (params.feeSplit.count != 0) revert FeeSplitMustBeEmptyForSteak();
SushiV3Factory.CreateParams memory p = params;
p.isLimited = true;
(token, proofOfSteak, poolId) = _launchWithSteak(p);
emit AdvancedLaunched(token, msg.sender, poolId, proofOfSteak);
}
// =====================================================
// INTERNAL
// =====================================================
/// @dev Coerce params to a DIRECT launch: no limits, isLimited=false. Rejects a
/// non-empty limits config rather than silently zeroing it.
function _asDirect(SushiV3Factory.CreateParams calldata params)
internal
pure
returns (SushiV3Factory.CreateParams memory p)
{
TimeLimits.TimeConfig calldata c = params.limits;
bool allZero = c.maxTxStart == 0 && c.maxTxStep == 0 && c.maxWalletStart == 0 && c.maxWalletStep == 0
&& c.maxTxInterval == 0 && c.maxWalletInterval == 0;
if (!allZero) revert DirectMustHaveNoLimits();
p = params;
p.isLimited = false;
}
/// @dev Shared POS path: deploy POS, set it as sole fee recipient, launch, link.
function _launchWithSteak(SushiV3Factory.CreateParams memory p)
internal
returns (address token, address proofOfSteak, bytes32 poolId)
{
proofOfSteak = address(
new ProofOfSteak{salt: _proofOfSteakSalt(address(factory), factory.totalLaunches(), p.name, p.symbol)}()
);
p.feeSplit = SushiV3Factory.FeeSplit({
wallets: [proofOfSteak, address(0), address(0), address(0), address(0)],
percentages: [uint16(10000), 0, 0, 0, 0],
count: 1
});
(token, poolId) = ISushiLauncher(address(factory)).createLaunchFor{value: msg.value}(p, msg.sender);
// The fee-source interface (collectFeesFromPosition / claim / claimable)
// lives on the FeeManager, so ProofOfSteak's positionHelper points there.
_linkSteak(proofOfSteak, token, address(factory.feeManager()), poolId, POSITION_COUNT);
}
function _proofOfSteakSalt(address _factory, uint256 launchIndex, string memory name, string memory symbol)
internal
view
returns (bytes32)
{
return keccak256(
abi.encode("SUSHI_POS_V1", block.chainid, address(this), msg.sender, _factory, launchIndex, name, symbol)
);
}
function _linkSteak(
address proofOfSteak,
address token,
address feeSource,
bytes32 poolId,
uint256 positionCount
) internal {
ProofOfSteak pos = ProofOfSteak(payable(proofOfSteak));
pos.setToken(token);
pos.setPositionHelper(feeSource, poolId, positionCount);
pos.renounceOwnership();
}
function totalLaunches() external view returns (uint256) {
return factory.totalLaunches();
}
receive() external payable {}
}
Chain explorer3571msChain node100ms