Sonic Blaze Testnet

Contract Diff Checker

Contract Name:
MultiSender

Contract Source Code:

File 1 of 1 : MultiSender

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

// IERC20.sol
interface IERC20 {
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

// Context.sol
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// Ownable.sol
abstract contract Ownable is Context {
    address private _owner;

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

    constructor(address initialOwner) {
        _transferOwnership(initialOwner);
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// ReentrancyGuard.sol
abstract contract ReentrancyGuard {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;
    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}

// MultiSender Contract
contract MultiSender is Ownable, ReentrancyGuard {
    uint256 public constant FEE_AMOUNT = 10 * 10**18; // 10 S tokens
    address public feeToken;
    
    // Events
    event MultisendToken(
        address indexed token,
        address indexed sender,
        uint256 totalAmount,
        uint256 recipientCount
    );
    
    event FeeTokenUpdated(address newFeeToken);
    event FeesCollected(address indexed sender, uint256 amount);
    
    constructor(address _feeToken) Ownable(msg.sender) {
        require(_feeToken != address(0), "Invalid fee token address");
        feeToken = _feeToken;
    }
    
    function multiSendToken(
        address token,
        address[] calldata recipients,
        uint256[] calldata amounts
    ) external nonReentrant {
        require(token != address(0), "Invalid token address");
        require(recipients.length > 0, "No recipients");
        require(recipients.length == amounts.length, "Length mismatch");
        require(recipients.length <= 200, "Too many recipients");
        
        // Calculate total amount
        uint256 totalAmount;
        for(uint i = 0; i < amounts.length; i++) {
            totalAmount += amounts[i];
        }
        
        // Collect fee in S tokens and send to owner
        require(
            IERC20(feeToken).transferFrom(msg.sender, owner(), FEE_AMOUNT),
            "Fee payment failed"
        );
        emit FeesCollected(msg.sender, FEE_AMOUNT);
        
        // Transfer tokens to recipients
        IERC20 tokenContract = IERC20(token);
        require(
            tokenContract.transferFrom(msg.sender, address(this), totalAmount),
            "Token transfer failed"
        );
        
        for(uint i = 0; i < recipients.length; i++) {
            require(recipients[i] != address(0), "Invalid recipient");
            require(
                tokenContract.transfer(recipients[i], amounts[i]),
                "Transfer to recipient failed"
            );
        }
        
        emit MultisendToken(token, msg.sender, totalAmount, recipients.length);
    }
    
    // Admin function
    function updateFeeToken(address _newFeeToken) external onlyOwner {
        require(_newFeeToken != address(0), "Invalid fee token");
        feeToken = _newFeeToken;
        emit FeeTokenUpdated(_newFeeToken);
    }
    
    function rescueTokens(address token) external onlyOwner {
        uint256 balance = IERC20(token).balanceOf(address(this));
        require(balance > 0, "No tokens to rescue");
        require(
            IERC20(token).transfer(owner(), balance),
            "Rescue transfer failed"
        );
    }
}

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

Context size (optional):