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"
);
}
}