pragma solidity ^0.4.15;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal constant 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 constant returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library Utils {
/**
@dev Helper function, determines if a given address is an account or a contract.
@return True if address is a contract, false otherwise
*/
function isContract(address _addr) constant internal returns (bool) {
uint size;
assembly {
size := extcodesize(_addr)
}
return (_addr == 0) ? false : size > 0;
}
}
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
function Ownable() {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
/**
* @title Claimable
* @dev Extension for the Ownable contract, where the ownership needs to be claimed.
* This allows the new owner to accept the transfer.
*/
contract Claimable is Ownable {
address public pendingOwner;
/**
* @dev Modifier throws if called by any account other than the pendingOwner.
*/
modifier onlyPendingOwner() {
require(msg.sender == pendingOwner);
_;
}
/**
* @dev Allows the current owner to set the pendingOwner address.
* @param newOwner The address to transfer ownership to.
*/
function transferOwnership(address newOwner) onlyOwner {
pendingOwner = newOwner;
}
/**
* @dev Allows the pendingOwner address to finalize the transfer.
*/
function claimOwnership() onlyPendingOwner {
OwnershipTransferred(owner, pendingOwner);
owner = pendingOwner;
pendingOwner = 0x0;
}
}
/**
@title Burnable
@dev Burnable custom interface, should allow external contracts to burn tokens on certain conditions.
*/
contract Burnable {
event Burn(address who, uint256 amount);
modifier onlyBurners {
require(isBurner(msg.sender));
_;
}
function burn(address target, uint256 amount) external onlyBurners returns (bool);
function setBurner(address who, bool auth) returns (bool);
function isBurner(address who) constant returns (bool);
}
/**
@title Lockable
@dev Lockable custom interface, should allow external contracts to lock accounts on certain conditions.
*/
contract Lockable {
uint256 public lockExpiration;
/**
@dev Constructor
@param _lockExpiration lock expiration datetime in UNIX time
*/
function Lockable(uint256 _lockExpiration) {
lockExpiration = _lockExpiration;
}
function isLocked(address who) constant returns (bool);
}
/**
@title ERC20 interface
@dev Standard ERC20 Interface.
*/
contract ERC20 {
uint256 public totalSupply;
function balanceOf(address who) constant returns (uint256);
function transfer(address to, uint256 value) returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
function allowance(address owner, address spender) constant returns (uint256);
function transferFrom(address from, address to, uint256 value) returns (bool);
function approve(address spender, uint256 value) returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
@title LWFToken
@dev ERC20 standard.
@dev Extra features: Burnable and Lockable under certain conditions.
@dev contract owner is set to msg.sender, lockExpiration for devs set to: 1535760000 || Saturday, 01-Sep-18 00:00:00 UTC
*/
contract LWFToken is ERC20, Burnable, Lockable(1535760000), Claimable {
using SafeMath for uint256;
// Snapshot of Account balance at specific block
struct Snapshot {
uint256 block;
uint256 balance;
}
struct Account {
uint256 balance;
Snapshot[] history; // history of snapshots
mapping(address => uint256) allowed;
bool isSet;
}
address[] accountsList;
mapping(address => Account) accounts;
bool public maintenance;
// BURN SETTINGS
mapping(address => bool) burners; // contracts authorized to block tokens
bool public burnAllowed;
// LOCK SETTINGS
mapping(address => bool) locked; //locked users addresses
// COSMETIC THINGS
string public name = "LWF";
string public symbol = "LWF";
string public version = "release-1.1";
uint256 public decimals = 2;
/**
@dev Throws if token is under maintenance.
*/
modifier disabledInMaintenance() {
if (maintenance)
revert();
_;
}
/**
@dev Throws if token is not under maintenance.
*/
modifier onlyUnderMaintenance() {
if (!maintenance)
revert();
_;
}
/**
@dev Registers the recipient account when tokens are sent to an unregistered account.
@param _recipient the recipient of the transfer
*/
modifier trackNewUsers (address _recipient) {
if (!accounts[_recipient].isSet) {
accounts[_recipient].isSet = true;
accountsList.push(_recipient);
}
_;
}
/**
@dev The constructor sets the initial balance to 30 million tokens.
@dev 27 million assigned to the contract owner.
@dev 3 million reserved and locked. (except bounty)
@dev Holders history is updated for data integrity.
@dev Burn functionality are enabled by default.
*/
function LWFToken() {
totalSupply = 30 * (10**6) * (10**decimals);
burnAllowed = true;
maintenance = false;
require(_setup(0x927Dc9F1520CA2237638D0D3c6910c14D9a285A8, 2700000000, false));
require(_setup(0x7AE7155fF280D5da523CDDe3855b212A8381F9E8, 30000000, false));
require(_setup(0x796d507A80B13c455c2C1D121eDE4bccca59224C, 263000000, true));
require(_setup(0xD77d620EC9774295ad8263cBc549789EE39C0BC0, 1000000, true));
require(_setup(0x574B35eC5650BE0aC217af9AFCfe1c7a3Ff0BecD, 1000000, true));
require(_setup(0x7c5a61f34513965AA8EC090011721a0b0A9d4D3a, 1000000, true));
require(_setup(0x0cDBb03DD2E8226A6c3a54081E93750B4f85DB92, 1000000, true));
require(_setup(0x03b6cF4A69fF306B3df9B9CeDB6Dc4ED8803cBA7, 1000000, true));
require(_setup(0xe2f7A1218E5d4a362D1bee8d2eda2cd285aAE87A, 1000000, true));
require(_setup(0xAcceDE2eFD2765520952B7Cb70406A43FC17e4fb, 1000000, true));
}
/**
@return accountsList length
*/
function accountsListLength() external constant returns (uint256) {
return accountsList.length;
}
/**
@dev Gets the address of any account in 'accountList'.
@param _index The index to query the address of
@return An address pointing to a registered account
*/
function getAccountAddress(uint256 _index) external constant returns (address) {
return accountsList[_index];
}
/**
@dev Checks if an accounts is registered.
@param _address The address to check
@return A bool set true if the account is registered, false otherwise
*/
function isSet(address _address) external constant returns (bool) {
return accounts[_address].isSet;
}
/**
@dev Gets the balance of the specified address at the first block minor or equal the specified block
@param _owner The address to query the the balance of
@param _block The block
@return An uint256 representing the amount owned by the passed address at the specified block.
*/
function balanceAt(address _owner, uint256 _block) external constant returns (uint256 balance) {
uint256 i = accounts[_owner].history.length;
do {
i--;
} while (i > 0 && accounts[_owner].history[i].block > _block);
uint256 matchingBlock = accounts[_owner].history[i].block;
uint256 matchingBalance = accounts[_owner].history[i].balance;
return (i == 0 && matchingBlock > _block) ? 0 : matchingBalance;
}
/**
@dev Authorized contracts can burn tokens.
@param _amount Quantity of tokens to burn
@return A bool set true if successful, false otherwise
*/
function burn(address _address, uint256 _amount) onlyBurners disabledInMaintenance external returns (bool) {
require(burnAllowed);
var _balance = accounts[_address].balance;
accounts[_address].balance = _balance.sub(_amount);
// update history with recent burn
require(_updateHistory(_address));
totalSupply = totalSupply.sub(_amount);
Burn(_address,_amount);
Transfer(_address, 0x0, _amount);
return true;
}
/**
@dev Send a specified amount of tokens from sender address to '_recipient'.
@param _recipient address receiving tokens
@param _amount the amount of tokens to be transferred
@return A bool set true if successful, false otherwise
*/
function transfer(address _recipient, uint256 _amount) returns (bool) {
require(!isLocked(msg.sender));
return _transfer(msg.sender,_recipient,_amount);
}
/**
@dev Transfer tokens from one address to another
@param _from address The address which you want to send tokens from
@param _to address The address which you want to transfer to
@param _amount the amount of tokens to be transferred
@return A bool set true if successful, false otherwise
*/
function transferFrom(address _from, address _to, uint256 _amount) returns (bool) {
require(!isLocked(_from));
require(_to != address(0));
var _allowance = accounts[_from].allowed[msg.sender];
// Check is not needed because sub(_allowance, _amount) will already throw if this condition is not met
// require (_amount <= _allowance);
accounts[_from].allowed[msg.sender] = _allowance.sub(_amount);
return _transfer(_from, _to, _amount);
}
/**
@dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
@param _spender The address which will spend the funds.
@param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) returns (bool) {
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender, 0)` if it is not
// already 0 to mitigate the race condition
require((_value == 0) || (accounts[msg.sender].allowed[_spender] == 0));
accounts[msg.sender].allowed[_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
/**
@dev Approve should be called when allowed[_spender] == 0. To increment
allowed value is better to use this function to avoid 2 calls (and wait until
the first transaction is mined)
@param _spender The address which will spend the funds
@param _addedValue The value which will be added from the allowed balance
*/
function increaseApproval(address _spender, uint _addedValue) returns (bool success) {
uint256 _allowance = accounts[msg.sender].allowed[_spender];
accounts[msg.sender].allowed[_spender] = _allowance.add(_addedValue);
Approval(msg.sender, _spender, accounts[msg.sender].allowed[_spender]);
return true;
}
/**
@dev Approve should be called when allowed[_spender] == 0. To decrement
allowed value is better to use this function to avoid 2 calls (and wait until
the first transaction is mined)
@param _spender The address which will spend the funds
@param _subtractedValue The value which will be subtracted from the allowed balance
@return A bool set true if successful, false otherwise
*/
function decreaseApproval (address _spender, uint _subtractedValue) returns (bool success) {
uint oldValue = accounts[msg.sender].allowed[_spender];
accounts[msg.sender].allowed[_spender] = (_subtractedValue > oldValue) ? 0 : oldValue.sub(_subtractedValue);
Approval(msg.sender, _spender, accounts[msg.sender].allowed[_spender]);
return true;
}
/**
@dev Sets a contract authorization to burn tokens.
@param _address The address to authorize/deauthorize
@param _auth True for authorization, false otherwise
@return A bool set true if successful, false otherwise
*/
function setBurner(address _address, bool _auth) onlyOwner returns (bool) {
require(burnAllowed);
assert(Utils.isContract(_address));
burners[_address] = _auth;
return true;
}
/**
@dev Checks if the provided contract can burn tokens.
@param _address The address to check
@return A bool set true if authorized, false otherwise
*/
function isBurner(address _address) constant returns (bool) {
return burnAllowed ? burners[_address] : false;
}
/**
@dev Checks if the token owned by the provided address are locked.
@param _address The address to check
@return A bool set true if locked, false otherwise
*/
function isLocked(address _address) constant returns (bool) {
return now >= lockExpiration ? false : locked[_address];
}
/**
@dev Function permanently disabling 'burn()' and 'setBurner()'.
@dev Already burned tokens are not recoverable.
@dev Effects of this transaction are irreversible.
@return A bool set true if successful, false otherwise
*/
function burnFeatureDeactivation() onlyOwner returns (bool) {
require(burnAllowed);
burnAllowed = false;
return true;
}
/**
@dev Gets the balance of the specified address.
@param _owner The address to query the the balance of.
@return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) constant returns (uint256 balance) {
return accounts[_owner].balance;
}
/**
@dev Function to check the amount of tokens that an owner allowed to a spender.
@param _owner address The address which owns the funds.
@param _spender address The address which will spend the funds.
@return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return accounts[_owner].allowed[_spender];
}
/**
@dev Sets the maintenance mode. During maintenance operations modifying balances are frozen.
@param _state true if maintenance is on, false otherwise
@return A bool set true if successful, false otherwise
*/
function setMaintenance(bool _state) onlyOwner returns (bool) {
maintenance = _state;
return true;
}
/**
@dev Maintenance function, if accountsList grows too long back end can safely clean unused accounts
and push the renewed list into the contract.
@dev Accounts removed from the list must be deactivated with maintenanceDeactivateUser(_user)
@param _accountsList A list containing the accounts' addresses
@return A bool set true if successful, false otherwise
*/
function maintenanceSetAccountsList(address[] _accountsList) onlyOwner onlyUnderMaintenance returns (bool) {
accountsList = _accountsList;
return true;
}
/**
@dev Maintenance function reserved to back end, removes an account from the list.
@return A bool set true if successful, false otherwise
*/
function maintenanceDeactivateUser(address _user) onlyOwner onlyUnderMaintenance returns (bool) {
accounts[_user].isSet = false;
delete accounts[_user].history;
return true;
}
/**
@dev Auxiliary method used in constructor to reserve some tokens and lock them in some cases.
@param _address The address to assign tokens
@param _amount The amount of tokens
@param _lock True to lock until 'lockExpiration', false to not
@return A bool set true if successful, false otherwise
*/
function _setup(address _address, uint256 _amount, bool _lock) internal returns (bool) {
locked[_address] = _lock;
accounts[_address].balance = _amount;
accounts[_address].isSet = true;
require(_updateHistory(_address));
accountsList.push(_address);
Transfer(this, _address, _amount);
return true;
}
/**
@dev Function implementing the shared logic of 'transfer()' and 'transferFrom()'
@param _from address sending tokens
@param _recipient address receiving tokens
@param _amount tokens to send
@return A bool set true if successful, false otherwise
*/
function _transfer(address _from, address _recipient, uint256 _amount) internal disabledInMaintenance trackNewUsers(_recipient) returns (bool) {
accounts[_from].balance = balanceOf(_from).sub(_amount);
accounts[_recipient].balance = balanceOf(_recipient).add(_amount);
// save this transaction in both accounts history
require(_updateHistory(_from));
require(_updateHistory(_recipient));
Transfer(_from, _recipient, _amount);
return true;
}
/**
@dev Updates the user history with the latest balance.
@param _address The Account's address to update
@return A bool set true if successful, false otherwise
*/
function _updateHistory(address _address) internal returns (bool) {
accounts[_address].history.push(Snapshot(block.number, balanceOf(_address)));
return true;
}
}
{
"compilationTarget": {
"LWFToken.sol": "LWFToken"
},
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"},{"name":"_auth","type":"bool"}],"name":"setBurner","outputs":[{"name":"","type":"bool"}],"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":"_accountsList","type":"address[]"}],"name":"maintenanceSetAccountsList","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_user","type":"address"}],"name":"maintenanceDeactivateUser","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_block","type":"uint256"}],"name":"balanceAt","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"accountsListLength","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"isBurner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"isLocked","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"claimOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_state","type":"bool"}],"name":"setMaintenance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"burnAllowed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lockExpiration","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maintenance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"isSet","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_address","type":"address"},{"name":"_amount","type":"uint256"}],"name":"burn","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipient","type":"address"},{"name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_index","type":"uint256"}],"name":"getAccountAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"burnFeatureDeactivation","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"who","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]