HoodDisperse

0x655f30299a3f6eece880b313fce76ef6fcb88c11

Verification
Verified
v0.8.20+commit.a1b79de6
Type
Contract
4,299 bytes
ABI entries
14
3 read · 5 write
License
none

Contract information

Address
0x655f30299a3f6eece880b313fce76ef6fcb88c11
Chain
Robinhood Chain (4663)
Compiler
v0.8.20+commit.a1b79de6
Optimization
Enabled
Creation tx
0x6a54d564b0…c18be8d92e

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (3)

feePerBatch()uint256
getFee()uint256
owner()address

Events (4)

EthDispersedFeeCollectedFeeUpdatedTokenDispersed

ABI

[
  {
    "inputs": [],
    "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": "token",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "totalRecipients",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "totalAmount",
        "type": "uint256"
      }
    ],
    "name": "TokenDispersed",
    "type": "event"
  },
  {
    "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": [],
    "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 allowance(address owner, address spender) external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
}

contract HoodDisperse {

    address public owner;
    uint256 public feePerBatch = 0.00005 ether;

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

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }

    function setFee(uint256 newFee) external onlyOwner {
        emit FeeUpdated(feePerBatch, newFee);
        feePerBatch = newFee;
    }

    function disperseEth(
        address[] calldata recipients,
        uint256[] calldata amounts
    ) external payable {
        require(recipients.length == amounts.length, "Length mismatch");
        require(recipients.length > 0, "Empty list");
        require(recipients.length <= 500, "Max 500 per batch");

        uint256 totalAirdrop = 0;

        for (uint256 i = 0; i < amounts.length; i++) {
            totalAirdrop += amounts[i];
        }

        require(
            msg.value >= feePerBatch + totalAirdrop,
            "Insufficient ETH: fee + amounts required"
        );

        (bool feeSent, ) = owner.call{value: feePerBatch}("");
        require(feeSent, "Fee transfer failed");

        emit FeeCollected(msg.sender, feePerBatch);

        for (uint256 i = 0; i < recipients.length; i++) {
            require(recipients[i] != address(0), "Zero address");

            (bool success, ) = recipients[i].call{value: amounts[i]}("");
            require(success, "ETH transfer failed");
        }

        uint256 leftover = msg.value - feePerBatch - totalAirdrop;

        if (leftover > 0) {
            (bool refund, ) = msg.sender.call{value: leftover}("");
            require(refund, "Refund failed");
        }

        emit EthDispersed(recipients.length, totalAirdrop);
    }

    function disperseToken(
        address token,
        address[] calldata recipients,
        uint256[] calldata amounts
    ) external payable {
        require(recipients.length == amounts.length, "Length mismatch");
        require(recipients.length > 0, "Empty list");
        require(recipients.length <= 500, "Max 500 per batch");
        require(token != address(0), "Invalid token");

        require(msg.value >= feePerBatch, "Insufficient fee");

        (bool feeSent, ) = owner.call{value: feePerBatch}("");
        require(feeSent, "Fee transfer failed");

        emit FeeCollected(msg.sender, feePerBatch);

        IERC20 erc20 = IERC20(token);

        uint256 total = 0;

        for (uint256 i = 0; i < amounts.length; i++) {
            total += amounts[i];
        }

        require(
            erc20.allowance(msg.sender, address(this)) >= total,
            "Insufficient allowance"
        );

        for (uint256 i = 0; i < recipients.length; i++) {
            require(recipients[i] != address(0), "Zero address");

            bool success = erc20.transferFrom(
                msg.sender,
                recipients[i],
                amounts[i]
            );

            require(success, "Token transfer failed");
        }

        uint256 leftover = msg.value - feePerBatch;

        if (leftover > 0) {
            (bool refund, ) = msg.sender.call{value: leftover}("");
            require(refund, "Refund failed");
        }

        emit TokenDispersed(token, recipients.length, total);
    }

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

    function withdrawToken(address token) external onlyOwner {
        IERC20 erc20 = IERC20(token);

        uint256 bal = erc20.balanceOf(address(this));

        require(bal > 0, "No tokens");

        erc20.transfer(owner, bal);
    }

    function getFee() external view returns (uint256) {
        return feePerBatch;
    }

    receive() external payable {}
}
Chain explorer2467msChain node87ms