账户
0x47...dd29
0x47...DD29

0x47...DD29

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.17+commit.8df45f5f
语言
Solidity
合同源代码
文件 1 的 7:Common.sol
/*
    SPDX-License-Identifier: Apache-2.0
*/

pragma solidity ^0.8.4;

library Common {
    function _validateAddress(address _addr) internal pure {
        require(_addr != address(0), "Address cannot be zero");
    }

    function _isContract(address account) internal view returns (bool) {
        return account.code.length > 0;
    }
}
合同源代码
文件 2 的 7:ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
合同源代码
文件 3 的 7:IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
合同源代码
文件 4 的 7:IStarBaseApprove.sol
/*

    Copyright 2020 StarBase.
    SPDX-License-Identifier: Apache-2.0

*/

pragma solidity ^0.8.4;

interface IStarBaseApprove {
    function claimTokens(address token, address who, address dest, uint160 amount) external;
    function getStarBaseProxy() external view returns (address);
}
合同源代码
文件 5 的 7:IStarBaseApproveProxy.sol
/*

    Copyright 2020 StarBase  .
    SPDX-License-Identifier: Apache-2.0

*/

pragma solidity ^0.8.4;

interface IStarBaseApproveProxy {
    function claimTokens(address token, address who, address dest, uint160 amount) external;
}
合同源代码
文件 6 的 7:InitializableOwnable.sol
/*

    Copyright 2020 StarBase  .
    SPDX-License-Identifier: Apache-2.0

*/

pragma solidity ^0.8.4;

/**
 * @title Ownable
 * @author StarBase  Simon
 *
 * @notice Ownership related functions
 */
contract InitializableOwnable {
    address public _OWNER_;
    address public _NEW_OWNER_;
    bool internal _INITIALIZED_;

    // ============ Events ============

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

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

    // ============ Modifiers ============

    modifier notInitialized() {
        require(!_INITIALIZED_, "StarBase_INITIALIZED");
        _;
    }

    modifier onlyOwner() {
        require(msg.sender == _OWNER_, "NOT_OWNER");
        _;
    }

    // ============ Functions ============

    function initOwner(address newOwner) public notInitialized {
        _INITIALIZED_ = true;
        _OWNER_ = newOwner;
    }

    function transferOwnership(address newOwner) public onlyOwner {
        emit OwnershipTransferPrepared(_OWNER_, newOwner);
        _NEW_OWNER_ = newOwner;
    }

    function claimOwnership() public {
        require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM");
        emit OwnershipTransferred(_OWNER_, _NEW_OWNER_);
        _OWNER_ = _NEW_OWNER_;
        _NEW_OWNER_ = address(0);
    }
}
合同源代码
文件 7 的 7:StarBaseApproveProxy.sol
/*
    Copyright 2024 StarBase.
    SPDX-License-Identifier: Apache-2.0
*/

pragma solidity ^0.8.4;

import { IStarBaseApprove } from "./intf/IStarBaseApprove.sol";
import { InitializableOwnable } from "./lib/InitializableOwnable.sol";
import { IStarBaseApproveProxy } from "./intf/IStarBaseApproveProxy.sol";
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { Common } from "./lib/Common.sol";

/**
 * @title StarBaseApproveProxy
 * @dev A proxy contract that allows approved addresses to claim tokens from the StarBaseApprove contract.
 * @notice This contract supports adding/removing proxy addresses with a timelock and enforcing access control on token claims.
 * @author StarBase
 */
contract StarBaseApproveProxy is InitializableOwnable, IStarBaseApproveProxy, ERC165 {
    // ============ Constants ============
    uint256 private constant _TIMELOCK_DURATION_ = 3 days; // Timelock duration for adding a new proxy

    // ============ Storage ============
    mapping(address => bool) public _IS_ALLOWED_PROXY_; // Mapping of allowed proxies
    uint256 public _TIMELOCK_; // Timestamp for the timelock
    address public _PENDING_ADD_StarBase_PROXY_; // Pending proxy to be added
    address public _StarBase_APPROVE_; // Address of the StarBaseApprove contract
    address public _Setup_Tool_;
    bool private _isStarBaseApproveSet_ = false;
    bool private _isSetWhiteList_ = false;

    // ============ Events ============
    event RemoveStarBaseProxy(address oldStarBaseProxy); // Emitted when a proxy is removed
    event ClaimTokens(address indexed token, address indexed who, address indexed dest, uint160 amount); // Emitted on successful token claim
    event UnlockAddProxy(address indexed newStarBaseProxy);
    event LockAddProxy();
    event AddStarBaseProxy(address indexed newStarBaseProxy);
    event SetStarBaseApprove(address indexed StarBaseApprove);
    event SetWhiteList(address[] indexed proxies);

    // ============ Modifiers ============
    /**
     * @dev Modifier to ensure that the contract is not in timelock state.
     */
    modifier notLocked() {
        require(_TIMELOCK_ <= block.timestamp, "SAP: SETPROXY IS TIMELOCKED");
        _;
    }

    /**
     * @dev Contract constructor to initialize the contract with the owner, the StarBaseApprove contract, and allowed proxies.
     * @param owner The owner of the contract.
     */
    constructor(address owner) {
        Common._validateAddress(owner);
        initOwner(owner);
    }

    /**
     * @dev Unlocks the ability to add a new proxy after the timelock.
     * @param newStarBaseProxy The new proxy address to be added.
     */
    function unlockAddProxy(address newStarBaseProxy) external onlyOwner {
        Common._validateAddress(newStarBaseProxy);
        _TIMELOCK_ = block.timestamp + _TIMELOCK_DURATION_;
        _PENDING_ADD_StarBase_PROXY_ = newStarBaseProxy;
        emit UnlockAddProxy(newStarBaseProxy);
    }

    /**
     * @dev Locks the process of adding a new proxy and clears the pending proxy address.
     */
    function lockAddProxy() public onlyOwner {
        _PENDING_ADD_StarBase_PROXY_ = address(0);
        _TIMELOCK_ = 0;
        emit LockAddProxy();
    }

    /**
     * @dev Adds the pending proxy address to the list of allowed proxies.
     * Can only be called after the timelock has expired.
     */
    function addStarBaseProxy() external onlyOwner notLocked {
        _IS_ALLOWED_PROXY_[_PENDING_ADD_StarBase_PROXY_] = true;
        lockAddProxy();
        emit AddStarBaseProxy(_PENDING_ADD_StarBase_PROXY_);
    }

    function setStarBaseApprove(address StarBaseApprove) external onlyOwner {
        require(_isStarBaseApproveSet_ == false, "SAP: IT HAS ALREADY BEEN INITIALIZED");

        require(
            _checkIfContractSupportsInterface(StarBaseApprove, type(IStarBaseApprove).interfaceId),
            "SAP: ADDRESS DOES NOT IMPLEMENT REQUIRED METHODS"
        );

        _StarBase_APPROVE_ = StarBaseApprove;
        _isStarBaseApproveSet_ = true;
        emit SetStarBaseApprove(StarBaseApprove);
    }

    function setWhiteList(address[] memory proxies) external onlyOwner {
        // Add each proxy to the allowed list
        require(_isSetWhiteList_ == false, "SAP: IT HAS ALREADY BEEN INITIALIZED");
        for (uint256 i = 0; i < proxies.length; i++) {
            Common._validateAddress(proxies[i]);
            _IS_ALLOWED_PROXY_[proxies[i]] = true;
        }
        _isSetWhiteList_ = true;
        emit SetWhiteList(proxies);
    }

    /**
     * @dev Removes an existing proxy from the allowed list.
     * @param oldStarBaseProxy The proxy address to be removed.
     */
    function removeStarBaseProxy(address oldStarBaseProxy) external onlyOwner {
        Common._validateAddress(oldStarBaseProxy);
        require(_IS_ALLOWED_PROXY_[oldStarBaseProxy], "SAP: ADDRESS IS NOT AN ALLOWED PROXY");
        _IS_ALLOWED_PROXY_[oldStarBaseProxy] = false;
        emit RemoveStarBaseProxy(oldStarBaseProxy);
    }

    /**
     * @dev Claims tokens from the StarBaseApprove contract.
     * @param token The token to claim.
     * @param who The address from which to claim tokens.
     * @param dest The destination address to receive the tokens.
     * @param amount The amount of tokens to claim.
     */
    function claimTokens(address token, address who, address dest, uint160 amount) external {
        Common._validateAddress(token);
        Common._validateAddress(who);
        Common._validateAddress(dest);

        require(_IS_ALLOWED_PROXY_[msg.sender], "SAP: ACCESS RESTRICTED TO ALLOWED PROXIES");
        IStarBaseApprove(_StarBase_APPROVE_).claimTokens(token, who, dest, amount);
        emit ClaimTokens(token, who, dest, amount);
    }

    function _checkIfContractSupportsInterface(address _contract, bytes4 interfaceId) internal view returns (bool) {
        (bool success, bytes memory result) = _contract.staticcall(
            abi.encodeWithSelector(ERC165.supportsInterface.selector, interfaceId)
        );

        if (success && result.length == 32) {
            return abi.decode(result, (bool));
        }
        return false;
    }

    function supportsInterface(bytes4 interfaceId) public pure override(ERC165) returns (bool) {
        return interfaceId == type(IStarBaseApproveProxy).interfaceId;
    }
}
设置
{
  "compilationTarget": {
    "src/StarBaseApproveProxy.sol": "StarBaseApproveProxy"
  },
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newStarBaseProxy","type":"address"}],"name":"AddStarBaseProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"},{"indexed":true,"internalType":"address","name":"dest","type":"address"},{"indexed":false,"internalType":"uint160","name":"amount","type":"uint160"}],"name":"ClaimTokens","type":"event"},{"anonymous":false,"inputs":[],"name":"LockAddProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferPrepared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldStarBaseProxy","type":"address"}],"name":"RemoveStarBaseProxy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"StarBaseApprove","type":"address"}],"name":"SetStarBaseApprove","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address[]","name":"proxies","type":"address[]"}],"name":"SetWhiteList","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newStarBaseProxy","type":"address"}],"name":"UnlockAddProxy","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_IS_ALLOWED_PROXY_","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_NEW_OWNER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_OWNER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_PENDING_ADD_StarBase_PROXY_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_Setup_Tool_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_StarBase_APPROVE_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_TIMELOCK_","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"addStarBaseProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"who","type":"address"},{"internalType":"address","name":"dest","type":"address"},{"internalType":"uint160","name":"amount","type":"uint160"}],"name":"claimTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"initOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockAddProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldStarBaseProxy","type":"address"}],"name":"removeStarBaseProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"StarBaseApprove","type":"address"}],"name":"setStarBaseApprove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"proxies","type":"address[]"}],"name":"setWhiteList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newStarBaseProxy","type":"address"}],"name":"unlockAddProxy","outputs":[],"stateMutability":"nonpayable","type":"function"}]