Files

175 lines
5.2 KiB
Solidity

import "./ERC23.sol";
pragma solidity ^0.4.11;
/**
* AbstractToken ECR20-compliant token contract
* Child should implement initial supply or minting and overwite base
* Based on BasicCoin by Parity Team (Ethcore), 2016.
* @author Ricardo Guilherme Schmidt
* Released under the Apache Licence 2.
*/
contract AbstractToken is ERC23 {
mapping (address => Account) private accounts;
function AbstractToken(uint256 _decimals, string _name, string _symbol){
decimals = _decimals;
name = _name;
symbol = _symbol;
}
struct Account {
uint256 balance;
mapping (address => Allowance) allowanceOf;
}
/// @dev `Allowance` structure holds block number of allowance spent
/// and the amount allowed
struct Allowance {
// `amount` to be spent
uint amount;
// `blockSpent` is for blocking change of allowance near spent block
// to prevent race conditions
uint timeSpent;
}
// the balance should be available
modifier when_owns(address _owner, uint256 _amount) {
if (balanceOf(_owner) < _amount) throw;
_;
}
// an allowance should be available
modifier when_has_allowance(address _owner, address _spender, uint256 _amount) {
if (allowance(_owner,_spender) < _amount) throw;
_;
}
//child may override this function to trigger changes in balance dependent storage
function _balanceUpdated(address _from)
internal {
}
// add tokens to a balance
function _mint(address _to, uint256 _value)
internal {
if (totalSupply + _value < totalSupply) throw; //overflow: maximum totalSupply in the current base;
Transfer(0x0, _to, _value);
totalSupply += _value;
accounts[_to].balance += _value;
if(isContract(_to)){
ERC23Receiver(_to).tokenFallback(0x0, _value, new bytes(0));
}
_balanceUpdated(_to);
}
// remove tokens from a balance
function _destroy(address _from, uint256 _value)
internal {
Transfer(_from, 0x0, _value);
totalSupply -= _value;
accounts[_from].balance -= _value;
if(accounts[_from].balance == 0){
delete accounts[_from]; //to reduce gas in mapping accounts
}
_balanceUpdated(_from);
}
// balance of a specific address
function balanceOf(address _who)
constant
returns (uint256) {
return accounts[_who].balance;
}
// transfer
function transfer(address _to, uint256 _value)
when_owns(msg.sender, _value)
returns (bool) {
return _transfer(msg.sender, _to, _value, new bytes(0));
}
function transfer(address _to, uint256 _value, bytes _data) when_owns(msg.sender, _value)
returns (bool) {
return _transfer(msg.sender, _to,_value, _data);
}
// transfer via allowance
function transferFrom(address _from, address _to, uint256 _value)
when_owns(_from, _value)
when_has_allowance(_from, msg.sender, _value)
returns (bool) {
accounts[_from].allowanceOf[msg.sender].amount -= _value;
accounts[_from].allowanceOf[msg.sender].timeSpent = now;
_transfer(_from, _to, _value, new bytes(0));
return true;
}
// set allowance
function approve(address _spender, uint256 _totalAllowed)
returns (bool) {
Approval(msg.sender, _spender, _totalAllowed);
if (_totalAllowed != 0 && now - accounts[msg.sender].allowanceOf[_spender].timeSpent < 30 minutes) throw;
if (_totalAllowed > 0){
accounts[msg.sender].allowanceOf[_spender].amount = _totalAllowed;
} else {
delete accounts[msg.sender].allowanceOf[_spender];
}
return true;
}
function approveAndCall(address _spender, uint256 _totalAllowed, bytes _extraData)
returns (bool) {
if(!approve(_spender,_totalAllowed)) throw;
ApproveAndCallFallBack(_spender).receiveApproval(
msg.sender,
_totalAllowed,
this,
_extraData
);
return true;
}
// available allowance
function allowance(address _owner, address _spender)
constant
returns (uint256) {
return accounts[_owner].allowanceOf[_spender].amount;
}
// transfer
function _transfer(address _from, address _to, uint256 _value, bytes _data)
internal
returns (bool) {
Transfer(_from, _to, _value);
accounts[_from].balance -= _value;
accounts[_to].balance += _value;
_balanceUpdated(_from);
_balanceUpdated(_to);
if(isContract(_to)){
ERC23Receiver(_to).tokenFallback(_from, _value, _data);
}
return true;
}
//assemble the given address bytecode. If bytecode exists then the _addr is a contract.
function isContract(address _addr) internal returns (bool is_contract) {
uint length;
assembly {
//retrieve the size of the code on target address, this needs assembly
length := extcodesize(_addr)
}
if(length>0) {
return true;
}
else {
return false;
}
}
}