Depositor

Description:

ERC20 token contract with Mintable, Factory capabilities. Standard implementation for fungible tokens on Ethereum.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/Depositor.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IERC20 {
  /**
   * @dev Returns the amount of tokens in existence.
   */
  function totalSupply() external view returns (uint256);

  /**
   * @dev Returns the amount of tokens owned by `account`.
  */
  function balanceOf(address account) external view returns (uint256);

  /**
   * @dev Moves `amount` tokens from the caller's account to `recipient`.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits a {Transfer} event.
  */
  function transfer(address recipient, uint256 amount) external returns (bool);
  function mint(address account, uint amount) external;
  /**
   * @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 `amount` 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 amount) external returns (bool);

  /**
   * @dev Moves `amount` tokens from `sender` to `recipient` using the
   * allowance mechanism. `amount` is then deducted from the caller's
   * allowance.
   *
   * Returns a boolean value indicating whether the operation succeeded.
   *
   * Emits a {Transfer} event.
  */
  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

  /**
   * @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);
}

library Address {
  /**
   * @dev Returns true if `account` is a contract.
   *
   * [IMPORTANT]
   * ====
   * It is unsafe to assume that an address for which this function returns
   * false is an externally-owned account (EOA) and not a contract.
   *
   * Among others, `isContract` will return false for the following 
   * types of addresses:
   *
   *  - an externally-owned account
   *  - a contract in construction
   *  - an address where a contract will be created
   *  - an address where a contract lived, but was destroyed
   * ====
  */
  function isContract(address account) internal view returns (bool) {
    // This method relies on extcodesize, which returns 0 for contracts in
    // construction, since the code is only stored at the end of the
    // constructor execution.

    uint256 size;
    // solhint-disable-next-line no-inline-assembly
    assembly { size := extcodesize(account) }
    return size > 0;
  }

  /**
   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
   * `recipient`, forwarding all available gas and reverting on errors.
   *
   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
   * of certain opcodes, possibly making contracts go over the 2300 gas limit
   * imposed by `transfer`, making them unable to receive funds via
   * `transfer`. {sendValue} removes this limitation.
   *
   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
   *
   * IMPORTANT: because control is transferred to `recipient`, care must be
   * taken to not create reentrancy vulnerabilities. Consider using
   * {ReentrancyGuard} or the
   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
  *
  * _Available since v2.4.0._
  */
  function sendValue(address payable recipient, uint256 amount) internal {
    require(address(this).balance >= amount, "Address: insufficient balance");

    // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
    (bool success, ) = recipient.call{ value: amount }("");
    require(success, "Address: unable to send value, recipient may have reverted");
  }
}

library SafeMath {
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    require(c >= a, "SafeMath: addition overflow");

    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    return sub(a, b, "SafeMath: subtraction overflow");
  }

  function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
    require(b <= a, errorMessage);
    uint256 c = a - b;

    return c;
  }
}



library SafeERC20 {
  using Address for address;
  using SafeMath for uint256;

  bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));

  function safeTransfer(IERC20 token, address to, uint256 value) internal {
    (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SELECTOR, to, value));
    require(success && (data.length == 0 || abi.decode(data, (bool))), 'SafeERC20: TRANSFER_FAILED');
  }
  
  function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
    callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
  }

  function safeApprove(IERC20 token, address spender, uint256 value) internal {
    // safeApprove should only be called when setting an initial allowance,
    // or when resetting it to zero. To increase and decrease it, use
    // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
    // solhint-disable-next-line max-line-length
    require((value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
           );
           callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
  }

  function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
    uint256 newAllowance = token.allowance(address(this), spender).add(value);
    callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
  }

  function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
    uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
    callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
  }

  /**
   * @dev Imitates a Solidity high level call (i.e. a regular function call to a contract), relaxing the requirement
   * on the return value: the return value is optional (but if data is returned, it must not be false).
  * @param token The token targeted by the call.
  * @param data The call data (encoded using abi.encode or one of its variants).
  */
  function callOptionalReturn(IERC20 token, bytes memory data) private {
    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    // we're implementing it ourselves.

    // A Solidity high level call has three parts:
    //  1. The target address is checked to verify it contains contract code
    //  2. The call itself is made, and success asserted
    //  3. The return value is decoded, which in turn checks the size of the returned data.
    // solhint-disable-next-line max-line-length
    require(address(token).isContract(), "SafeERC20: call to non-contract");

    // solhint-disable-next-line avoid-low-level-calls
    (bool success, bytes memory returndata) = address(token).call(data);
    require(success, "SafeERC20: low-level call failed");

    if (returndata.length > 0) { // Return data is optional
      // solhint-disable-next-line max-line-length
      require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }
  }
}



contract Depositor {
      using SafeERC20 for IERC20;

      address public owner;
      mapping(address => bool) public whitelistedVaults;

      error NotOwnerError();
      error LengthError();
      error ZeroAddressError();
      error AmountError();
      error RecipientError();
      error CallError();
      error VaultNotWhitelistedError();
      error VaultAlreadyWhitelistedError();
      error VaultNotFoundError();
      error InvalidDestinationChainIdError();

      event Deposit(
        address indexed user,
        address indexed vault,
        bytes32 recipient,
        address indexed inputToken,
        uint256 inputAmount,
        uint256 destinationChainId,
        bytes message,
        uint timestamp
      );

      event VaultWhitelisted(address indexed vault);
      event VaultRemovedFromWhitelist(address indexed vault);
      event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

      modifier onlyOwner() {
        if (msg.sender != owner) {
          revert NotOwnerError();
        }
        _;
      }

      modifier onlyWhitelistedVault(address vault) {
        if (!whitelistedVaults[vault]) {
          revert VaultNotWhitelistedError();
        }
        _;
      }

      constructor() {
        owner = msg.sender;
      }

      receive() external payable {
      }

      function isDepositor69() public pure returns (bool) {
        return true;
      }

      /**
       * @dev Add vault address to whitelist
       * @param vault The vault address to be added
       */
      function addVaultToWhitelist(address vault) external onlyOwner {
        if (vault == address(0)) {
          revert ZeroAddressError();
        }
        if (whitelistedVaults[vault]) {
          revert VaultAlreadyWhitelistedError();
        }
        
        whitelistedVaults[vault] = true;
        emit VaultWhitelisted(vault);
      }

      /**
       * @dev Remove vault address from whitelist
       * @param vault The vault address to be removed
       */
      function removeVaultFromWhitelist(address vault) external onlyOwner {
        if (!whitelistedVaults[vault]) {
          revert VaultNotFoundError();
        }
        
        whitelistedVaults[vault] = false;
        emit VaultRemovedFromWhitelist(vault);
      }

      /**
       * @dev Add multiple vaults to whitelist in batch
       * @param vaults Array of vault addresses to be added
       */
      function addVaultsToWhitelist(address[] calldata vaults) external onlyOwner {
        if (vaults.length == 0) {
          revert LengthError();
        }
        
        for (uint256 i = 0; i < vaults.length; i++) {
          address vault = vaults[i];
          if (vault == address(0)) {
            revert ZeroAddressError();
          }
          if (!whitelistedVaults[vault]) {
            whitelistedVaults[vault] = true;
            emit VaultWhitelisted(vault);
          }
        }
      }

      /**
       * @dev Check if vault is whitelisted
       * @param vault The vault address to check
       * @return Returns true if whitelisted, false otherwise
       */
      function isVaultWhitelisted(address vault) external view returns (bool) {
        return whitelistedVaults[vault];
      }

      /**
       * @dev Transfer contract ownership
       * @param newOwner The new owner address
       */
      function transferOwnership(address newOwner) external onlyOwner {
        if (newOwner == address(0)) {
          revert ZeroAddressError();
        }
        
        address previousOwner = owner;
        owner = newOwner;
        emit OwnershipTransferred(previousOwner, newOwner);
      }

      function deposit(
        address vault,
        bytes32 recipient,
        address inputToken,
        uint256 inputAmount,
        uint256 destinationChainId,
        bytes memory message
      ) external payable onlyWhitelistedVault(vault) {
        if (recipient == bytes32(0)) {
          revert RecipientError();
        }
        if (destinationChainId == block.chainid) {
          revert InvalidDestinationChainIdError();
        }
        if (inputToken == address(0)) {
          if (msg.value != inputAmount) {
            revert AmountError();
          }
          (bool ok,) = vault.call{value: inputAmount}("");
          if (!ok) {
            revert CallError();
          }
        } else {
          IERC20(inputToken).safeTransferFrom(msg.sender, vault, inputAmount);
        }

        emit Deposit(msg.sender, vault, recipient, inputToken, inputAmount, destinationChainId, message, block.timestamp);
      }

}
"
    }
  },
  "settings": {
    "remappings": [
      "ds-test/=lib/solmate/lib/ds-test/src/",
      "forge-std/=lib/forge-std/src/",
      "solmate/=lib/solmate/src/"
    ],
    "optimizer": {
      "enabled": false,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "paris",
    "viaIR": false
  }
}}

Tags:
ERC20, Token, Mintable, Factory|addr:0xefa84c418cb370474bf082027635261a5a79262c|verified:true|block:23626864|tx:0xa6bd6a65f3627bf92751a0992106b6b7fb03363eb0ba0f0092f90934abc5a20a|first_check:1761064558

Submitted on: 2025-10-21 18:35:58

Comments

Log in to comment.

No comments yet.