KitchenSushi

0xfce2050d5135531ac8730f917454605a684a7947

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
13,566 bytes
ABI entries
21
4 read · 6 write
License
none

Contract information

Address
0xfce2050d5135531ac8730f917454605a684a7947
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xa74b4981ed…ff95928039

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 explorer2081msChain node81ms