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"
}
]