Contract Source Code (Solidity Standard Json-Input format)
File 1 of 1 : USDTAirdrop.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
/// @title USDT Airdrop Distribution Contract
/// @notice This contract allows the owner to airdrop USDT tokens to multiple users in chunks
/// @dev Uses nonReentrant modifier to prevent reentrancy attacks
interface IERC20 {
/// @notice Transfers tokens from the contract to a recipient
/// @param recipient Address to receive the tokens
/// @param amount Number of tokens to transfer
/// @return success True if the transfer succeeds
function transfer(address recipient, uint256 amount) external returns (bool);
/// @notice Returns the balance of a given account
/// @param account Address to query the balance of
/// @return balance The number of tokens owned by the account
function balanceOf(address account) external view returns (uint256);
}
contract USDTAirdrop {
/// @notice Address of the contract owner
address public owner;
/// @notice The USDT token to be distributed
IERC20 public USDT;
/// @notice Mapping to store each recipient's airdrop amount
mapping(address => uint256) public airdropAmounts;
/// @notice Array of recipient addresses
address[] public recipients;
/// @notice Total USDT allocated for airdrop
uint256 public airdropAmount;
/// @notice Number of users processed per chunk
uint256 public chunkSize;
/// @notice Last index processed during chunk distribution
uint256 public lastDistributedIndex;
/// @dev Modifier to restrict function access to contract owner
modifier onlyOwner() {
require(msg.sender == owner, "Only owner can call this function");
_;
}
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status = _NOT_ENTERED;
/// @dev Modifier to prevent reentrant calls
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
/// @notice Emitted when users are added to the airdrop list
event UsersAdded(uint256 count, uint256 totalAmount);
/// @notice Emitted when tokens are distributed to a recipient
event TokensDistributed(address indexed recipient, uint256 amount);
/// @notice Constructor to initialize the airdrop contract
/// @param token The address of the USDT token contract
constructor(address token) {
require(token != address(0), "Invalid USDT address");
owner = msg.sender;
USDT = IERC20(token);
chunkSize = 100;
}
/// @notice Adds users and their airdrop amounts
/// @param users Array of recipient addresses
/// @param amounts Array of corresponding USDT amounts
function addUser(address[] calldata users, uint256[] calldata amounts) external onlyOwner nonReentrant {
require(users.length == amounts.length, "Arrays length mismatch");
require(users.length > 0, "Empty arrays");
uint256 newTotal;
for (uint256 i = 0; i < users.length; i++) {
address user = users[i];
uint256 amount = amounts[i];
require(user != address(0), "Invalid address");
require(amount > 0, "Amount must be greater than 0");
recipients.push(user);
airdropAmounts[user] = amount;
newTotal += amount;
}
airdropAmount += newTotal;
emit UsersAdded(users.length, newTotal);
}
/// @notice Updates the chunk size for batch distribution
/// @param size New chunk size
function setChunkSize(uint256 size) external onlyOwner {
require(size > 0, "Chunk size must be greater than 0");
chunkSize = size;
}
/// @notice Distributes tokens to recipients in a batch (chunk)
/// @dev Uses `lastDistributedIndex` to track progress
function distributeChunk() external onlyOwner nonReentrant {
require(lastDistributedIndex < recipients.length, "Airdrop completed");
uint256 endIndex = lastDistributedIndex + chunkSize;
if (endIndex > recipients.length) {
endIndex = recipients.length;
}
for (uint256 i = lastDistributedIndex; i < endIndex; i++) {
address recipient = recipients[i];
uint256 amount = airdropAmounts[recipient];
if (amount > 0) {
airdropAmounts[recipient] = 0;
airdropAmount -= amount;
bool sent = USDT.transfer(recipient, amount);
require(sent, "USDT transfer failed");
emit TokensDistributed(recipient, amount);
}
}
lastDistributedIndex = endIndex;
}
/// @notice Returns the number of recipients yet to receive their airdrop
/// @return count Number of users remaining
function getRemainingCount() public view returns (uint256) {
return recipients.length - lastDistributedIndex;
}
/// @notice Allows the owner to withdraw remaining undistributed USDT tokens
function withdrawRemaining() external onlyOwner nonReentrant {
uint256 balance = USDT.balanceOf(address(this));
bool sent = USDT.transfer(owner, balance);
require(sent, "Failed to withdraw remaining tokens");
}
/// @notice Transfers contract ownership to a new address
/// @param newOwner Address of the new owner
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "New owner is the zero address");
owner = newOwner;
}
/// @notice Resets the airdrop data to allow for a new round
function resetAirdrop() external onlyOwner nonReentrant {
delete recipients;
airdropAmount = 0;
lastDistributedIndex = 0;
}
}