Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
- Contract name:
- Airdrop
- Optimization enabled
- true
- Compiler version
- v0.8.9+commit.e5eed63a
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2022-06-17T17:21:00.201626Z
Constructor Arguments
0000000000000000000000009fae2529863bd691b4a7171bdfcf33c7ebb10a65
Arg [0] (address) : 0x9fae2529863bd691b4a7171bdfcf33c7ebb10a65
Contract source code
// SPDX-License-Identifier: No License (None) pragma solidity ^0.8.0; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () { _owner = msg.sender; emit OwnershipTransferred(address(0), msg.sender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == msg.sender, "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } /** * @dev Interface of the ERC223 standard as defined in the EIP. */ interface IERC223 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); function transfer(address recipient, uint256 amount, bytes calldata data) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); } abstract contract ERC223Recipient { /** * @dev Standard ERC223 function that will handle incoming token transfers. * * @param _from Token sender address. * @param _value Amount of tokens. * @param _data Transaction metadata. */ function tokenReceived(address _from, uint _value, bytes memory _data) external virtual {} } contract Airdrop is Ownable, ERC223Recipient { struct Setting { uint256 amount; uint256 duration; // in days uint256 daysPassed; } struct User { uint256 timestamp; uint256 amount; } struct Participants { uint256 totalParticipants; uint256 addedParticipants; } IERC223 public token; // token to airdrop uint256 constant public lockPeriod = 180; // 180 days (6 months) lock period mapping(uint256 => mapping(address => User)) public receivers; // airdrop ID => user address => amount and timestamp mapping(uint256 => mapping(uint256 => Participants)) public participants; // airdrop ID => day => Participants Setting[] public airdrops; address public system; event Rescue(address _token, uint256 _amount); event AirdropCreated(uint256 airdropId, uint256 amount, uint256 duration); event SetSystem(address _system); event Airdropped(uint256 indexed airdropId, address indexed user, uint256 amount); /** * @dev Throws if called by any account other than the owner. */ modifier onlySystem() { require(system == msg.sender, "Ownable: caller is not the owner"); _; } constructor (address _token) { token = IERC223(_token); } function setSystem(address _system) onlyOwner external { system = _system; emit SetSystem(_system); } function createAirdrop(uint256 amount, uint256 duration) onlyOwner external returns(uint256 airdropId) { airdropId = airdrops.length; airdrops.push(Setting(amount, duration, 0)); emit AirdropCreated(airdropId, amount, duration); } function getAirdropsLength() external view returns (uint256) { return airdrops.length; } function getUserInfo(address user) external view returns(User[] memory) { uint256 len = airdrops.length; User[] memory u = new User[](len); for (uint i = 0; i < len; i++) { u[i] = receivers[i][user]; } return u; } /** * @dev Close Airdrop day. Call this function on next day after claiming (after 00:00 UTC) * * @param airdropId Airdrop ID. * @param day Day number of airdrop. From 1 to airdrop duration * @param totalParticipants Total number of approved user that claim tokens on this day. */ function closeDay(uint256 airdropId, uint256 day, uint256 totalParticipants) onlySystem external { require(participants[airdropId][day].totalParticipants == 0, "Day already closed"); participants[airdropId][day].totalParticipants = totalParticipants; } /** * @dev Add approved users. Call function closeDay() before start add users. * * @param airdropId Airdrop ID. * @param day Day number of airdrop. From 1 to airdrop duration * @param users The array of approved users whose claim tokens on this day. About 100 users in the array. */ function addUsers(uint256 airdropId, uint256 day, address[] calldata users) onlySystem external { require(airdrops[airdropId].daysPassed + 1 == day, "Day already passed"); require(airdrops[airdropId].daysPassed < airdrops[airdropId].duration, "Airdrop ended"); uint256 timestamp = block.timestamp / 1 days * 1 days; // align timestamp to 00:00 UTC uint256 totalParticipants = participants[airdropId][day].totalParticipants; uint256 amount = airdrops[airdropId].amount / (airdrops[airdropId].duration * totalParticipants); participants[airdropId][day].addedParticipants += users.length; require (participants[airdropId][day].addedParticipants <= totalParticipants, "Too many users"); if (participants[airdropId][day].addedParticipants == totalParticipants) { airdrops[airdropId].daysPassed = airdrops[airdropId].daysPassed + 1; } for (uint i = 0; i < users.length; i++) { if (receivers[airdropId][users[i]].timestamp == 0) { receivers[airdropId][users[i]].timestamp = timestamp; receivers[airdropId][users[i]].amount = amount; } } } /** * @dev Claim tokens on users behalf when lock period ends. * * @param airdropId Airdrop ID. * @param users The array of users whose lock period ended. About 100 users in the array. */ function claimToken(uint256 airdropId, address[] calldata users) external { for (uint i = 0; i < users.length; i++) { User memory u = receivers[airdropId][users[i]]; if (u.timestamp + lockPeriod <= block.timestamp && u.amount > 0) { delete receivers[airdropId][users[i]]; token.transfer(users[i], u.amount); emit Airdropped(airdropId, users[i], u.amount); } } } function rescueTokens(address _token) onlyOwner external { uint256 amount = IERC223(_token).balanceOf(address(this)); IERC223(_token).transfer(msg.sender, amount); emit Rescue(_token, amount); } }
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"event","name":"AirdropCreated","inputs":[{"type":"uint256","name":"airdropId","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"duration","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Airdropped","inputs":[{"type":"uint256","name":"airdropId","internalType":"uint256","indexed":true},{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Rescue","inputs":[{"type":"address","name":"_token","internalType":"address","indexed":false},{"type":"uint256","name":"_amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetSystem","inputs":[{"type":"address","name":"_system","internalType":"address","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addUsers","inputs":[{"type":"uint256","name":"airdropId","internalType":"uint256"},{"type":"uint256","name":"day","internalType":"uint256"},{"type":"address[]","name":"users","internalType":"address[]"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"duration","internalType":"uint256"},{"type":"uint256","name":"daysPassed","internalType":"uint256"}],"name":"airdrops","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimToken","inputs":[{"type":"uint256","name":"airdropId","internalType":"uint256"},{"type":"address[]","name":"users","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"closeDay","inputs":[{"type":"uint256","name":"airdropId","internalType":"uint256"},{"type":"uint256","name":"day","internalType":"uint256"},{"type":"uint256","name":"totalParticipants","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"airdropId","internalType":"uint256"}],"name":"createAirdrop","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"duration","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAirdropsLength","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct Airdrop.User[]","components":[{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"}]}],"name":"getUserInfo","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lockPeriod","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"totalParticipants","internalType":"uint256"},{"type":"uint256","name":"addedParticipants","internalType":"uint256"}],"name":"participants","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"}],"name":"receivers","inputs":[{"type":"uint256","name":"","internalType":"uint256"},{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueTokens","inputs":[{"type":"address","name":"_token","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSystem","inputs":[{"type":"address","name":"_system","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"system","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC223"}],"name":"token","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tokenReceived","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_value","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101155760003560e01c806381c82648116100a257806395bf75fd1161007157806395bf75fd1461028e578063b4f4613c146102a1578063f2fde38b146102b4578063fc0c546a146102c7578063fe289b65146102da57600080fd5b806381c826481461021157806381fb1fb4146102245780638943ec02146102565780638da5cb5b1461026957600080fd5b806355837757116100e9578063558377571461016157806360db5082146101745780636386c1c7146101a2578063715018a6146101c25780637cf27c39146101ca57600080fd5b8062ae3bf81461011a57806318809fd51461012f5780633fd8b02f14610146578063429d299e1461014e575b600080fd5b61012d610128366004610fb6565b6102ed565b005b6004545b6040519081526020015b60405180910390f35b61013360b481565b61012d61015c366004611024565b610473565b61012d61016f366004610fb6565b61086b565b610187610182366004611077565b6108f8565b6040805193845260208401929092529082015260600161013d565b6101b56101b0366004610fb6565b61092b565b60405161013d9190611090565b61012d610a10565b6101fc6101d83660046110df565b60026020908152600092835260408084209091529082529020805460019091015482565b6040805192835260208301919091520161013d565b61012d61021f36600461110b565b610a93565b6101fc610232366004611157565b60036020908152600092835260408084209091529082529020805460019091015482565b61012d61026436600461118f565b505050565b6000546001600160a01b03165b6040516001600160a01b03909116815260200161013d565b600554610276906001600160a01b031681565b6101336102af366004611157565b610cd7565b61012d6102c2366004610fb6565b610dff565b600154610276906001600160a01b031681565b61012d6102e836600461125a565b610ef8565b336103006000546001600160a01b031690565b6001600160a01b03161461032f5760405162461bcd60e51b815260040161032690611286565b60405180910390fd5b6040516370a0823160e01b81523060048201526000906001600160a01b038316906370a082319060240160206040518083038186803b15801561037157600080fd5b505afa158015610385573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103a991906112bb565b60405163a9059cbb60e01b8152336004820152602481018290529091506001600160a01b0383169063a9059cbb90604401602060405180830381600087803b1580156103f457600080fd5b505af1158015610408573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042c91906112d4565b50604080516001600160a01b0384168152602081018390527f542fa6bfee3b4746210fbdd1d83f9e49b65adde3639f8d8f165dd18347938af2910160405180910390a15050565b6005546001600160a01b0316331461049d5760405162461bcd60e51b815260040161032690611286565b82600485815481106104b1576104b16112f6565b90600052602060002090600302016002015460016104cf9190611322565b146105115760405162461bcd60e51b815260206004820152601260248201527111185e48185b1c9958591e481c185cdcd95960721b6044820152606401610326565b60048481548110610524576105246112f6565b90600052602060002090600302016001015460048581548110610549576105496112f6565b906000526020600020906003020160020154106105985760405162461bcd60e51b815260206004820152600d60248201526c105a5c991c9bdc08195b991959609a1b6044820152606401610326565b60006105a7620151804261133a565b6105b4906201518061135c565b6000868152600360209081526040808320888452909152812054600480549394509092839190899081106105ea576105ea6112f6565b906000526020600020906003020160010154610606919061135c565b60048881548110610619576106196112f6565b906000526020600020906003020160000154610635919061133a565b60008881526003602090815260408083208a8452909152812060010180549293508692909190610666908490611322565b909155505060008781526003602090815260408083208984529091529020600101548210156106c85760405162461bcd60e51b815260206004820152600e60248201526d546f6f206d616e7920757365727360901b6044820152606401610326565b600087815260036020908152604080832089845290915290206001015482141561074657600487815481106106ff576106ff6112f6565b906000526020600020906003020160020154600161071d9190611322565b60048881548110610730576107306112f6565b9060005260206000209060030201600201819055505b60005b8481101561086157600088815260026020526040812090878784818110610772576107726112f6565b90506020020160208101906107879190610fb6565b6001600160a01b0316815260208101919091526040016000205461084f57600088815260026020526040812085918888858181106107c7576107c76112f6565b90506020020160208101906107dc9190610fb6565b6001600160a01b0316815260208082019290925260409081016000908120939093558a835260029091528120839188888581811061081c5761081c6112f6565b90506020020160208101906108319190610fb6565b6001600160a01b031681526020810191909152604001600020600101555b806108598161137b565b915050610749565b5050505050505050565b3361087e6000546001600160a01b031690565b6001600160a01b0316146108a45760405162461bcd60e51b815260040161032690611286565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f49cd4dad53143519125de2da7395d254bd24b8f3c049554685fadeafc1fd96c89060200160405180910390a150565b6004818154811061090857600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b60045460609060008167ffffffffffffffff81111561094c5761094c611179565b60405190808252806020026020018201604052801561099157816020015b604080518082019091526000808252602082015281526020019060019003908161096a5790505b50905060005b82811015610a085760008181526002602090815260408083206001600160a01b0389168452825291829020825180840190935280548352600101549082015282518390839081106109ea576109ea6112f6565b60200260200101819052508080610a009061137b565b915050610997565b509392505050565b33610a236000546001600160a01b031690565b6001600160a01b031614610a495760405162461bcd60e51b815260040161032690611286565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b60005b81811015610cd157600084815260026020526040812081858585818110610abf57610abf6112f6565b9050602002016020810190610ad49190610fb6565b6001600160a01b03166001600160a01b031681526020019081526020016000206040518060400160405290816000820154815260200160018201548152505090504260b48260000151610b279190611322565b11158015610b39575060008160200151115b15610cbe57600085815260026020526040812090858585818110610b5f57610b5f6112f6565b9050602002016020810190610b749190610fb6565b6001600160a01b03908116825260208201929092526040016000908120818155600190810191909155541663a9059cbb858585818110610bb657610bb66112f6565b9050602002016020810190610bcb9190610fb6565b60208401516040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401602060405180830381600087803b158015610c1657600080fd5b505af1158015610c2a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4e91906112d4565b50838383818110610c6157610c616112f6565b9050602002016020810190610c769190610fb6565b6001600160a01b0316857f745451e9085df6151853070d092cd5b0409d5888d965ea556a9734dabde8801b8360200151604051610cb591815260200190565b60405180910390a35b5080610cc98161137b565b915050610a96565b50505050565b600033610cec6000546001600160a01b031690565b6001600160a01b031614610d125760405162461bcd60e51b815260040161032690611286565b50600480546040805160608082018352868252602080830187815260008486018181526001880189559790529251600386027f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b81019190915592517f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19c84015594517f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19d90920191909155815183815293840186905290830184905290917f87620792bbfc30ecd66cb6c71bb4ffc7323cf9f22c2bbaceca6d37a6a70942cd910160405180910390a192915050565b33610e126000546001600160a01b031690565b6001600160a01b031614610e385760405162461bcd60e51b815260040161032690611286565b6001600160a01b038116610e9d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610326565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6005546001600160a01b03163314610f225760405162461bcd60e51b815260040161032690611286565b600083815260036020908152604080832085845290915290205415610f7e5760405162461bcd60e51b815260206004820152601260248201527111185e48185b1c9958591e4818db1bdcd95960721b6044820152606401610326565b6000928352600360209081526040808520938552929052912055565b80356001600160a01b0381168114610fb157600080fd5b919050565b600060208284031215610fc857600080fd5b610fd182610f9a565b9392505050565b60008083601f840112610fea57600080fd5b50813567ffffffffffffffff81111561100257600080fd5b6020830191508360208260051b850101111561101d57600080fd5b9250929050565b6000806000806060858703121561103a57600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561105f57600080fd5b61106b87828801610fd8565b95989497509550505050565b60006020828403121561108957600080fd5b5035919050565b602080825282518282018190526000919060409081850190868401855b828110156110d2578151805185528601518685015292840192908501906001016110ad565b5091979650505050505050565b600080604083850312156110f257600080fd5b8235915061110260208401610f9a565b90509250929050565b60008060006040848603121561112057600080fd5b83359250602084013567ffffffffffffffff81111561113e57600080fd5b61114a86828701610fd8565b9497909650939450505050565b6000806040838503121561116a57600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156111a457600080fd5b6111ad84610f9a565b925060208401359150604084013567ffffffffffffffff808211156111d157600080fd5b818601915086601f8301126111e557600080fd5b8135818111156111f7576111f7611179565b604051601f8201601f19908116603f0116810190838211818310171561121f5761121f611179565b8160405282815289602084870101111561123857600080fd5b8260208601602083013760006020848301015280955050505050509250925092565b60008060006060848603121561126f57600080fd5b505081359360208301359350604090920135919050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000602082840312156112cd57600080fd5b5051919050565b6000602082840312156112e657600080fd5b81518015158114610fd157600080fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600082198211156113355761133561130c565b500190565b60008261135757634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156113765761137661130c565b500290565b600060001982141561138f5761138f61130c565b506001019056fea26469706673582212204b751c979b95f0495c78d108bbc4ab2f59ff542435de44ba58b8a1a9b1390f7d64736f6c63430008090033