mirror of
https://github.com/status-im/github-oracle.git
synced 2026-08-29 10:51:08 +00:00
175 lines
5.2 KiB
Solidity
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;
|
|
}
|
|
}
|
|
|
|
}
|