FrothMemeProtocolDeployer01

0x771fa05d3233d16df5cd2990adac93a1340e11e7

Verification
Verified
v0.8.28+commit.7893614a
Type
Contract
22,864 bytes
ABI entries
17
14 read · 2 write
License
none

Contract information

Address
0x771fa05d3233d16df5cd2990adac93a1340e11e7
Chain
Robinhood Chain (4663)
Compiler
v0.8.28+commit.7893614a
Optimization
Enabled
Creation tx
0xc429c8ed92…2a7183cca6

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (14)

BPS_DENOMINATOR()uint256
CREATE_MEME_TOKEN_FEE_KEY()bytes32
CREATOR_FEES_ON_BUYING_KEY()bytes32
CREATOR_FEES_ON_SELLING_KEY()bytes32
DEFAULT_MIN_CONTRIBUTION_AMOUNT()uint256
GRADUATION_FEE_KEY()bytes32
MAX_TOTAL_CONTRIBUTION()uint256
MEME_TOKEN_CAP()uint256
MEME_TOKEN_LIQUIDITY_AMOUNT()uint256
RUG_FEE_KEY()bytes32
TRADE_BUY_FEE_KEY()bytes32
TRADE_SELL_FEE_KEY()bytes32
toString(uint256)string
toString(bytes32)string

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "caller",
        "type": "address"
      }
    ],
    "name": "UnauthorizedOrchestrator",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "BPS_DENOMINATOR",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "CREATE_MEME_TOKEN_FEE_KEY",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "CREATOR_FEES_ON_BUYING_KEY",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "CREATOR_FEES_ON_SELLING_KEY",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "DEFAULT_MIN_CONTRIBUTION_AMOUNT",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "GRADUATION_FEE_KEY",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_TOTAL_CONTRIBUTION",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MEME_TOKEN_CAP",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MEME_TOKEN_LIQUIDITY_AMOUNT",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "RUG_FEE_KEY",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TRADE_BUY_FEE_KEY",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TRADE_SELL_FEE_KEY",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "initialAdminAndOperator",
            "type": "address"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.BondingCurveFactoryParams",
            "name": "bondingCurveFactoryParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "uint256",
                "name": "initialVirtualNative",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "initialVirtualTokens",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "maxTokensSold",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "targetGraduation",
                "type": "uint256"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.BondingCurveParams",
            "name": "bondingCurveParams",
            "type": "tuple"
          },
          {
            "internalType": "uint256",
            "name": "A",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "B",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "wrappedNative",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "routerV2",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "frothSwapV1Router",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "uniswapV3SwapRouter",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "frothV3FeeTier",
            "type": "uint24"
          },
          {
            "internalType": "address",
            "name": "froth",
            "type": "address"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              },
              {
                "components": [
                  {
                    "internalType": "uint256",
                    "name": "mintFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "creatorFeesOnBuyingFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "creatorFeesOnSellingFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "tradeBuyFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "tradeSellFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "graduationFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "rugFee",
                    "type": "uint256"
                  }
                ],
                "internalType": "struct BaseFrothMemeProtocolDeployer.FeeParams",
                "name": "feeParams",
                "type": "tuple"
              },
              {
                "internalType": "address",
                "name": "twapPool",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "teamWallet",
                "type": "address"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.FeeDistributorParams",
            "name": "feeDistributorParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.SaleMemeTokenManagerParams",
            "name": "saleMemeTokenManagerParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "paymentToken",
                "type": "address"
              },
              {
                "internalType": "uint256",
                "name": "paymentAmount",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "memeExpirationTime",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "minContributionAmount",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "maxTotalContribution",
                "type": "uint256"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.FrothMemeFactoryParams",
            "name": "frothMemeFactoryParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.CreatorFeesClaimerParams",
            "name": "creatorFeesClaimerParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              },
              {
                "internalType": "uint256",
                "name": "minNativeAmount",
                "type": "uint256"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.FrothBurnerParams",
            "name": "frothBurnerParams",
            "type": "tuple"
          }
        ],
        "internalType": "struct BaseFrothMemeProtocolDeployer.InputParams",
        "name": "_inputParams",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "bondingCurveFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "bondingCurve",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeDistributor",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "twapPool",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "saleMemeTokenManager",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "frothMemeFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "creatorFeesClaimer",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "frothBurner",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "uniswapV3SwapAdapter",
            "type": "address"
          }
        ],
        "internalType": "struct BaseFrothMemeProtocolDeployer.OutputParams",
        "name": "_outputParams",
        "type": "tuple"
      }
    ],
    "name": "configure",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "initialAdminAndOperator",
            "type": "address"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.BondingCurveFactoryParams",
            "name": "bondingCurveFactoryParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "uint256",
                "name": "initialVirtualNative",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "initialVirtualTokens",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "maxTokensSold",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "targetGraduation",
                "type": "uint256"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.BondingCurveParams",
            "name": "bondingCurveParams",
            "type": "tuple"
          },
          {
            "internalType": "uint256",
            "name": "A",
            "type": "uint256"
          },
          {
            "internalType": "uint256",
            "name": "B",
            "type": "uint256"
          },
          {
            "internalType": "address",
            "name": "wrappedNative",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "routerV2",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "frothSwapV1Router",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "uniswapV3SwapRouter",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "frothV3FeeTier",
            "type": "uint24"
          },
          {
            "internalType": "address",
            "name": "froth",
            "type": "address"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              },
              {
                "components": [
                  {
                    "internalType": "uint256",
                    "name": "mintFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "creatorFeesOnBuyingFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "creatorFeesOnSellingFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "tradeBuyFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "tradeSellFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "graduationFee",
                    "type": "uint256"
                  },
                  {
                    "internalType": "uint256",
                    "name": "rugFee",
                    "type": "uint256"
                  }
                ],
                "internalType": "struct BaseFrothMemeProtocolDeployer.FeeParams",
                "name": "feeParams",
                "type": "tuple"
              },
              {
                "internalType": "address",
                "name": "twapPool",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "teamWallet",
                "type": "address"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.FeeDistributorParams",
            "name": "feeDistributorParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.SaleMemeTokenManagerParams",
            "name": "saleMemeTokenManagerParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "paymentToken",
                "type": "address"
              },
              {
                "internalType": "uint256",
                "name": "paymentAmount",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "memeExpirationTime",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "minContributionAmount",
                "type": "uint256"
              },
              {
                "internalType": "uint256",
                "name": "maxTotalContribution",
                "type": "uint256"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.FrothMemeFactoryParams",
            "name": "frothMemeFactoryParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.CreatorFeesClaimerParams",
            "name": "creatorFeesClaimerParams",
            "type": "tuple"
          },
          {
            "components": [
              {
                "internalType": "address",
                "name": "finalAdmin",
                "type": "address"
              },
              {
                "internalType": "address",
                "name": "finalOperator",
                "type": "address"
              },
              {
                "internalType": "uint256",
                "name": "minNativeAmount",
                "type": "uint256"
              }
            ],
            "internalType": "struct BaseFrothMemeProtocolDeployer.FrothBurnerParams",
            "name": "frothBurnerParams",
            "type": "tuple"
          }
        ],
        "internalType": "struct BaseFrothMemeProtocolDeployer.InputParams",
        "name": "_inputParams",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "address",
            "name": "bondingCurveFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "bondingCurve",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeDistributor",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "twapPool",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "saleMemeTokenManager",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "frothMemeFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "creatorFeesClaimer",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "frothBurner",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "uniswapV3SwapAdapter",
            "type": "address"
          }
        ],
        "internalType": "struct BaseFrothMemeProtocolDeployer.OutputParams",
        "name": "_outputParams",
        "type": "tuple"
      }
    ],
    "name": "deploy",
    "outputs": [
      {
        "components": [
          {
            "internalType": "address",
            "name": "bondingCurveFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "bondingCurve",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "feeDistributor",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "twapPool",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "saleMemeTokenManager",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "frothMemeFactory",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "creatorFeesClaimer",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "frothBurner",
            "type": "address"
          },
          {
            "internalType": "address",
            "name": "uniswapV3SwapAdapter",
            "type": "address"
          }
        ],
        "internalType": "struct BaseFrothMemeProtocolDeployer.OutputParams",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "_uint256",
        "type": "uint256"
      }
    ],
    "name": "toString",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "_bytes32",
        "type": "bytes32"
      }
    ],
    "name": "toString",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {FeeDistributor} from "../../src/FeeDistributor.sol";
import {BaseFrothMemeProtocolDeployer} from "./BaseFrothMemeProtocolDeployer.sol";
import {ConstantProductBondingCurve} from "../../src/ConstantProductBondingCurve.sol";

contract FrothMemeProtocolDeployer01 is BaseFrothMemeProtocolDeployer {
    function deploy(InputParams memory _inputParams, OutputParams memory _outputParams)
        external
        override
        onlyOrchestrator
        returns (OutputParams memory)
    {
        _printInputParams(_inputParams);

        // _outputParams = _deployBondingCurveFactory(_inputParams, _outputParams);
        // _outputParams = _deployBondingCurve(_inputParams, _outputParams);
        _outputParams = _deployConstantProductBondingCurve(_inputParams, _outputParams);
        _outputParams = _deployFeeDistributor(_inputParams, _outputParams);

        return _outputParams;
    }

    function configure(InputParams calldata _inputParams, OutputParams calldata _outputParams)
        external
        override
        onlyOrchestrator
    {
        // _configureBondingCurveFactory(_inputParams, _outputParams);
        _configureFeeDistributor(_inputParams, _outputParams);
    }

    function _deployConstantProductBondingCurve(InputParams memory inputParams, OutputParams memory outputParams)
        internal
        returns (OutputParams memory)
    {
        // The factory's graduation vault cap and the curve's target must agree, otherwise
        // sales either graduate at the wrong price point or can never fill the vault.
        require(
            inputParams.bondingCurveParams.targetGraduation
                == inputParams.frothMemeFactoryParams.maxTotalContribution,
            "Curve target != factory maxTotalContribution"
        );
        // The curve's sellable supply must equal the factory's curve allocation (cap minus the
        // 200M LP reserve). If they diverge, graduation's `unsoldTokens < 1e18` check bricks or
        // the maxSupply-cap path strands the token below the graduation trigger.
        require(
            inputParams.bondingCurveParams.maxTokensSold == MEME_TOKEN_CAP - MEME_TOKEN_LIQUIDITY_AMOUNT,
            "maxTokensSold != cap - LP reserve"
        );
        outputParams.bondingCurve = address(
            new ConstantProductBondingCurve(
                inputParams.bondingCurveParams.initialVirtualNative,
                inputParams.bondingCurveParams.initialVirtualTokens,
                inputParams.bondingCurveParams.maxTokensSold,
                inputParams.bondingCurveParams.targetGraduation
            )
        );
        return outputParams;
    }

/*
    function _deployBondingCurve(InputParams memory inputParams, OutputParams memory outputParams)
        internal
        returns (OutputParams memory)
    {
        IBondingCurveFactory bondingCurveFactory = IBondingCurveFactory(outputParams.bondingCurveFactory);
        address bondingCurve = bondingCurveFactory.createBondingCurve(inputParams.A, inputParams.B);
        outputParams.bondingCurve = bondingCurve;
        return outputParams;
    }

    function _deployBondingCurveFactory(InputParams memory inputParams, OutputParams memory outputParams)
        internal
        returns (OutputParams memory)
    {
        outputParams.bondingCurveFactory =
            address(new BondingCurveFactory(inputParams.initialAdminAndOperator, inputParams.initialAdminAndOperator));
        return outputParams;
    }
    */

    function _deployFeeDistributor(InputParams memory inputParams, OutputParams memory outputParams)
        internal
        returns (OutputParams memory)
    {
        outputParams.feeDistributor =
            address(new FeeDistributor(inputParams.initialAdminAndOperator, inputParams.initialAdminAndOperator));
        return outputParams;
    }

    /*
    function _configureBondingCurveFactory(InputParams memory inputParams, OutputParams memory outputParams) internal {
        // Bonding curve factory
        BondingCurveFactory bondingCurveFactory = BondingCurveFactory(outputParams.bondingCurveFactory);

        if (inputParams.initialAdminAndOperator != inputParams.bondingCurveFactoryParams.finalOperator) {
            bondingCurveFactory.grantRole(
                bondingCurveFactory.OPERATOR_ROLE(), inputParams.bondingCurveFactoryParams.finalOperator
            );
            bondingCurveFactory.revokeRole(bondingCurveFactory.OPERATOR_ROLE(), inputParams.initialAdminAndOperator);
        }

        // Grant final admin role to bonding curve factory
        if (inputParams.initialAdminAndOperator != inputParams.bondingCurveFactoryParams.finalAdmin) {
            bondingCurveFactory.grantRole(
                bondingCurveFactory.DEFAULT_ADMIN_ROLE(), inputParams.bondingCurveFactoryParams.finalAdmin
            );
            bondingCurveFactory.revokeRole(
                bondingCurveFactory.DEFAULT_ADMIN_ROLE(), inputParams.initialAdminAndOperator
            );
        }
    }
    */

    function _configureFeeDistributor(InputParams memory inputParams, OutputParams memory outputParams) internal {
        // Fee distributor
        FeeDistributor feeDistributor = FeeDistributor(outputParams.feeDistributor);
        /*
        Froth.meme — TL;DR Fees + Rug System (for dev)
        - Mint Fee (FROTH)
            1,000 FROTH (adjustable via setMintFee())
            100% → team multisig
        - Trade Fee (1% on every buy/sell)
            50% → TWAP pool
            30% → team multisig
            15% → creator (claimable to dev wallet)
            5% → FROTH buyback (burned)
        - Graduation Fee (on bond success)
            2% of final native vault
            100% → TWAP pool
        - Rug (Failed Launch)
            At 7 days: if unbonded → auto-rug
            100% of vault native → TWAP pool
            No refunds. No user claims.
        - TWAP Pool
            Weekly TWAP buys for a random selected graduated token from factory
            60 micro-swaps via PunchSwap V2
            Funds: trade fees + rugs + grad fee
        - How Contracts Work
            FrothFactory → deploys Memecoin, takes mint fee
            BondingCurveRouter → buy/sell, applies 1% fee, calls FeeSplitter
            FeeSplitter → splits 50/30/15/5 + creator
            TWAPPool → holds native, executeTWAP() weekly
            FROTHBuyback → 2.5% fee → buys & burns FROTH  -- this can be just sent to protocol multisig
            GraduationManager → adds LP, burns 100%, 2% fee to TWAP
        */
        // Set fee params
        feeDistributor.setFeeBps(
            CREATOR_FEES_ON_BUYING_KEY, inputParams.feeDistributorParams.feeParams.creatorFeesOnBuyingFee
        );
        feeDistributor.setFeeBps(
            CREATOR_FEES_ON_SELLING_KEY, inputParams.feeDistributorParams.feeParams.creatorFeesOnSellingFee
        );
        feeDistributor.setFeeBps(TRADE_BUY_FEE_KEY, inputParams.feeDistributorParams.feeParams.tradeBuyFee);
        feeDistributor.setFeeBps(TRADE_SELL_FEE_KEY, inputParams.feeDistributorParams.feeParams.tradeSellFee);
        feeDistributor.setFeeBps(GRADUATION_FEE_KEY, inputParams.feeDistributorParams.feeParams.graduationFee);
        feeDistributor.setFeeBps(RUG_FEE_KEY, inputParams.feeDistributorParams.feeParams.rugFee);

        address[] memory createMemeFeeReceivers = new address[](1);
        createMemeFeeReceivers[0] = inputParams.feeDistributorParams.teamWallet;
        uint256[] memory createMemeFeeBps = new uint256[](1);
        createMemeFeeBps[0] = 100_00;
        feeDistributor.setDistributionKeyFees(CREATE_MEME_TOKEN_FEE_KEY, createMemeFeeReceivers, createMemeFeeBps);

        address[] memory tradeFeeReceivers = new address[](4);
        tradeFeeReceivers[0] = inputParams.feeDistributorParams.twapPool;
        tradeFeeReceivers[1] = inputParams.feeDistributorParams.teamWallet;
        tradeFeeReceivers[2] = outputParams.creatorFeesClaimer;
        tradeFeeReceivers[3] = outputParams.frothBurner;
        uint256[] memory tradeFeeBps = new uint256[](4);
        tradeFeeBps[0] = 50_00;
        tradeFeeBps[1] = 30_00;
        tradeFeeBps[2] = 15_00;
        tradeFeeBps[3] = 5_00;
        // The creator's slice of the trade-fee distribution (tradeFeeBps[2]) must equal the
        // CREATOR_FEES_ON_*_KEY bps so emitted/forwarded fee metadata matches the intended
        // economics. CreatorFeesClaimer uses its actual transferred share as authoritative.
        require(
            inputParams.feeDistributorParams.feeParams.creatorFeesOnBuyingFee == tradeFeeBps[2]
                && inputParams.feeDistributorParams.feeParams.creatorFeesOnSellingFee == tradeFeeBps[2],
            "creator fee key != claimer distribution slice"
        );
        feeDistributor.setDistributionKeyFees(TRADE_BUY_FEE_KEY, tradeFeeReceivers, tradeFeeBps);
        feeDistributor.setDistributionKeyFees(TRADE_SELL_FEE_KEY, tradeFeeReceivers, tradeFeeBps);

        address[] memory rugFeeReceivers = new address[](1);
        rugFeeReceivers[0] = inputParams.feeDistributorParams.twapPool;
        uint256[] memory rugFeeBps = new uint256[](1);
        rugFeeBps[0] = 100_00;
        feeDistributor.setDistributionKeyFees(RUG_FEE_KEY, rugFeeReceivers, rugFeeBps);

        address[] memory graduationFeeReceivers = new address[](1);
        graduationFeeReceivers[0] = inputParams.feeDistributorParams.twapPool;
        uint256[] memory graduationFeeBps = new uint256[](1);
        graduationFeeBps[0] = 100_00;
        feeDistributor.setDistributionKeyFees(GRADUATION_FEE_KEY, graduationFeeReceivers, graduationFeeBps);

        feeDistributor.grantRole(feeDistributor.OPERATOR_ROLE(), outputParams.frothMemeFactory);
        feeDistributor.grantRole(feeDistributor.OPERATOR_ROLE(), outputParams.saleMemeTokenManager);

        if (inputParams.initialAdminAndOperator != inputParams.feeDistributorParams.finalOperator) {
            feeDistributor.grantRole(feeDistributor.OPERATOR_ROLE(), inputParams.feeDistributorParams.finalOperator);
            feeDistributor.revokeRole(feeDistributor.OPERATOR_ROLE(), inputParams.initialAdminAndOperator);
        }

        // Grant final admin role to fee distributor
        if (inputParams.initialAdminAndOperator != inputParams.feeDistributorParams.finalAdmin) {
            feeDistributor.grantRole(feeDistributor.DEFAULT_ADMIN_ROLE(), inputParams.feeDistributorParams.finalAdmin);
            feeDistributor.revokeRole(feeDistributor.DEFAULT_ADMIN_ROLE(), inputParams.initialAdminAndOperator);
        }
    }
}
Chain explorer1844msChain node96ms