GateWhitelist

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/gate/GateWhitelist.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 [Byzantine Finance]
// The implementation of this contract was inspired by Morpho Vault V2, developed by the Morpho Association in 2025.
pragma solidity ^0.8.0;

import "../../src/interfaces/IGate.sol";

/// @notice Morpho Bundler3 contract interface
/// @dev Must give the address that initiates the transaction to the vault (real msg.sender)
/// @dev Source code here: https://github.com/morpho-org/bundler3/blob/main/src/Bundler3.sol
interface IBundler3 {
    function initiator() external view returns (address);
}

/// @notice Bundler Adapter contract interface (must support erc4626 deposits and withdrawals)
/// @dev Must give the Bundler3 contract used by the initiator
/// @dev Very likely the GeneralAdapter1:
/// https://github.com/morpho-org/bundler3/blob/main/src/adapters/GeneralAdapter1.sol
interface IBundlerAdapter {
    function BUNDLER3() external view returns (IBundler3);
}

/// VaultV2 Gate with the following characteristics:
/// - It is a send assets gate, i.e. it checks users who deposit assets to the vault.
/// - It is a receive assets gate, i.e. it checks users who receive assets from the vault.
/// - It is a send shares gate, i.e. it checks users who transfer shares to an address.
/// - It is a receive shares gate, i.e. it checks users who receive shares from an address.
/// - It has a single whitelist for all permissions.
/// - It works with Bundler3.
///   To enable transfers to/from a Bundler3 adapter, set isBundlerAdapter[bundlerAdapter] to true.
///   Only trusted Bundler3 adapters should be added (addresses here
///   https://docs.morpho.org/get-started/resources/addresses/#bundlers)
contract GateWhitelist is IReceiveSharesGate, ISendSharesGate, IReceiveAssetsGate, ISendAssetsGate {
    /* STORAGE */

    address public owner;
    mapping(address => bool) public isBundlerAdapter;
    mapping(address => bool) public whitelisted;

    /* EVENTS */

    event SetOwner(address oldOwner, address indexed newOwner);
    event SetIsWhitelisted(address indexed account, bool newIsWhitelisted);
    event SetIsBundlerAdapter(address indexed account, bool newIsBundlerAdapter);

    /* ERRORS */

    error Unauthorized();
    error ArrayLengthMismatch();

    /* CONSTRUCTOR */

    constructor(address _owner) {
        owner = _owner;
        emit SetOwner(address(0), _owner);
    }

    /* ROLES FUNCTIONS */

    /// @notice Set the owner of the gate.
    function setOwner(address newOwner) external {
        require(msg.sender == owner, Unauthorized());
        owner = newOwner;
        emit SetOwner(msg.sender, newOwner);
    }

    /// @notice Set who is whitelisted.
    function setIsWhitelisted(address account, bool newIsWhitelisted) external {
        require(msg.sender == owner, Unauthorized());
        _setIsWhitelisted(account, newIsWhitelisted);
    }

    /// @notice Set who is whitelisted in batch.
    function setIsWhitelistedBatch(address[] memory accounts, bool[] memory newIsWhitelisted) external {
        require(msg.sender == owner, Unauthorized());
        require(accounts.length == newIsWhitelisted.length, ArrayLengthMismatch());
        for (uint256 i; i < accounts.length; ++i) {
            _setIsWhitelisted(accounts[i], newIsWhitelisted[i]);
        }
    }

    /// @notice Set who is allowed to handle shares and assets on behalf of another account.
    function setIsBundlerAdapter(address account, bool newIsBundlerAdapter) external {
        require(msg.sender == owner, Unauthorized());
        isBundlerAdapter[account] = newIsBundlerAdapter;
        emit SetIsBundlerAdapter(account, newIsBundlerAdapter);
    }

    /* VIEW FUNCTIONS */

    /// @notice Check if `account` can supply assets when a deposit is made.
    function canSendAssets(address account) external view returns (bool) {
        return _whitelistedOrHandlingOnBehalf(account);
    }

    /// @notice Check if `account` can receive assets when a withdrawal is made.
    function canReceiveAssets(address account) external view returns (bool) {
        return _whitelistedOrHandlingOnBehalf(account);
    }

    /// @notice Check if `account` can send shares.
    function canSendShares(address account) external view returns (bool) {
        return _whitelistedOrHandlingOnBehalf(account);
    }

    /// @notice Check if `account` can receive shares.
    function canReceiveShares(address account) external view returns (bool) {
        return _whitelistedOrHandlingOnBehalf(account);
    }

    /* INTERNAL FUNCTIONS */

    function _whitelistedOrHandlingOnBehalf(address account) internal view returns (bool) {
        return whitelisted[account]
            || (isBundlerAdapter[account] && whitelisted[IBundlerAdapter(account).BUNDLER3().initiator()]);
    }

    function _setIsWhitelisted(address account, bool newIsWhitelisted) internal {
        whitelisted[account] = newIsWhitelisted;
        emit SetIsWhitelisted(account, newIsWhitelisted);
    }
}
"
    },
    "src/interfaces/IGate.sol": {
      "content": "// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2025 Morpho Association
pragma solidity >=0.5.0;

interface IReceiveSharesGate {
    function canReceiveShares(address account) external view returns (bool);
}

interface ISendSharesGate {
    function canSendShares(address account) external view returns (bool);
}

interface IReceiveAssetsGate {
    function canReceiveAssets(address account) external view returns (bool);
}

interface ISendAssetsGate {
    function canSendAssets(address account) external view returns (bool);
}
"
    }
  },
  "settings": {
    "remappings": [
      "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
      "ds-test/=lib/morpho-blue/lib/forge-std/lib/ds-test/src/",
      "erc4626-tests/=lib/metamorpho/lib/erc4626-tests/",
      "forge-std/=lib/forge-std/src/",
      "halmos-cheatcodes/=lib/morpho-blue/lib/halmos-cheatcodes/src/",
      "metamorpho-v1.1/=lib/metamorpho-v1.1/",
      "metamorpho/=lib/metamorpho/",
      "morpho-blue-irm/=lib/metamorpho/lib/morpho-blue-irm/src/",
      "morpho-blue/=lib/morpho-blue/",
      "openzeppelin-contracts/=lib/openzeppelin-contracts/",
      "solmate/=lib/metamorpho/lib/morpho-blue-irm/lib/solmate/src/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 100000
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "none",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "cancun",
    "viaIR": true
  }
}}

Tags:
Factory|addr:0x40ee5564691d04e77764f155cfa1494c7304ce13|verified:true|block:23547021|tx:0xac9d66b1108d550eda71638cc5167b66f7eb658374dabdf45612e01ce4f777ee|first_check:1760095903

Submitted on: 2025-10-10 13:31:44

Comments

Log in to comment.

No comments yet.