Contract Name:
UpgradebleStormSender
Contract Source Code:
File 1 of 1 : UpgradebleStormSender
pragma solidity 0.4.24;
contract EternalStorage {
mapping(bytes32 => uint256) internal uintStorage;
mapping(bytes32 => string) internal stringStorage;
mapping(bytes32 => address) internal addressStorage;
mapping(bytes32 => bytes) internal bytesStorage;
mapping(bytes32 => bool) internal boolStorage;
mapping(bytes32 => int256) internal intStorage;
}
contract UpgradeabilityOwnerStorage {
address private _upgradeabilityOwner;
function upgradeabilityOwner() public view returns (address) {
return _upgradeabilityOwner;
}
function setUpgradeabilityOwner(address newUpgradeabilityOwner) internal {
_upgradeabilityOwner = newUpgradeabilityOwner;
}
}
contract UpgradeabilityStorage {
string internal _version;
address internal _implementation;
function version() public view returns (string) {
return _version;
}
function implementation() public view returns (address) {
return _implementation;
}
}
contract OwnedUpgradeabilityStorage is UpgradeabilityOwnerStorage, UpgradeabilityStorage, EternalStorage {}
library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract Ownable is EternalStorage {
event OwnershipTransferred(address previousOwner, address newOwner);
modifier onlyOwner() {
require(msg.sender == owner());
_;
}
function owner() public view returns (address) {
return addressStorage[keccak256("owner")];
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
setOwner(newOwner);
}
function setOwner(address newOwner) internal {
emit OwnershipTransferred(owner(), newOwner);
addressStorage[keccak256("owner")] = newOwner;
}
}
contract Claimable is EternalStorage, Ownable {
function pendingOwner() public view returns (address) {
return addressStorage[keccak256("pendingOwner")];
}
modifier onlyPendingOwner() {
require(msg.sender == pendingOwner());
_;
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
addressStorage[keccak256("pendingOwner")] = newOwner;
}
function claimOwnership() public onlyPendingOwner {
emit OwnershipTransferred(owner(), pendingOwner());
addressStorage[keccak256("owner")] = addressStorage[keccak256("pendingOwner")];
addressStorage[keccak256("pendingOwner")] = address(0);
}
}
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract UpgradebleStormSender is OwnedUpgradeabilityStorage, Claimable {
using SafeMath for uint256;
event Multisended(uint256 total, address tokenAddress);
event ClaimedTokens(address token, address owner, uint256 balance);
modifier hasFee() {
if (currentFee(msg.sender) > 0) {
require(msg.value >= currentFee(msg.sender));
}
_;
}
function() public payable {}
function initialize(address _owner) public {
require(!initialized());
setOwner(_owner);
setArrayLimit(200);
setDiscountStep(0.00002 ether);
setFee(0.02 ether);
boolStorage[keccak256("rs_multisender_initialized")] = true;
}
function initialized() public view returns (bool) {
return boolStorage[keccak256("rs_multisender_initialized")];
}
function txCount(address customer) public view returns(uint256) {
return uintStorage[keccak256(abi.encodePacked("txCount", customer))];
}
function arrayLimit() public view returns(uint256) {
return uintStorage[keccak256(abi.encodePacked("arrayLimit"))];
}
function setArrayLimit(uint256 _newLimit) public onlyOwner {
require(_newLimit != 0);
uintStorage[keccak256("arrayLimit")] = _newLimit;
}
function discountStep() public view returns(uint256) {
return uintStorage[keccak256("discountStep")];
}
function setDiscountStep(uint256 _newStep) public onlyOwner {
require(_newStep != 0);
uintStorage[keccak256("discountStep")] = _newStep;
}
function fee() public view returns(uint256) {
return uintStorage[keccak256("fee")];
}
function currentFee(address _customer) public view returns(uint256) {
if (fee() > discountRate(msg.sender)) {
return fee().sub(discountRate(_customer));
} else {
return 0;
}
}
function setFee(uint256 _newStep) public onlyOwner {
require(_newStep != 0);
uintStorage[keccak256("fee")] = _newStep;
}
function discountRate(address _customer) public view returns(uint256) {
uint256 count = txCount(_customer);
return count.mul(discountStep());
}
function multisendToken(address token, address[] _contributors, uint256[] _balances) public hasFee payable {
if (token == 0x000000000000000000000000000000000000bEEF){
multisendEther(_contributors, _balances);
} else {
uint256 total = 0;
require(_contributors.length <= arrayLimit());
ERC20 erc20token = ERC20(token);
uint8 i = 0;
for (i; i < _contributors.length; i++) {
erc20token.transferFrom(msg.sender, _contributors[i], _balances[i]);
total += _balances[i];
}
setTxCount(msg.sender, txCount(msg.sender).add(1));
emit Multisended(total, token);
}
}
function multisendEther(address[] _contributors, uint256[] _balances) public payable {
uint256 total = msg.value;
uint256 userfee = currentFee(msg.sender);
require(total >= userfee);
require(_contributors.length <= arrayLimit());
total = total.sub(userfee);
uint256 i = 0;
for (i; i < _contributors.length; i++) {
require(total >= _balances[i]);
total = total.sub(_balances[i]);
_contributors[i].transfer(_balances[i]);
}
setTxCount(msg.sender, txCount(msg.sender).add(1));
emit Multisended(msg.value, 0x000000000000000000000000000000000000bEEF);
}
function claimTokens(address _token) public onlyOwner {
if (_token == 0x0) {
owner().transfer(address(this).balance);
return;
}
ERC20 erc20token = ERC20(_token);
uint256 balance = erc20token.balanceOf(this);
erc20token.transfer(owner(), balance);
emit ClaimedTokens(_token, owner(), balance);
}
function setTxCount(address customer, uint256 _txCount) private {
uintStorage[keccak256(abi.encodePacked("txCount", customer))] = _txCount;
}
}