Description:
ERC20 token contract with Factory capabilities. Standard implementation for fungible tokens on Ethereum.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"YGMI/YGMIAirdrop.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/* -------------------------------------------------------------------------- */
/* Minimal OpenZeppelin Refs */
/* -------------------------------------------------------------------------- */
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
}
/* ----------------------------- Ownable (minimal) ---------------------------- */
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
constructor(address initialOwner) {
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not owner");
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is zero");
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
/* --------------------------- ReentrancyGuard (min) -------------------------- */
abstract contract ReentrancyGuard {
uint256 private _status;
constructor() {
_status = 1;
}
modifier nonReentrant() {
require(_status == 1, "ReentrancyGuard: reentrant");
_status = 2;
_;
_status = 1;
}
}
/* ----------------------------- IERC20 interface ---------------------------- */
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(
address owner,
address spender
) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
/* ------------------------------- SafeERC20 lib ------------------------------ */
library SafeERC20 {
function safeTransfer(IERC20 token, address to, uint256 value) internal {
require(
_callOptionalReturn(
token,
abi.encodeWithSelector(token.transfer.selector, to, value)
),
"SafeERC20: transfer failed"
);
}
function _callOptionalReturn(
IERC20 token,
bytes memory data
) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
if (!success) return false;
if (returndata.length == 0) return true;
return abi.decode(returndata, (bool));
}
}
/* ------------------------------- MerkleProof ------------------------------- */
library MerkleProof {
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
function processProof(
bytes32[] memory proof,
bytes32 leaf
) internal pure returns (bytes32 computedHash) {
computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
bytes32 proofElement = proof[i];
if (computedHash <= proofElement) {
computedHash = keccak256(
abi.encodePacked(computedHash, proofElement)
);
} else {
computedHash = keccak256(
abi.encodePacked(proofElement, computedHash)
);
}
}
}
}
/* -------------------------------------------------------------------------- */
/* YGMIAirdrop */
/* -------------------------------------------------------------------------- */
contract YGMIAirdrop is Ownable, ReentrancyGuard {
using SafeERC20 for IERC20;
IERC20 public immutable ygmi;
struct Round {
bytes32 merkleRoot;
uint256 totalClaimed;
}
uint256 public currentRound;
mapping(uint256 => mapping(address => bool)) public hasClaimed;
mapping(uint256 => Round) public rounds;
event MerkleRootUpdated(uint256 indexed round, bytes32 indexed newRoot);
event Claimed(
uint256 indexed round,
address indexed account,
uint256 amount
);
event Withdrawn(address indexed to, uint256 amount);
constructor(IERC20 _ygmi, address _owner) Ownable(_owner) {
require(address(_ygmi) != address(0), "YGMI address zero");
ygmi = _ygmi;
}
/* ----------------------------- Admin Actions ----------------------------- */
/// @notice Starts a new round with a new merkle root.
/// The new root overrides the previous one — only this root is active.
function setMerkleRoot(bytes32 _root) external onlyOwner {
require(_root != bytes32(0), "Invalid root");
currentRound++;
rounds[currentRound].merkleRoot = _root;
emit MerkleRootUpdated(currentRound, _root);
}
/* ----------------------------- User Functions ---------------------------- */
function claim(
uint256 amount,
bytes32[] calldata proof
) external nonReentrant {
Round storage round = rounds[currentRound];
require(round.merkleRoot != bytes32(0), "Root not set");
require(!hasClaimed[currentRound][msg.sender], "Already claimed");
require(amount > 0, "Zero amount");
bytes32 leaf = keccak256(abi.encode(msg.sender, amount));
require(
MerkleProof.verify(proof, round.merkleRoot, leaf),
"Invalid proof"
);
hasClaimed[currentRound][msg.sender] = true;
round.totalClaimed += amount;
ygmi.safeTransfer(msg.sender, amount);
emit Claimed(currentRound, msg.sender, amount);
}
/* ----------------------------- View Helpers ----------------------------- */
function canClaim(
address account,
uint256 amount,
bytes32[] calldata proof
) external view returns (bool) {
Round storage round = rounds[currentRound];
if (
round.merkleRoot == bytes32(0) ||
hasClaimed[currentRound][account] ||
amount == 0
) return false;
bytes32 leaf = keccak256(abi.encode(account, amount));
return MerkleProof.verify(proof, round.merkleRoot, leaf);
}
/* ----------------------------- Getters ----------------------------- */
function getActiveRoot() external view returns (bytes32) {
return rounds[currentRound].merkleRoot;
}
function getTotalClaimed(uint256 roundId) external view returns (uint256) {
return rounds[roundId].totalClaimed;
}
}
"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": []
}
}}
Submitted on: 2025-10-28 10:06:55
Comments
Log in to comment.
No comments yet.