OmniaDisperse
0xbecacca1e44859363a2c3d31b0c514d6478bacd6
Verification
Verified
0.8.20+commit.a1b79de6
Type
Contract
8,690 bytes
ABI entries
17
4 read · 6 write
License
none
Contract information
- Address
- 0xbecacca1e44859363a2c3d31b0c514d6478bacd6
- Chain
- Robinhood Chain (4663)
- Compiler
- 0.8.20+commit.a1b79de6
- Optimization
- Disabled
- Creator
- 0xD582EDE311…555b5D1aD5
- Creation tx
- 0x0940cd4e1a…7fc0eead72
Token
Not a token
This contract does not expose ERC-20 metadata.
Read contract (4)
MAX_PER_BATCH() → uint256
feePerBatch() → uint256
getFee() → uint256
owner() → address
Events (5)
EthDispersedFeeCollectedFeeUpdatedOwnershipTransferredTokenDispersed
ABI
[
{
"inputs": [
{
"internalType": "uint256",
"name": "_feePerBatch",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "totalRecipients",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "totalAmount",
"type": "uint256"
}
],
"name": "EthDispersed",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "payer",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "FeeCollected",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "oldFee",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "newFee",
"type": "uint256"
}
],
"name": "FeeUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "oldOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "token",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "totalRecipients",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "totalAmount",
"type": "uint256"
}
],
"name": "TokenDispersed",
"type": "event"
},
{
"inputs": [],
"name": "MAX_PER_BATCH",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "recipients",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"name": "disperseEth",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
},
{
"internalType": "address[]",
"name": "recipients",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"name": "disperseToken",
"outputs": [],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "feePerBatch",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getFee",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "newFee",
"type": "uint256"
}
],
"name": "setFee",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "withdrawEth",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "token",
"type": "address"
}
],
"name": "withdrawToken",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
]Source code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function transferFrom(address from, address to, uint256 amount) external returns (bool);
function transfer(address to, uint256 amount) external returns (bool);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
}
/// @title OmniaDisperse — multisend ETH / ERC-20 in one transaction.
/// @notice Non-custodial: ETH is forwarded straight to each recipient and
/// tokens move via transferFrom directly from the sender. The
/// contract never holds user funds. feePerBatch (wei) is charged
/// per call and paid instantly to the owner; 0 = free.
/// @dev Part of the OMNIA toolkit (deploy + airdrop).
/// One identical contract per supported network.
contract OmniaDisperse {
// ------------------------------------------------------------------
// State
// ------------------------------------------------------------------
address public owner;
uint256 public feePerBatch; // in wei
uint256 public constant MAX_PER_BATCH = 500;
uint256 private _locked;
// ------------------------------------------------------------------
// Events
// ------------------------------------------------------------------
event EthDispersed(uint256 totalRecipients, uint256 totalAmount);
event TokenDispersed(address indexed token, uint256 totalRecipients, uint256 totalAmount);
event FeeCollected(address indexed payer, uint256 amount);
event FeeUpdated(uint256 oldFee, uint256 newFee);
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
// ------------------------------------------------------------------
// Modifiers
// ------------------------------------------------------------------
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
modifier nonReentrant() {
require(_locked == 0, "Reentrant");
_locked = 1;
_;
_locked = 0;
}
/// @param _feePerBatch fee per call in wei (0 = no fee)
constructor(uint256 _feePerBatch) {
owner = msg.sender;
feePerBatch = _feePerBatch;
emit OwnershipTransferred(address(0), msg.sender);
}
function getFee() external view returns (uint256) {
return feePerBatch;
}
// ------------------------------------------------------------------
// ETH multisend
// ------------------------------------------------------------------
function disperseEth(address[] calldata recipients, uint256[] calldata amounts)
external
payable
nonReentrant
{
require(recipients.length == amounts.length, "Length mismatch");
require(amounts.length > 0, "Empty list");
require(amounts.length <= MAX_PER_BATCH, "Max 500 per batch");
uint256 total;
for (uint256 i = 0; i < amounts.length; i++) {
total += amounts[i];
}
require(msg.value >= total + feePerBatch, "Insufficient ETH: fee + amounts required");
if (feePerBatch > 0) {
(bool fok, ) = owner.call{value: feePerBatch}("");
require(fok, "Fee transfer failed");
emit FeeCollected(msg.sender, feePerBatch);
}
for (uint256 i = 0; i < recipients.length; i++) {
require(recipients[i] != address(0), "Zero address");
(bool ok, ) = recipients[i].call{value: amounts[i]}("");
require(ok, "ETH transfer failed");
}
uint256 refund = msg.value - feePerBatch - total;
if (refund > 0) {
(bool rok, ) = msg.sender.call{value: refund}("");
require(rok, "Refund failed");
}
emit EthDispersed(recipients.length, total);
}
// ------------------------------------------------------------------
// ERC-20 multisend (sender must approve this contract first)
// ------------------------------------------------------------------
function disperseToken(address token, address[] calldata recipients, uint256[] calldata amounts)
external
payable
nonReentrant
{
require(recipients.length == amounts.length, "Length mismatch");
require(amounts.length > 0, "Empty list");
require(amounts.length <= MAX_PER_BATCH, "Max 500 per batch");
require(token != address(0), "Invalid token");
require(msg.value >= feePerBatch, "Insufficient fee");
if (feePerBatch > 0) {
(bool fok, ) = owner.call{value: feePerBatch}("");
require(fok, "Fee transfer failed");
emit FeeCollected(msg.sender, feePerBatch);
}
uint256 total;
for (uint256 i = 0; i < amounts.length; i++) {
total += amounts[i];
}
require(
IERC20(token).allowance(msg.sender, address(this)) >= total,
"Insufficient allowance"
);
for (uint256 i = 0; i < recipients.length; i++) {
require(recipients[i] != address(0), "Zero address");
bool ok = IERC20(token).transferFrom(msg.sender, recipients[i], amounts[i]);
require(ok, "Token transfer failed");
}
uint256 refund = msg.value - feePerBatch;
if (refund > 0) {
(bool rok, ) = msg.sender.call{value: refund}("");
require(rok, "Refund failed");
}
emit TokenDispersed(token, recipients.length, total);
}
// ------------------------------------------------------------------
// Owner controls
// ------------------------------------------------------------------
function setFee(uint256 newFee) external onlyOwner {
emit FeeUpdated(feePerBatch, newFee);
feePerBatch = newFee;
}
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "Zero address");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
/// Rescue ETH stuck in the contract (normally 0 — fees go straight to owner).
function withdrawEth() external onlyOwner {
uint256 bal = address(this).balance;
require(bal > 0, "Nothing to withdraw");
(bool ok, ) = owner.call{value: bal}("");
require(ok, "Withdraw failed");
}
/// Rescue tokens stuck in the contract (normally 0).
function withdrawToken(address token) external onlyOwner {
uint256 bal = IERC20(token).balanceOf(address(this));
require(bal > 0, "No tokens");
require(IERC20(token).transfer(owner, bal), "Token transfer failed");
}
receive() external payable {}
}
Chain explorer1779msChain node89ms