pragma solidity >=0.4.24;
library SafeMath {
function add(
uint256 a,
uint256 b)
internal
pure
returns(uint256 c)
{
c = a + b;
require(c >= a);
}
function sub(
uint256 a,
uint256 b)
internal
pure
returns(uint256 c)
{
require(b <= a);
c = a - b;
}
function mul(
uint256 a,
uint256 b)
internal
pure
returns(uint256 c) {
c = a * b;
require(a == 0 || c / a == b);
}
function div(
uint256 a,
uint256 b)
internal
pure
returns(uint256 c) {
require(b > 0);
c = a / b;
}
}
interface IERC20 {
// ERC20 Optional Views
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
// Views
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
// Mutative functions
function transfer(address to, uint value) external returns (bool);
function approve(address spender, uint value) external returns (bool);
function transferFrom(
address from,
address to,
uint value
) external returns (bool);
// Events
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
// https://docs.synthetix.io/contracts/source/contracts/owned
contract Owned {
address public owner;
address public nominatedOwner;
constructor(address _owner) public {
require(_owner != address(0), "Owner address cannot be 0");
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
modifier onlyOwner {
_onlyOwner();
_;
}
function _onlyOwner() private view {
require(msg.sender == owner, "Only the contract owner may perform this action");
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}
contract Pausable is Owned {
event Pause();
event Unpause();
bool public paused = false;
modifier whenNotPaused() {
require(!paused);
_;
}
modifier whenPaused() {
require(paused);
_;
}
function pause() onlyOwner whenNotPaused public {
paused = true;
emit Pause();
}
function unpause() onlyOwner whenPaused public {
paused = false;
emit Unpause();
}
}
pragma solidity >=0.4.24;
contract IDODistribution is Owned, Pausable {
using SafeMath for uint;
/**
* @notice Authorised address able to call batchDeposit
*/
address public authority;
/**
* @notice Address of ERC20 token
*/
address public erc20Address;
mapping(address => uint) balances;
mapping(address => uint) counts;
uint public totalSupply;
constructor(
address _owner,
address _authority
) public Owned(_owner) {
authority = _authority;
}
function balanceOf(address _address) public view returns (uint) {
return balances[_address];
}
function depositNumberOf(address _address) public view returns (uint) {
return counts[_address];
}
// ========== EXTERNAL SETTERS ==========
function setTokenAddress(address _erc20Address) public onlyOwner {
erc20Address = _erc20Address;
}
/**
* @notice Set the address of the contract authorised to call distributeReward()
* @param _authority Address of the authorised calling contract.
*/
function setAuthority(address _authority) public onlyOwner {
authority = _authority;
}
function batchDeposit(address[] destinations, uint[] amounts) public returns (bool) {
require(msg.sender == authority, "Caller is not authorized");
require(erc20Address != address(0), "erc20 token address is not set");
require(destinations.length == amounts.length, "length of inputs not match");
// we don't need check amount[i] > 0 or destinations != 0x0 because they cannot claim anyway
uint amount = 0;
for (uint i = 0; i < amounts.length; i++) {
amount = amount.add(amounts[i]);
balances[destinations[i]] = balances[destinations[i]].add(amounts[i]);
counts[destinations[i]] += 1;
}
totalSupply = totalSupply.add(amount);
emit TokenDeposit(amount);
return true;
}
function claim() public whenNotPaused returns (bool) {
require(erc20Address != address(0), "erc20 token address is not set");
require(balances[msg.sender] > 0, "account balance is zero");
uint _amount = balances[msg.sender];
require(
IERC20(erc20Address).balanceOf(address(this)) >= _amount,
"This contract does not have enough tokens to distribute"
);
balances[msg.sender] = 0;
IERC20(erc20Address).transfer(msg.sender, _amount);
totalSupply = totalSupply.sub(_amount);
emit UserClaimed(msg.sender, _amount);
return true;
}
/* ========== Events ========== */
event TokenDeposit(uint _amount);
event UserClaimed(address _address, uint _amount);
}
{
"compilationTarget": {
"IDODistribution.sol": "IDODistribution"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"depositNumberOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_erc20Address","type":"address"}],"name":"setTokenAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"erc20Address","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"destinations","type":"address[]"},{"name":"amounts","type":"uint256[]"}],"name":"batchDeposit","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"unpause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"claim","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nominatedOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"paused","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"acceptOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_authority","type":"address"}],"name":"setAuthority","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"authority","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_owner","type":"address"},{"name":"_authority","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_amount","type":"uint256"}],"name":"TokenDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_address","type":"address"},{"indexed":false,"name":"_amount","type":"uint256"}],"name":"UserClaimed","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"oldOwner","type":"address"},{"indexed":false,"name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"}]