Blockchain / Global / Address

Contract

0xF2dfE329648F5c51F35B00c097e6fBD50B07F3f2

Balance
0 SOMI
Transactions sent
1
Type
Contract · 9,032 bytes of code

MigratorV3Upgradeable Verified

Compiler
solc 0.8.28+commit.7893614a
Language
Solidity
Optimization
Yes, 200 runs
EVM version
paris
License
—
Verified
2026-10-12

contracts/launchpad/MigratorV3Upgradeable.sol

and 12 more files

Solidity
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;

import "../interfaces/IAMMRouter.sol";
import "../interfaces/IAMMPairERC20.sol";
import "../interfaces/IAMMFactory.sol";
import "../interfaces/IBondingCurve.sol";
import "../interfaces/IBondingCurveFactory.sol";
import "../interfaces/IMigratorV3.sol";
import "../libraries/TransferHelper.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/IMigrationLocker.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

contract MigratorV3Upgradeable is Initializable, ReentrancyGuard, IMigratorV3 {
	using EnumerableSet for EnumerableSet.AddressSet;

	enum OperatorManage {
		Add,
		Remove
	}

	struct FundingTokenFee {
		uint256 fees;
		uint256 operateFees;
	}

	uint256 constant LOCK_SECONDS = 100 * 365 * 86400; // 100 years

	address private admin;
	address public feeTo;
	uint256 public fees; // fees for migrate native token launcher
	uint256 public MAX_FEES = 0.5 ether; // limit fees
	uint256 public operateFees; // only for migrate native token launcher
	address private _pendingOwner;
	uint256[9] __gap;
	mapping(address => bool) operators;
	IAMMFactory public factory;
	IAMMRouter public router;
	address public locker;
	address public weth;
	EnumerableSet.AddressSet private curvesReadyForMigration;
	EnumerableSet.AddressSet private _bondingCurveFactories;
	EnumerableSet.AddressSet private _curves;
	mapping(address fundingToken => FundingTokenFee) public fundingFees; // fees for migrate curve with funding token

	event Migrated(
		address indexed token0,
		address indexed token1,
		uint256 amount0,
		uint256 amount1,
		uint256 liquidity,
		address to
	);

	event OperatorsUpdated(address indexed operator, OperatorManage action);

	event FeeToUpdated(address indexed feeTo);

	event FeesUpdated(uint256 fees);

	event OperateFeesUpdated(uint256 operateFees);

	event LockerSetted(address indexed locker);

	event FundingFeesUpdated(address indexed launcher, FundingTokenFee fee);

	event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

	error FeesNotSet(address fundingToken);

	error OwnableUnauthorizedAccount(address account);

	modifier onlyAdmin() {
		require(msg.sender == admin, "Not admin");
		_;
	}

	modifier onlyOperator() {
		require(operators[msg.sender], "Not operator");
		_;
	}

	function initialize(address _admin, address _factory, address _router, address _weth) external initializer {
		require(_admin != address(0), "zero admin address");
		require(_router != address(0), "zero router address");
		admin = _admin;
		router = IAMMRouter(_router);
		factory = IAMMFactory(_factory);
		weth = _weth;
	}

	function transferOwnership(address newOwner) public onlyAdmin {
		_pendingOwner = newOwner;
	}

	function acceptOwnership() public virtual {
		address sender = msg.sender;
		if (_pendingOwner != sender) {
			revert OwnableUnauthorizedAccount(sender);
		}
		address oldOwner = admin;
		admin = sender;
		emit OwnershipTransferred(oldOwner, sender);
	}

	function addOperator(address _newOperator) external onlyAdmin {
		require(_newOperator != address(0), "zero address");
		require(!operators[_newOperator], "operator exists");
		operators[_newOperator] = true;
		emit OperatorsUpdated(_newOperator, OperatorManage.Add);
	}

	function removeOperator(address toRemove) external onlyAdmin {
		require(toRemove != address(0), "zero address");
		require(operators[toRemove], "operator not exists");
		operators[toRemove] = false;
		emit OperatorsUpdated(toRemove, OperatorManage.Remove);
	}

	function setFeeTo(address team) external onlyAdmin {
		require(team != address(0), "zero team address");
		feeTo = team;
		emit FeeToUpdated(feeTo);
	}

	function setFees(uint256 _fees) external onlyAdmin {
		fees = _fees;
		emit FeesUpdated(fees);
	}

	function setOperateFees(uint256 _operateFees) external onlyAdmin {
		require(_operateFees < fees, "out of the total fees");
		operateFees = _operateFees;
		emit OperateFeesUpdated(operateFees);
	}

	function setLocker(address _locker) external onlyAdmin {
		require(_locker != address(0), "zero address");
		locker = _locker;
		emit LockerSetted(_locker);
	}

	function setFundingFees(address fundingToken, FundingTokenFee calldata fee) external onlyAdmin {
		require(fundingToken != address(0), "zero launcher address");
		fundingFees[fundingToken] = fee;
		emit FundingFeesUpdated(fundingToken, fee);
	}

	function addBondingCurveFactory(address _factory) external onlyAdmin {
		require(_factory != address(0), "can not set zero address");
		require(_bondingCurveFactories.add(_factory), "already added");
	}

	function removeBondingCurveFactory(address _factory) external onlyAdmin {
		require(_factory != address(0), "can not set zero address");
		require(_bondingCurveFactories.remove(_factory), "not added");
	}

	function addCurve(address _curve) external {
		require(_bondingCurveFactories.contains(msg.sender), "not a registered factory");
		require(_curves.add(_curve), "already added");
	}

	function appendToReadyForMigration() external override returns(bool) {
		if (!_curves.contains(msg.sender)) {
			return false;
		}
		if (!IBondingCurve(msg.sender).isMarketCapReached()){
			return false;
		}
		_curves.remove(msg.sender);
		// no need to check if it's already in the set, because it will be added again
		return curvesReadyForMigration.add(msg.sender);
	}

	function addCurveFromReadyForMigration(address curve) external onlyAdmin {
		require(curve != address(0), "zero curve address");
		require(curvesReadyForMigration.add(curve), "curve is already in set");
	}

	function removeCurveFromReadyForMigration(address curve) external onlyAdmin {
		require(curve != address(0), "zero curve address");
		require(curvesReadyForMigration.remove(curve), "curve not in set");
	}

	function readyForMigrationLength() external view returns (uint256) {
		return curvesReadyForMigration.length();
	}

	function readyForMigrationAt(uint256 index) external view returns (address) {
		return curvesReadyForMigration.at(index);
	}

	// @dev to the owner of lp, zero address or MigrationLocker
	function migrate(address curve, address to, address operator) external override onlyOperator nonReentrant {
		require(curve != address(0), "zero curve address");
		require(operator != address(0), "zero operator address");
		bool lockLp = locker != address(0);

		address token0 = IBondingCurve(curve).token0();
		address token1 = IBondingCurve(curve).token1();

		(uint256 amount0, uint256 amount1) = IBondingCurve(curve).removeLiquidity();
		if (amount0 == 0 || amount1 == 0) {
			return;
		}
		if (feeTo != address(0)) {
			FundingTokenFee memory fee = fundingFees[token1];
			if (fee.fees == 0) {
				revert FeesNotSet(token1);
			}
			amount1 -= fee.fees;
			TransferHelper.safeTransfer(token1, feeTo, fee.fees);
			if (fee.operateFees != 0) {
				amount1 -= fee.operateFees;
				TransferHelper.safeTransfer(token1, operator, fee.operateFees);
			}
		}
		TransferHelper.safeApprove(token0, address(router), amount0);
		TransferHelper.safeApprove(token1, address(router), amount1);

		(uint256 amountToken, uint256 amountETH, uint256 liquidity) = router.addLiquidity(
			token0,
			token1,
			amount0,
			amount1,
			0,
			0,
			lockLp ? address(this) : to,
			block.timestamp + 86400
		);
		// no need to check if it's the list of tokens ready for migration
		curvesReadyForMigration.remove(curve);
		if (lockLp) {
			address lpToken = factory.getPair(token0, token1);
			TransferHelper.safeApprove(lpToken, locker, liquidity);
			IMigrationLocker(locker).lockLPToken(lpToken, to, liquidity, LOCK_SECONDS);
			emit Migrated(token0, token1, amountToken, amountETH, liquidity, locker);
		} else {
			emit Migrated(token0, token1, amountToken, amountETH, liquidity, to);
		}
	}

	function migrateETH(address curve, address to, address operator) external payable override onlyOperator nonReentrant {
		require(curve != address(0), "zero curve address");
		require(operator != address(0), "zero operator address");
		bool lockLp = locker != address(0);

		address token = IBondingCurve(curve).token0();

		(uint256 amount0, uint256 amount1) = IBondingCurve(curve).removeLiquidity();

		if (feeTo != address(0)) {
			if (fees == 0) {
				revert FeesNotSet(weth);
			}
			TransferHelper.safeTransferETH(feeTo, fees - operateFees);
			if (operateFees != 0) {
				TransferHelper.safeTransferETH(operator, operateFees);
			}
		}
		TransferHelper.safeApprove(token, address(router), amount0);

		(uint256 amountToken, uint256 amountETH, uint256 liquidity) = router.addLiquidityETH{value: amount1 - fees}(
			token,
			amount0,
			0,
			0,
			lockLp ? address(this) : to,
			block.timestamp + 86400
		);
		// no need to check if it's the list of tokens ready for migration
		curvesReadyForMigration.remove(curve);
		if (lockLp) {
			address lpToken = factory.getPair(token, weth);
			require(lpToken != address(0), "NOT AMM");
			TransferHelper.safeApprove(lpToken, locker, liquidity);
			IMigrationLocker(locker).lockLPToken(lpToken, to, liquidity, LOCK_SECONDS);
			emit Migrated(token, weth, amountToken, amountETH, liquidity, locker);
		} else {
			emit Migrated(token, weth, amountToken, amountETH, liquidity, to);
		}
	}

	function claimeLpReward(address _lpToken, address _to) external onlyOperator nonReentrant {
		uint256[] memory lockIDs = IMigrationLocker(locker).allLockIDs(_lpToken);
		for (uint256 i = 0; i < lockIDs.length; ++i) {
			IMigrationLocker(locker).claimeLpReward(_lpToken, i, lockIDs[i], _to);
		}
	}

	receive() external payable {}
}

Other files

  • @openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
     *
     * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
     * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
     * case an upgrade adds a module that needs to be initialized.
     *
     * For example:
     *
     * [.hljs-theme-light.nopadding]
     * ```solidity
     * contract MyToken is ERC20Upgradeable {
     *     function initialize() initializer public {
     *         __ERC20_init("MyToken", "MTK");
     *     }
     * }
     *
     * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
     *     function initializeV2() reinitializer(2) public {
     *         __ERC20Permit_init("MyToken");
     *     }
     * }
     * ```
     *
     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
     *
     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
     *
     * [CAUTION]
     * ====
     * Avoid leaving a contract uninitialized.
     *
     * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
     * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
     * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
     *
     * [.hljs-theme-light.nopadding]
     * ```
     * /// @custom:oz-upgrades-unsafe-allow constructor
     * constructor() {
     *     _disableInitializers();
     * }
     * ```
     * ====
     */
    abstract contract Initializable {
        /**
         * @dev Storage of the initializable contract.
         *
         * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
         * when using with upgradeable contracts.
         *
         * @custom:storage-location erc7201:openzeppelin.storage.Initializable
         */
        struct InitializableStorage {
            /**
             * @dev Indicates that the contract has been initialized.
             */
            uint64 _initialized;
            /**
             * @dev Indicates that the contract is in the process of being initialized.
             */
            bool _initializing;
        }
    
        // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
        bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
    
        /**
         * @dev The contract is already initialized.
         */
        error InvalidInitialization();
    
        /**
         * @dev The contract is not initializing.
         */
        error NotInitializing();
    
        /**
         * @dev Triggered when the contract has been initialized or reinitialized.
         */
        event Initialized(uint64 version);
    
        /**
         * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
         * `onlyInitializing` functions can be used to initialize parent contracts.
         *
         * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
         * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
         * production.
         *
         * Emits an {Initialized} event.
         */
        modifier initializer() {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
    
            // Cache values to avoid duplicated sloads
            bool isTopLevelCall = !$._initializing;
            uint64 initialized = $._initialized;
    
            // Allowed calls:
            // - initialSetup: the contract is not in the initializing state and no previous version was
            //                 initialized
            // - construction: the contract is initialized at version 1 (no reininitialization) and the
            //                 current contract is just being deployed
            bool initialSetup = initialized == 0 && isTopLevelCall;
            bool construction = initialized == 1 && address(this).code.length == 0;
    
            if (!initialSetup && !construction) {
                revert InvalidInitialization();
            }
            $._initialized = 1;
            if (isTopLevelCall) {
                $._initializing = true;
            }
            _;
            if (isTopLevelCall) {
                $._initializing = false;
                emit Initialized(1);
            }
        }
    
        /**
         * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
         * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
         * used to initialize parent contracts.
         *
         * A reinitializer may be used after the original initialization step. This is essential to configure modules that
         * are added through upgrades and that require initialization.
         *
         * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
         * cannot be nested. If one is invoked in the context of another, execution will revert.
         *
         * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
         * a contract, executing them in the right order is up to the developer or operator.
         *
         * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
         *
         * Emits an {Initialized} event.
         */
        modifier reinitializer(uint64 version) {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
    
            if ($._initializing || $._initialized >= version) {
                revert InvalidInitialization();
            }
            $._initialized = version;
            $._initializing = true;
            _;
            $._initializing = false;
            emit Initialized(version);
        }
    
        /**
         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
         * {initializer} and {reinitializer} modifiers, directly or indirectly.
         */
        modifier onlyInitializing() {
            _checkInitializing();
            _;
        }
    
        /**
         * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
         */
        function _checkInitializing() internal view virtual {
            if (!_isInitializing()) {
                revert NotInitializing();
            }
        }
    
        /**
         * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
         * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
         * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
         * through proxies.
         *
         * Emits an {Initialized} event the first time it is successfully executed.
         */
        function _disableInitializers() internal virtual {
            // solhint-disable-next-line var-name-mixedcase
            InitializableStorage storage $ = _getInitializableStorage();
    
            if ($._initializing) {
                revert InvalidInitialization();
            }
            if ($._initialized != type(uint64).max) {
                $._initialized = type(uint64).max;
                emit Initialized(type(uint64).max);
            }
        }
    
        /**
         * @dev Returns the highest version that has been initialized. See {reinitializer}.
         */
        function _getInitializedVersion() internal view returns (uint64) {
            return _getInitializableStorage()._initialized;
        }
    
        /**
         * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
         */
        function _isInitializing() internal view returns (bool) {
            return _getInitializableStorage()._initializing;
        }
    
        /**
         * @dev Returns a pointer to the storage namespace.
         */
        // solhint-disable-next-line var-name-mixedcase
        function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
            assembly {
                $.slot := INITIALIZABLE_STORAGE
            }
        }
    }
    
  • @openzeppelin/contracts/token/ERC20/IERC20.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    
        /**
         * @dev Returns the value of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns the value of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
    
        /**
         * @dev Moves a `value` amount of tokens from the caller's account to `to`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address to, uint256 value) external returns (bool);
    
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
    
        /**
         * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
         * caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 value) external returns (bool);
    
        /**
         * @dev Moves a `value` amount of tokens from `from` to `to` using the
         * allowance mechanism. `value` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address from, address to, uint256 value) external returns (bool);
    }
    
  • @openzeppelin/contracts/utils/ReentrancyGuard.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Contract module that helps prevent reentrant calls to a function.
     *
     * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
     * available, which can be applied to functions to make sure there are no nested
     * (reentrant) calls to them.
     *
     * Note that because there is a single `nonReentrant` guard, functions marked as
     * `nonReentrant` may not call one another. This can be worked around by making
     * those functions `private`, and then adding `external` `nonReentrant` entry
     * points to them.
     *
     * TIP: If you would like to learn more about reentrancy and alternative ways
     * to protect against it, check out our blog post
     * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
     */
    abstract contract ReentrancyGuard {
        // Booleans are more expensive than uint256 or any type that takes up a full
        // word because each write operation emits an extra SLOAD to first read the
        // slot's contents, replace the bits taken up by the boolean, and then write
        // back. This is the compiler's defense against contract upgrades and
        // pointer aliasing, and it cannot be disabled.
    
        // The values being non-zero value makes deployment a bit more expensive,
        // but in exchange the refund on every call to nonReentrant will be lower in
        // amount. Since refunds are capped to a percentage of the total
        // transaction's gas, it is best to keep them low in cases like this one, to
        // increase the likelihood of the full refund coming into effect.
        uint256 private constant NOT_ENTERED = 1;
        uint256 private constant ENTERED = 2;
    
        uint256 private _status;
    
        /**
         * @dev Unauthorized reentrant call.
         */
        error ReentrancyGuardReentrantCall();
    
        constructor() {
            _status = NOT_ENTERED;
        }
    
        /**
         * @dev Prevents a contract from calling itself, directly or indirectly.
         * Calling a `nonReentrant` function from another `nonReentrant`
         * function is not supported. It is possible to prevent this from happening
         * by making the `nonReentrant` function external, and making it call a
         * `private` function that does the actual work.
         */
        modifier nonReentrant() {
            _nonReentrantBefore();
            _;
            _nonReentrantAfter();
        }
    
        function _nonReentrantBefore() private {
            // On the first call to nonReentrant, _status will be NOT_ENTERED
            if (_status == ENTERED) {
                revert ReentrancyGuardReentrantCall();
            }
    
            // Any calls to nonReentrant after this point will fail
            _status = ENTERED;
        }
    
        function _nonReentrantAfter() private {
            // By storing the original value once again, a refund is triggered (see
            // https://eips.ethereum.org/EIPS/eip-2200)
            _status = NOT_ENTERED;
        }
    
        /**
         * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
         * `nonReentrant` function in the call stack.
         */
        function _reentrancyGuardEntered() internal view returns (bool) {
            return _status == ENTERED;
        }
    }
    
  • @openzeppelin/contracts/utils/structs/EnumerableSet.sol
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
    // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
    
    pragma solidity ^0.8.20;
    
    /**
     * @dev Library for managing
     * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
     * types.
     *
     * Sets have the following properties:
     *
     * - Elements are added, removed, and checked for existence in constant time
     * (O(1)).
     * - Elements are enumerated in O(n). No guarantees are made on the ordering.
     *
     * ```solidity
     * contract Example {
     *     // Add the library methods
     *     using EnumerableSet for EnumerableSet.AddressSet;
     *
     *     // Declare a set state variable
     *     EnumerableSet.AddressSet private mySet;
     * }
     * ```
     *
     * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
     * and `uint256` (`UintSet`) are supported.
     *
     * [WARNING]
     * ====
     * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
     * unusable.
     * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
     *
     * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
     * array of EnumerableSet.
     * ====
     */
    library EnumerableSet {
        // To implement this library for multiple types with as little code
        // repetition as possible, we write it in terms of a generic Set type with
        // bytes32 values.
        // The Set implementation uses private functions, and user-facing
        // implementations (such as AddressSet) are just wrappers around the
        // underlying Set.
        // This means that we can only create new EnumerableSets for types that fit
        // in bytes32.
    
        struct Set {
            // Storage of set values
            bytes32[] _values;
            // Position is the index of the value in the `values` array plus 1.
            // Position 0 is used to mean a value is not in the set.
            mapping(bytes32 value => uint256) _positions;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function _add(Set storage set, bytes32 value) private returns (bool) {
            if (!_contains(set, value)) {
                set._values.push(value);
                // The value is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                set._positions[value] = set._values.length;
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function _remove(Set storage set, bytes32 value) private returns (bool) {
            // We cache the value's position to prevent multiple reads from the same storage slot
            uint256 position = set._positions[value];
    
            if (position != 0) {
                // Equivalent to contains(set, value)
                // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                // the array, and then remove the last element (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
    
                uint256 valueIndex = position - 1;
                uint256 lastIndex = set._values.length - 1;
    
                if (valueIndex != lastIndex) {
                    bytes32 lastValue = set._values[lastIndex];
    
                    // Move the lastValue to the index where the value to delete is
                    set._values[valueIndex] = lastValue;
                    // Update the tracked position of the lastValue (that was just moved)
                    set._positions[lastValue] = position;
                }
    
                // Delete the slot where the moved value was stored
                set._values.pop();
    
                // Delete the tracked position for the deleted slot
                delete set._positions[value];
    
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function _contains(Set storage set, bytes32 value) private view returns (bool) {
            return set._positions[value] != 0;
        }
    
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function _length(Set storage set) private view returns (uint256) {
            return set._values.length;
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function _at(Set storage set, uint256 index) private view returns (bytes32) {
            return set._values[index];
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function _values(Set storage set) private view returns (bytes32[] memory) {
            return set._values;
        }
    
        // Bytes32Set
    
        struct Bytes32Set {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
            return _add(set._inner, value);
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
            return _remove(set._inner, value);
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
            return _contains(set._inner, value);
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(Bytes32Set storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
            return _at(set._inner, index);
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
            bytes32[] memory store = _values(set._inner);
            bytes32[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    
        // AddressSet
    
        struct AddressSet {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(AddressSet storage set, address value) internal returns (bool) {
            return _add(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(AddressSet storage set, address value) internal returns (bool) {
            return _remove(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(AddressSet storage set, address value) internal view returns (bool) {
            return _contains(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(AddressSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(AddressSet storage set, uint256 index) internal view returns (address) {
            return address(uint160(uint256(_at(set._inner, index))));
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(AddressSet storage set) internal view returns (address[] memory) {
            bytes32[] memory store = _values(set._inner);
            address[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    
        // UintSet
    
        struct UintSet {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(UintSet storage set, uint256 value) internal returns (bool) {
            return _add(set._inner, bytes32(value));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(UintSet storage set, uint256 value) internal returns (bool) {
            return _remove(set._inner, bytes32(value));
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(UintSet storage set, uint256 value) internal view returns (bool) {
            return _contains(set._inner, bytes32(value));
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(UintSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(UintSet storage set, uint256 index) internal view returns (uint256) {
            return uint256(_at(set._inner, index));
        }
    
        /**
         * @dev Return the entire set in an array
         *
         * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
         * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
         * this function has an unbounded cost, and using it as part of a state-changing function may render the function
         * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
         */
        function values(UintSet storage set) internal view returns (uint256[] memory) {
            bytes32[] memory store = _values(set._inner);
            uint256[] memory result;
    
            /// @solidity memory-safe-assembly
            assembly {
                result := store
            }
    
            return result;
        }
    }
    
  • contracts/interfaces/IAMMFactory.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity ^0.8.24;
    
    interface IAMMFactory {
    	event PairCreated(
    		address indexed token0,
    		address indexed token1,
    		address pair,
    		uint
    	);
    	function getPair(
    		address tokenA,
    		address tokenB
    	) external view returns (address pair);
    	function createPair(
    		address tokenA,
    		address tokenB
    	) external returns (address pair);
    	function allPairs(uint) external view returns (address pair);
    	function allPairsLength() external view returns (uint);
    }
    
  • contracts/interfaces/IAMMPairERC20.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity ^0.8.24;
    
    interface IAMMPairERC20 {
    	event Approval(address indexed owner, address indexed spender, uint value);
        event Transfer(address indexed from, address indexed to, uint value);
    
        function name() external pure returns (string memory);
        function symbol() external pure returns (string memory);
        function decimals() external pure returns (uint8);
        function totalSupply() external view returns (uint);
        function balanceOf(address owner) external view returns (uint);
        function allowance(address owner, address spender) external view returns (uint);
    
        function approve(address spender, uint value) external returns (bool);
        function transfer(address to, uint value) external returns (bool);
        function transferFrom(address from, address to, uint value) external returns (bool);
    
        function DOMAIN_SEPARATOR() external view returns (bytes32);
        function PERMIT_TYPEHASH() external pure returns (bytes32);
        function nonces(address owner) external view returns (uint);
    
        function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
    
        event Mint(address indexed sender, uint amount0, uint amount1);
        event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
        event Swap(
            address indexed sender,
            uint amount0In,
            uint amount1In,
            uint amount0Out,
            uint amount1Out,
            address indexed to
        );
        event Sync(uint112 reserve0, uint112 reserve1);
    
        function MINIMUM_LIQUIDITY() external pure returns (uint);
        function factory() external view returns (address);
        function token0() external view returns (address);
        function token1() external view returns (address);
        function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
        function price0CumulativeLast() external view returns (uint);
        function price1CumulativeLast() external view returns (uint);
        function kLast() external view returns (uint);
    
        function mint(address to) external returns (uint liquidity);
        function burn(address to) external returns (uint amount0, uint amount1);
        function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
        function skim(address to) external;
        function sync() external;
    
        function initialize(address, address) external;
    }
    
  • contracts/interfaces/IAMMRouter.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity >=0.8.0;
    
    interface IAMMRouter {
        function addLiquidity(
            address tokenA,
            address tokenB,
            uint amountADesired,
            uint amountBDesired,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB, uint liquidity);
        function addLiquidityETH(
            address token,            
            uint amountTokenDesired,  
            uint amountTokenMin,     
            uint amountETHMin,        
            address to,               
            uint deadline            
        ) external payable returns (uint amountToken, uint amountETH, uint liquidity);
    }
  • contracts/interfaces/IBondingCurve.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity ^0.8.24;
    
    interface IBondingCurve {
    	function initialize(address token0, address token1, address migrator) external;
    	function buy(uint256 amount, uint256 maxCost) external;
    	function sell(uint256 amount, uint256 minOut) external;
    	function removeLiquidity() external returns (uint256 amount0, uint256 amount1);
    	function migrateToken() external returns (uint256 amount);
    	function token0() external view returns (address);
    	function token1() external view returns (address);
    	function getReserves() external view returns (uint, uint);
      function isMarketCapReached() external view returns(bool);
    	function factory() external view returns (address);
    }
    
  • contracts/interfaces/IBondingCurveFactory.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity ^0.8.24;
    
    interface IBondingCurveFactory {
    	function allCurveLength() external view returns (uint);
    	function allPairs(uint) external view returns (address);
    	function getCurve(address token0, address token1) external view returns (address);
    }
    
  • contracts/interfaces/IMigrationLocker.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity >=0.8.20;
    
    interface IMigrationLocker {
        struct TokenLock {
            uint256 lockDate;
            uint256 unLockDate;
            uint256 amount; // the current amount of liquidity position
            uint256 remainAmount0; // the remaining amount of token0
            uint256 remainAmount1; // the remaining amount of token1
            uint256 k; // the snapshot k of the lp token
            uint256 lockID;
            address owner;
            uint256 updateTimestamp;
        }
    
        event Deposit(
            address indexed lpToken,
            address indexed user,
            uint256 amount,
            TokenLock lock
        );
        event Withdraw(
            address indexed lpToken,
            address indexed user,
            uint256 amount,
            TokenLock lock
        );
        event LockUpdated(address indexed lpToken, TokenLock lock);
        event RewardClaimed(address indexed token0, address indexed token1, uint256 amount0, uint256 amount1);
    
        function lockLPToken(
            address lpToken,
            address withdrawer,
            uint256 amount,
            uint256 unlockDate
        ) external;
    
        function claimeLpReward(
            address _lpToken,
            uint256 _index,
            uint256 _lockID,
            address _to
        ) external;
    
    		function allLockIDs(
            address _lpToken
        ) external view returns (uint256[] memory lockIDs);
    }
    
  • contracts/interfaces/IMigratorV3.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity ^0.8.24;
    
    interface IMigratorV3 {
      function migrate(address curve, address to, address operator) external;
      function migrateETH(address curve, address to, address operator) external payable;
      function readyForMigrationLength() external view returns (uint256);
      function readyForMigrationAt(uint256 index) external view returns (address);
      function addCurve(address _curve) external;
      function appendToReadyForMigration() external returns (bool);
    }
  • contracts/libraries/TransferHelper.sol
    // SPDX-License-Identifier: BUSL-1.1
    pragma solidity ^0.8.24;
    
    // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
    library TransferHelper {
    	function safeApprove(address token, address to, uint value) internal {
    		// bytes4(keccak256(bytes('approve(address,uint256)')));
    		(bool success, bytes memory data) = token.call(
    			abi.encodeWithSelector(0x095ea7b3, to, value)
    		);
    		require(
    			success && (data.length == 0 || abi.decode(data, (bool))),
    			"APPROVE_FAILED"
    		);
    	}
    
    	function safeTransfer(address token, address to, uint value) internal {
    		// bytes4(keccak256(bytes('transfer(address,uint256)')));
    		(bool success, bytes memory data) = token.call(
    			abi.encodeWithSelector(0xa9059cbb, to, value)
    		);
    		require(
    			success && (data.length == 0 || abi.decode(data, (bool))),
    			"TRANSFER_FAILED"
    		);
    	}
    
    	function safeTransferFrom(
    		address token,
    		address from,
    		address to,
    		uint value
    	) internal {
    		// bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
    		(bool success, bytes memory data) = token.call(
    			abi.encodeWithSelector(0x23b872dd, from, to, value)
    		);
    		require(
    			success && (data.length == 0 || abi.decode(data, (bool))),
    			"TRANSFER_FROM_FAILED"
    		);
    	}
    
    	function safeTransferETH(address to, uint value) internal {
    		(bool success, ) = to.call{value: value}(new bytes(0));
    		require(success, "ETH_TRANSFER_FAILED");
    	}
    }
    
ABI · 45 entries
json
[
  {
    "name": "FeesNotSet",
    "type": "error",
    "inputs": [
      {
        "name": "fundingToken",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "name": "InvalidInitialization",
    "type": "error",
    "inputs": []
  },
  {
    "name": "NotInitializing",
    "type": "error",
    "inputs": []
  },
  {
    "name": "OwnableUnauthorizedAccount",
    "type": "error",
    "inputs": [
      {
        "name": "account",
        "type": "address",
        "internalType": "address"
      }
    ]
  },
  {
    "name": "ReentrancyGuardReentrantCall",
    "type": "error",
    "inputs": []
  },
  {
    "name": "FeeToUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "feeTo",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "FeesUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "fees",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "FundingFeesUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "launcher",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "fee",
        "type": "tuple",
        "indexed": false,
        "components": [
          {
            "name": "fees",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "operateFees",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct MigratorV3Upgradeable.FundingTokenFee"
      }
    ],
    "anonymous": false
  },
  {
    "name": "Initialized",
    "type": "event",
    "inputs": [
      {
        "name": "version",
        "type": "uint64",
        "indexed": false,
        "internalType": "uint64"
      }
    ],
    "anonymous": false
  },
  {
    "name": "LockerSetted",
    "type": "event",
    "inputs": [
      {
        "name": "locker",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "Migrated",
    "type": "event",
    "inputs": [
      {
        "name": "token0",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "token1",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "amount0",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "amount1",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "liquidity",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      },
      {
        "name": "to",
        "type": "address",
        "indexed": false,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OperateFeesUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "operateFees",
        "type": "uint256",
        "indexed": false,
        "internalType": "uint256"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OperatorsUpdated",
    "type": "event",
    "inputs": [
      {
        "name": "operator",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "action",
        "type": "uint8",
        "indexed": false,
        "internalType": "enum MigratorV3Upgradeable.OperatorManage"
      }
    ],
    "anonymous": false
  },
  {
    "name": "OwnershipTransferred",
    "type": "event",
    "inputs": [
      {
        "name": "previousOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      },
      {
        "name": "newOwner",
        "type": "address",
        "indexed": true,
        "internalType": "address"
      }
    ],
    "anonymous": false
  },
  {
    "name": "MAX_FEES",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "acceptOwnership",
    "type": "function",
    "inputs": [],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "addBondingCurveFactory",
    "type": "function",
    "inputs": [
      {
        "name": "_factory",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "addCurve",
    "type": "function",
    "inputs": [
      {
        "name": "_curve",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "addCurveFromReadyForMigration",
    "type": "function",
    "inputs": [
      {
        "name": "curve",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "addOperator",
    "type": "function",
    "inputs": [
      {
        "name": "_newOperator",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "appendToReadyForMigration",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "bool",
        "internalType": "bool"
      }
    ],
    "stateMutability": "nonpayable"
  },
  {
    "name": "claimeLpReward",
    "type": "function",
    "inputs": [
      {
        "name": "_lpToken",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_to",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "factory",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract IAMMFactory"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "feeTo",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "fees",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "fundingFees",
    "type": "function",
    "inputs": [
      {
        "name": "fundingToken",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [
      {
        "name": "fees",
        "type": "uint256",
        "internalType": "uint256"
      },
      {
        "name": "operateFees",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "initialize",
    "type": "function",
    "inputs": [
      {
        "name": "_admin",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_factory",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_router",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "_weth",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "locker",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "migrate",
    "type": "function",
    "inputs": [
      {
        "name": "curve",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "to",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "operator",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "migrateETH",
    "type": "function",
    "inputs": [
      {
        "name": "curve",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "to",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "operator",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "payable"
  },
  {
    "name": "operateFees",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "readyForMigrationAt",
    "type": "function",
    "inputs": [
      {
        "name": "index",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "readyForMigrationLength",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "removeBondingCurveFactory",
    "type": "function",
    "inputs": [
      {
        "name": "_factory",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "removeCurveFromReadyForMigration",
    "type": "function",
    "inputs": [
      {
        "name": "curve",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "removeOperator",
    "type": "function",
    "inputs": [
      {
        "name": "toRemove",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "router",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "contract IAMMRouter"
      }
    ],
    "stateMutability": "view"
  },
  {
    "name": "setFeeTo",
    "type": "function",
    "inputs": [
      {
        "name": "team",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setFees",
    "type": "function",
    "inputs": [
      {
        "name": "_fees",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setFundingFees",
    "type": "function",
    "inputs": [
      {
        "name": "fundingToken",
        "type": "address",
        "internalType": "address"
      },
      {
        "name": "fee",
        "type": "tuple",
        "components": [
          {
            "name": "fees",
            "type": "uint256",
            "internalType": "uint256"
          },
          {
            "name": "operateFees",
            "type": "uint256",
            "internalType": "uint256"
          }
        ],
        "internalType": "struct MigratorV3Upgradeable.FundingTokenFee"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setLocker",
    "type": "function",
    "inputs": [
      {
        "name": "_locker",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "setOperateFees",
    "type": "function",
    "inputs": [
      {
        "name": "_operateFees",
        "type": "uint256",
        "internalType": "uint256"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "transferOwnership",
    "type": "function",
    "inputs": [
      {
        "name": "newOwner",
        "type": "address",
        "internalType": "address"
      }
    ],
    "outputs": [],
    "stateMutability": "nonpayable"
  },
  {
    "name": "weth",
    "type": "function",
    "inputs": [],
    "outputs": [
      {
        "name": "",
        "type": "address",
        "internalType": "address"
      }
    ],
    "stateMutability": "view"
  },
  {
    "type": "receive",
    "stateMutability": "payable"
  }
]