ETH Price: $2,950.27 (-0.08%)

Contract Diff Checker

Contract Name:
SyncSwapPoolMaster

Contract Source Code:

// SPDX-License-Identifier: AGPL-3.0-or-later AND MIT

// File contracts/interfaces/master/IFeeManager.sol

// Original license: SPDX_License_Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

/// @notice The manager contract to control fees.
/// Management functions are omitted.
interface IFeeManager {
    function getSwapFee(
        address pool,
        address sender,
        address tokenIn,
        address tokenOut,
        bytes calldata data
    ) external view returns (uint24);

    function getProtocolFee(address pool) external view returns (uint24);

    function getFeeRecipient() external view returns (address);
}


// File contracts/interfaces/master/IForwarderRegistry.sol

// Original license: SPDX_License_Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IForwarderRegistry {
    function isForwarder(address forwarder) external view returns (bool);
}


// File contracts/interfaces/master/IPoolMaster.sol

// Original license: SPDX_License_Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;
/// @dev The master contract to create pools and manage whitelisted factories.
/// Inheriting the fee manager interface to support fee queries.
interface IPoolMaster is IFeeManager, IForwarderRegistry {
    event SetFactoryWhitelisted(address indexed factory, bool whitelisted);

    event RegisterPool(
        address indexed factory,
        address indexed pool,
        uint16 indexed poolType,
        bytes data
    );

    event UpdateForwarderRegistry(address indexed newForwarderRegistry);

    event UpdateFeeManager(address indexed newFeeManager);

    function wETH() external view returns (address);

    function vault() external view returns (address);

    function feeManager() external view returns (address);

    function pools(uint) external view returns (address);

    function poolsLength() external view returns (uint);

    // Forwarder Registry
    function setForwarderRegistry(address) external;

    // Fees
    function setFeeManager(address) external;

    // Factories
    function isFactoryWhitelisted(address) external view returns (bool);

    function setFactoryWhitelisted(address factory, bool whitelisted) external;

    // Pools
    function isPool(address) external view returns (bool);

    function getPool(bytes32) external view returns (address);

    function createPool(address factory, bytes calldata data) external returns (address pool);

    function registerPool(address pool, uint16 poolType, bytes calldata data, address token0, address token1) external;
}


// File contracts/libraries/Ownable.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable {
    address private _owner;

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

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(msg.sender);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == msg.sender, "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}


// File contracts/libraries/Ownable2Step.sol

// Original license: SPDX_License_Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)

pragma solidity ^0.8.0;
/**
 * @dev Contract module which provides access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership} and {acceptOwnership}.
 *
 * This module is used through inheritance. It will make available all functions
 * from parent (Ownable).
 */
abstract contract Ownable2Step is Ownable {
    address private _pendingOwner;

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

    /**
     * @dev Returns the address of the pending owner.
     */
    function pendingOwner() public view virtual returns (address) {
        return _pendingOwner;
    }

    /**
     * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual override onlyOwner {
        _pendingOwner = newOwner;
        emit OwnershipTransferStarted(owner(), newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual override {
        delete _pendingOwner;
        super._transferOwnership(newOwner);
    }

    /**
     * @dev The new owner accepts the ownership transfer.
     */
    function acceptOwnership() public virtual {
        require(pendingOwner() == msg.sender, "Ownable2Step: caller is not the new owner");
        _transferOwnership(msg.sender);
    }
}


// File contracts/interfaces/factory/IPoolFactory.sol

// Original license: SPDX_License_Identifier: AGPL-3.0-or-later

pragma solidity >=0.5.0;

interface IPoolFactory {
    function master() external view returns (address);

    function getDeployData() external view returns (bytes memory);

    function createPool(bytes calldata data) external returns (address pool);
}


// File contracts/master/SyncSwapPoolMaster.sol

// Original license: SPDX_License_Identifier: AGPL-3.0-or-later

pragma solidity ^0.8.0;
error NotWhitelistedFactory();
error PoolAlreadyExists();

/// @notice The pool master manages swap fees for pools, whitelist for factories,
/// protocol fee and pool registry.
///
/// It accepts pool registers from whitelisted factories, with the pool data on pool
/// creation, to enable querying of the existence or fees of a pool by address or config.
///
/// This contract provides a unified interface to query and manage fees across
/// different pool types, and a unique registry for all pools.
///
contract SyncSwapPoolMaster is IPoolMaster, Ownable2Step {

    address public immutable override wETH;

    /// @dev The vault that holds funds.
    address public immutable override vault;

    /// @dev The registry of forwarder.
    address public forwarderRegistry;

    /// @dev The fee manager.
    address public override feeManager;

    /// @dev Whether an address is a factory.
    mapping(address => bool) public override isFactoryWhitelisted;

    /// @dev Whether an address is a pool.
    mapping(address => bool) public override isPool;

    /// @dev Pools by hash of its config.
    mapping(bytes32 => address) public override getPool;

    struct PoolInfo {
        address pool;
        uint16 poolType;
    }
    mapping(address => mapping(address => PoolInfo[])) public pairPools;

    address[] public override pools;

    constructor(address _wETH, address _vault, address _forwarderRegistry, address _feeManager) {
        wETH = _wETH;
        vault = _vault;
        forwarderRegistry = _forwarderRegistry;
        feeManager = _feeManager;
    }

    function poolsLength() external view override returns (uint) {
        return pools.length;
    }

    function _hashPoolConfig(uint16 poolType, address token0, address token1) private pure returns (bytes32 hash) {
        hash = keccak256(abi.encode(poolType, token0, token1));
    }

    function _sortTokens(address tokenA, address tokenB) private pure returns (address token0, address token1) {
        if (tokenA < tokenB) {
            (token0, token1) = (tokenA, tokenB);
        } else {
            (token0, token1) = (tokenB, tokenA);
        }
    }

    function getPoolByTokens(uint16 poolType, address tokenA, address tokenB) external view returns (address) {
        (tokenA, tokenB) = _sortTokens(tokenA, tokenB);
        return getPool[_hashPoolConfig(poolType, tokenA, tokenB)];
    }

    function pairPoolsLength(address tokenA, address tokenB) external view returns (uint) {
        (tokenA, tokenB) = _sortTokens(tokenA, tokenB);
        return pairPools[tokenA][tokenB].length;
    }

    function getPairPools(address tokenA, address tokenB) external view returns (PoolInfo[] memory) {
        (tokenA, tokenB) = _sortTokens(tokenA, tokenB);
        return pairPools[tokenA][tokenB];
    }

    function isForwarder(address forwarder) external view override returns (bool) {
        return IForwarderRegistry(forwarderRegistry).isForwarder(forwarder);
    }

    function setForwarderRegistry(address newForwarderRegistry) external override onlyOwner {
        forwarderRegistry = newForwarderRegistry;
        emit UpdateForwarderRegistry(newForwarderRegistry);
    }

    function getSwapFee(
        address pool,
        address sender,
        address tokenIn,
        address tokenOut,
        bytes calldata data
    ) external view override returns (uint24 fee) {
        fee = IFeeManager(feeManager).getSwapFee(pool, sender, tokenIn, tokenOut, data);
    }

    function getProtocolFee(address pool) external view override returns (uint24 fee) {
        fee = IFeeManager(feeManager).getProtocolFee(pool);
    }

    function getFeeRecipient() external view override returns (address recipient) {
        recipient = IFeeManager(feeManager).getFeeRecipient();
    }

    function setFeeManager(address newFeeManager) external override onlyOwner {
        feeManager = newFeeManager;
        emit UpdateFeeManager(newFeeManager);
    }

    function setFactoryWhitelisted(address factory, bool whitelisted) external override onlyOwner {
        require(factory != address(0), "Invalid factory");
        isFactoryWhitelisted[factory] = whitelisted;
        emit SetFactoryWhitelisted(factory, whitelisted);
    }

    /// @dev Create a pool with deployment data and, register it via the factory.
    function createPool(address factory, bytes calldata data) external override returns (address pool) {
        // The factory have to call `registerPool` to register the pool.
        // The pool whitelist is checked in `registerPool`.
        pool = IPoolFactory(factory).createPool(data);
    }

    /// @dev Register a pool to the mapping by its config. Can only be called by factories.
    function registerPool(address pool, uint16 poolType, bytes calldata data, address token0, address token1) external override {
        if (!isFactoryWhitelisted[msg.sender]) {
            revert NotWhitelistedFactory();
        }

        require(pool != address(0));

        // Double check to prevent duplicated pools.
        if (isPool[pool]) {
            revert PoolAlreadyExists();
        }

        // Encode and hash pool config to get the mapping key.
        bytes32 hash = keccak256(abi.encode(poolType, data));

        // Double check to prevent duplicated pools.
        if (getPool[hash] != address(0)) {
            revert PoolAlreadyExists();
        }

        // Set to mappings.
        getPool[hash] = pool;
        isPool[pool] = true;
        pools.push(pool);

        pairPools[token0][token1].push(PoolInfo({
            pool: pool,
            poolType: poolType
        }));

        emit RegisterPool(msg.sender, pool, poolType, data);
    }
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):