Contract Source Code:
File 1 of 1 : Token
pragma solidity ^0.4.24;
/* ANCI
// Antrodia Cinamomum Token (ANCI)
// ERC20 Contract with Timelock capabilities
// The bigger intricate timelock mechanisms out here
// ---
// ---
// _ _ _ _ _ ___ ___ ___
// | |_| |_ ___ /_\ | \| |/ __|_ _| | _ \_____ __ _____ _ _
// | _| ' \/ -_) / _ \| .` | (__ | | | _/ _ \ V V / -_) '_|
// \__|_||_\___| /_/ \_\_|\_|\___|___| |_| \___/\_/\_/\___|_|
//
// ---
// ---
*/
/* an owner is required */
contract Owned {
address public owner;
function Owned() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function setOwner(address _owner) onlyOwner public {
owner = _owner;
}
}
/* SafeMath implementation to guard against overflows */
contract SafeMath {
function add(uint256 _a, uint256 _b) internal pure returns (uint256) {
uint256 c = _a + _b;
assert(c >= _a); // checks for overflow
return c;
}
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_a >= _b); // guards against overflow
return _a - _b;
}
function mul(uint256 _a, uint256 _b) internal pure returns (uint256) {
uint256 c = _a * _b;
assert(_a == 0 || c / _a == _b); // checks for overflow
return c;
}
}
/* The main contract for the timelock capable ERC20 token */
contract Token is SafeMath, Owned {
uint256 constant DAY_IN_SECONDS = 86400;
string public constant standard = "0.777";
string public name = "";
string public symbol = "";
uint8 public decimals = 0;
uint256 public totalSupply = 0;
mapping (address => uint256) public balanceP;
mapping (address => mapping (address => uint256)) public allowance;
mapping (address => uint256[]) public lockTime;
mapping (address => uint256[]) public lockValue;
mapping (address => uint256) public lockNum;
mapping (address => bool) public locker;
uint256 public later = 0;
uint256 public earlier = 0;
/* standard ERC20 events */
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
/* custom lock-related events */
event TransferredLocked(address indexed _from, address indexed _to, uint256 _time, uint256 _value);
event TokenUnlocked(address indexed _address, uint256 _value);
/* ERC20 constructor */
function Token(string _name, string _symbol, uint8 _decimals, uint256 _totalSupply) public {
require(bytes(_name).length > 0 && bytes(_symbol).length > 0);
name = _name;
symbol = _symbol;
decimals = _decimals;
totalSupply = _totalSupply;
balanceP[msg.sender] = _totalSupply;
}
/* don't allow zero address */
modifier validAddress(address _address) {
require(_address != 0x0);
_;
}
/* owner may add & remove optional locker contract */
function addLocker(address _address) public validAddress(_address) onlyOwner {
locker[_address] = true;
}
function removeLocker(address _address) public validAddress(_address) onlyOwner {
locker[_address] = false;
}
/* owner may fast-forward or delay ALL timelocks */
function setUnlockEarlier(uint256 _earlier) public onlyOwner {
earlier = add(earlier, _earlier);
}
function setUnlockLater(uint256 _later) public onlyOwner {
later = add(later, _later);
}
/* shows unlocked balance */
function balanceUnlocked(address _address) public view returns (uint256 _balance) {
_balance = balanceP[_address];
uint256 i = 0;
while (i < lockNum[_address]) {
if (add(now, earlier) > add(lockTime[_address][i], later)) _balance = add(_balance, lockValue[_address][i]);
i++;
}
return _balance;
}
/* shows locked balance */
function balanceLocked(address _address) public view returns (uint256 _balance) {
_balance = 0;
uint256 i = 0;
while (i < lockNum[_address]) {
if (add(now, earlier) < add(lockTime[_address][i], later)) _balance = add(_balance, lockValue[_address][i]);
i++;
}
return _balance;
}
/* standard ERC20 compatible balance accessor */
function balanceOf(address _address) public view returns (uint256 _balance) {
_balance = balanceP[_address];
uint256 i = 0;
while (i < lockNum[_address]) {
_balance = add(_balance, lockValue[_address][i]);
i++;
}
return _balance;
}
/* show the timelock periods and locked values */
function showTime(address _address) public view validAddress(_address) returns (uint256[] _time) {
uint i = 0;
uint256[] memory tempLockTime = new uint256[](lockNum[_address]);
while (i < lockNum[_address]) {
tempLockTime[i] = sub(add(lockTime[_address][i], later), earlier);
i++;
}
return tempLockTime;
}
function showValue(address _address) public view validAddress(_address) returns (uint256[] _value) {
return lockValue[_address];
}
/* calculates and handles the timelocks before related operations */
function calcUnlock(address _address) private {
uint256 i = 0;
uint256 j = 0;
uint256[] memory currentLockTime;
uint256[] memory currentLockValue;
uint256[] memory newLockTime = new uint256[](lockNum[_address]);
uint256[] memory newLockValue = new uint256[](lockNum[_address]);
currentLockTime = lockTime[_address];
currentLockValue = lockValue[_address];
while (i < lockNum[_address]) {
if (add(now, earlier) > add(currentLockTime[i], later)) {
balanceP[_address] = add(balanceP[_address], currentLockValue[i]);
/* emit custom timelock expiration event */
emit TokenUnlocked(_address, currentLockValue[i]);
} else {
newLockTime[j] = currentLockTime[i];
newLockValue[j] = currentLockValue[i];
j++;
}
i++;
}
uint256[] memory trimLockTime = new uint256[](j);
uint256[] memory trimLockValue = new uint256[](j);
i = 0;
while (i < j) {
trimLockTime[i] = newLockTime[i];
trimLockValue[i] = newLockValue[i];
i++;
}
lockTime[_address] = trimLockTime;
lockValue[_address] = trimLockValue;
lockNum[_address] = j;
}
/* ERC20 compliant transfer method */
function transfer(address _to, uint256 _value) public validAddress(_to) returns (bool success) {
if (lockNum[msg.sender] > 0) calcUnlock(msg.sender);
if (balanceP[msg.sender] >= _value && _value > 0) {
balanceP[msg.sender] = sub(balanceP[msg.sender], _value);
balanceP[_to] = add(balanceP[_to], _value);
emit Transfer(msg.sender, _to, _value);
return true;
}
else {
return false;
}
}
/* custom timelocked transfer method */
function transferLocked(address _to, uint256[] _time, uint256[] _value) public validAddress(_to) returns (bool success) {
require(_value.length == _time.length);
if (lockNum[msg.sender] > 0) calcUnlock(msg.sender);
uint256 i = 0;
uint256 totalValue = 0;
while (i < _value.length) {
totalValue = add(totalValue, _value[i]);
i++;
}
if (balanceP[msg.sender] >= totalValue && totalValue > 0) {
i = 0;
while (i < _time.length) {
balanceP[msg.sender] = sub(balanceP[msg.sender], _value[i]);
lockTime[_to].length = lockNum[_to]+1;
lockValue[_to].length = lockNum[_to]+1;
lockTime[_to][lockNum[_to]] = add(now, _time[i]);
lockValue[_to][lockNum[_to]] = _value[i];
/* emit custom timelock event */
emit TransferredLocked(msg.sender, _to, lockTime[_to][lockNum[_to]], lockValue[_to][lockNum[_to]]);
/* emit standard transfer event */
emit Transfer(msg.sender, _to, lockValue[_to][lockNum[_to]]);
lockNum[_to]++;
i++;
}
return true;
}
else {
return false;
}
}
/* custom timelocker method */
function transferLockedFrom(address _from, address _to, uint256[] _time, uint256[] _value) public
validAddress(_from) validAddress(_to) returns (bool success) {
require(locker[msg.sender]);
require(_value.length == _time.length);
if (lockNum[_from] > 0) calcUnlock(_from);
uint256 i = 0;
uint256 totalValue = 0;
while (i < _value.length) {
totalValue = add(totalValue, _value[i]);
i++;
}
if (balanceP[_from] >= totalValue && totalValue > 0) {
i = 0;
while (i < _time.length) {
balanceP[_from] = sub(balanceP[_from], _value[i]);
lockTime[_to].length = lockNum[_to]+1;
lockValue[_to].length = lockNum[_to]+1;
lockTime[_to][lockNum[_to]] = add(now, _time[i]);
lockValue[_to][lockNum[_to]] = _value[i];
/* emit custom timelock event */
emit TransferredLocked(_from, _to, lockTime[_to][lockNum[_to]], lockValue[_to][lockNum[_to]]);
/* emit standard transfer event */
emit Transfer(_from, _to, lockValue[_to][lockNum[_to]]);
lockNum[_to]++;
i++;
}
return true;
}
else {
return false;
}
}
/* standard ERC20 compliant transferFrom method */
function transferFrom(address _from, address _to, uint256 _value) public validAddress(_from) validAddress(_to) returns (bool success) {
if (lockNum[_from] > 0) calcUnlock(_from);
if (balanceP[_from] >= _value && _value > 0) {
allowance[_from][msg.sender] = sub(allowance[_from][msg.sender], _value);
balanceP[_from] = sub(balanceP[_from], _value);
balanceP[_to] = add(balanceP[_to], _value);
emit Transfer(_from, _to, _value);
return true;
}
else {
return false;
}
}
/* standard ERC20 compliant approve method */
function approve(address _spender, uint256 _value) public validAddress(_spender) returns (bool success) {
require(_value == 0 || allowance[msg.sender][_spender] == 0);
if (lockNum[msg.sender] > 0) calcUnlock(msg.sender);
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/* safety method against ether transfer */
function () public payable {
revert();
}
}