Contract Source Code:
File 1 of 1 : ApisToken
pragma solidity ^0.4.18;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
uint256 public totalSupply;
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);
}
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
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;
}
}
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
// SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
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) public view returns (uint256 balance) {
return balances[_owner];
}
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
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);
}
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
/**
* @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 _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[_from]);
require(_value <= allowed[_from][msg.sender]);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
*
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
/**
* @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) public view returns (uint256) {
return allowed[_owner][_spender];
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
*
* 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)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _addedValue The amount of tokens to increase the allowance by.
*/
function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
*
* 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)
* From MonolithDAO Token.sol
* @param _spender The address which will spend the funds.
* @param _subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
/**
* @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;
address public newOwner;
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() public {
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) public onlyOwner {
require(_newOwner != address(0));
OwnershipTransferred(owner, _newOwner);
newOwner = _newOwner;
}
/**
* @dev μλ‘μ΄ κ΄λ¦¬μκ° μΉμΈν΄μΌλ§ μμ κΆμ΄ μ΄μ λλ€
*/
function acceptOwnership() public {
require(msg.sender == newOwner);
OwnershipTransferred(owner, newOwner);
owner = newOwner;
newOwner = address(0);
}
}
/**
* @title APIS Token
* @dev APIS ν ν°μ μμ±νλ€
*/
contract ApisToken is StandardToken, Ownable {
// ν ν°μ μ΄λ¦
string public constant name = "APIS";
// ν ν°μ λ¨μ
string public constant symbol = "APIS";
// μμμ μ리μ. ETH 18μ리μ λ§μΆλ€
uint8 public constant decimals = 18;
// μ§κ°λ³λ‘ μ‘κΈ/μκΈ κΈ°λ₯μ μ κΈ΄ μ¬λΆλ₯Ό μ μ₯
mapping (address => LockedInfo) public lockedWalletInfo;
/**
* @dev νλ«νΌμμ μ΄μνλ λ§μ€ν°λ
Έλ μ€λ§νΈ 컨νΈλ νΈ μ£Όμ
*/
mapping (address => bool) public manoContracts;
/**
* @dev ν ν° μ§κ°μ μ κΉ μμ±μ μ μ
*
* @param timeLockUpEnd timeLockUpEnd μκ°κΉμ§ μ‘/μκΈμ λν μ νμ΄ μ μ©λλ€. μ΄νμλ μ νμ΄ νλ¦°λ€
* @param sendLock μΆκΈ μ κΉ μ¬λΆ(true : μ κΉ, false : νλ¦Ό)
* @param receiveLock μ
κΈ μ κΉ μ¬λΆ (true : μ κΉ, false : νλ¦Ό)
*/
struct LockedInfo {
uint timeLockUpEnd;
bool sendLock;
bool receiveLock;
}
/**
* @dev ν ν°μ΄ μ‘κΈλμ λ λ°μνλ μ΄λ²€νΈ
* @param from ν ν°μ 보λ΄λ μ§κ° μ£Όμ
* @param to ν ν°μ λ°λ μ§κ° μ£Όμ
* @param value μ λ¬λλ ν ν°μ μ (Satoshi)
*/
event Transfer (address indexed from, address indexed to, uint256 value);
/**
* @dev ν ν° μ§κ°μ μ‘κΈ/μ
κΈ κΈ°λ₯μ΄ μ νλμμ λ λ°μνλ μ΄λ²€νΈ
* @param target μ ν λμ μ§κ° μ£Όμ
* @param timeLockUpEnd μ νμ΄ μ’
λ£λλ μκ°(UnixTimestamp)
* @param sendLock μ§κ°μμμ μ‘κΈμ μ ννλμ§ μ¬λΆ(true : μ ν, false : ν΄μ )
* @param receiveLock μ§κ°μΌλ‘μ μ
κΈμ μ ννλμ§ μ¬λΆ (true : μ ν, false : ν΄μ )
*/
event Locked (address indexed target, uint timeLockUpEnd, bool sendLock, bool receiveLock);
/**
* @dev μ§κ°μ λν μ‘κΈ/μ
κΈ μ νμ ν΄μ νμ λ λ°μνλ μ΄λ²€νΈ
* @param target ν΄μ λμ μ§κ° μ£Όμ
*/
event Unlocked (address indexed target);
/**
* @dev μ‘κΈ λ°λ μ§κ°μ μ
κΈμ΄ μ νλμ΄μμ΄μ μ‘κΈμ΄ κ±°μ λμμ λ λ°μνλ μ΄λ²€νΈ
* @param from ν ν°μ 보λ΄λ μ§κ° μ£Όμ
* @param to (μ
κΈμ΄ μ νλ) ν ν°μ λ°λ μ§κ° μ£Όμ
* @param value μ μ‘νλ €κ³ ν ν ν°μ μ(Satoshi)
*/
event RejectedPaymentToLockedUpWallet (address indexed from, address indexed to, uint256 value);
/**
* @dev μ‘κΈνλ μ§κ°μ μΆκΈμ΄ μ νλμ΄μμ΄μ μ‘κΈμ΄ κ±°μ λμμ λ λ°μνλ μ΄λ²€νΈ
* @param from (μΆκΈμ΄ μ νλ) ν ν°μ 보λ΄λ μ§κ° μ£Όμ
* @param to ν ν°μ λ°λ μ§κ° μ£Όμ
* @param value μ μ‘νλ €κ³ ν ν ν°μ μ(Satoshi)
*/
event RejectedPaymentFromLockedUpWallet (address indexed from, address indexed to, uint256 value);
/**
* @dev ν ν°μ μκ°νλ€.
* @param burner ν ν°μ μκ°νλ μ§κ° μ£Όμ
* @param value μκ°νλ ν ν°μ μ(Satoshi)
*/
event Burn (address indexed burner, uint256 value);
/**
* @dev μνΌμ€ νλ«νΌμ λ§μ€ν°λ
Έλ μ€λ§νΈ 컨νΈλ νΈκ° λ±λ‘λκ±°λ ν΄μ λ λ λ°μνλ μ΄λ²€νΈ
*/
event ManoContractRegistered (address manoContract, bool registered);
/**
* @dev 컨νΈλνΈκ° μμ±λ λ μ€ν. 컨νΈλ νΈ μμ μ μ§κ°μ λͺ¨λ ν ν°μ ν λΉνλ€.
* λ°νλμ΄λ μ΄λ¦μ μμ€μ½λμμ νμΈν μ μλλ‘ λ³κ²½νμμ
*/
function ApisToken() public {
// μ΄ APIS λ°νλ (95μ΅ 2μ²λ§)
uint256 supplyApis = 9520000000;
// wei λ¨μλ‘ ν ν° μ΄λμ μμ±νλ€.
totalSupply = supplyApis * 10 ** uint256(decimals);
balances[msg.sender] = totalSupply;
Transfer(0x0, msg.sender, totalSupply);
}
/**
* @dev μ§κ°μ μ§μ λ μκ°κΉμ§ μ νμν€κ±°λ ν΄μ μν¨λ€. μ ν μκ°μ΄ κ²½κ³Όνλ©΄ λͺ¨λ μ νμ΄ ν΄μ λλ€.
* @param _targetWallet μ νμ μ μ©ν μ§κ° μ£Όμ
* @param _timeLockEnd μ νμ΄ μ’
λ£λλ μκ°(UnixTimestamp)
* @param _sendLock (true : μ§κ°μμ ν ν°μ μΆκΈνλ κΈ°λ₯μ μ ννλ€.) (false : μ νμ ν΄μ νλ€)
* @param _receiveLock (true : μ§κ°μΌλ‘ ν ν°μ μ
κΈλ°λ κΈ°λ₯μ μ ννλ€.) (false : μ νμ ν΄μ νλ€)
*/
function walletLock(address _targetWallet, uint _timeLockEnd, bool _sendLock, bool _receiveLock) onlyOwner public {
require(_targetWallet != 0x0);
// If all locks are unlocked, set the _timeLockEnd to zero.
if(_sendLock == false && _receiveLock == false) {
_timeLockEnd = 0;
}
lockedWalletInfo[_targetWallet].timeLockUpEnd = _timeLockEnd;
lockedWalletInfo[_targetWallet].sendLock = _sendLock;
lockedWalletInfo[_targetWallet].receiveLock = _receiveLock;
if(_timeLockEnd > 0) {
Locked(_targetWallet, _timeLockEnd, _sendLock, _receiveLock);
} else {
Unlocked(_targetWallet);
}
}
/**
* @dev μ§κ°μ μ
κΈ/μΆκΈμ μ§μ λ μκ°κΉμ§ μ νμν¨λ€. μ ν μκ°μ΄ κ²½κ³Όνλ©΄ λͺ¨λ μ νμ΄ ν΄μ λλ€.
* @param _targetWallet μ νμ μ μ©ν μ§κ° μ£Όμ
* @param _timeLockUpEnd μ νμ΄ μ’
λ£λλ μκ°(UnixTimestamp)
*/
function walletLockBoth(address _targetWallet, uint _timeLockUpEnd) onlyOwner public {
walletLock(_targetWallet, _timeLockUpEnd, true, true);
}
/**
* @dev μ§κ°μ μ
κΈ/μΆκΈμ μμν(33658-9-27 01:46:39+00) μ νμν¨λ€.
* @param _targetWallet μ νμ μ μ©ν μ§κ° μ£Όμ
*/
function walletLockBothForever(address _targetWallet) onlyOwner public {
walletLock(_targetWallet, 999999999999, true, true);
}
/**
* @dev μ§κ°μ μ€μ λ μ
μΆκΈ μ νμ ν΄μ νλ€
* @param _targetWallet μ νμ ν΄μ νκ³ μ νλ μ§κ° μ£Όμ
*/
function walletUnlock(address _targetWallet) onlyOwner public {
walletLock(_targetWallet, 0, false, false);
}
/**
* @dev μ§κ°μ μ‘κΈ κΈ°λ₯μ΄ μ νλμ΄μλμ§ νμΈνλ€.
* @param _addr μ‘κΈ μ ν μ¬λΆλ₯Ό νμΈνλ €λ μ§κ°μ μ£Όμ
* @return isSendLocked (true : μ νλμ΄ μμ, ν ν°μ λ³΄λΌ μ μμ) (false : μ ν μμ, ν ν°μ λ³΄λΌ μ μμ)
* @return until μ 겨μλ μκ°, UnixTimestamp
*/
function isWalletLocked_Send(address _addr) public constant returns (bool isSendLocked, uint until) {
require(_addr != 0x0);
isSendLocked = (lockedWalletInfo[_addr].timeLockUpEnd > now && lockedWalletInfo[_addr].sendLock == true);
if(isSendLocked) {
until = lockedWalletInfo[_addr].timeLockUpEnd;
} else {
until = 0;
}
}
/**
* @dev μ§κ°μ μ
κΈ κΈ°λ₯μ΄ μ νλμ΄μλμ§ νμΈνλ€.
* @param _addr μ
κΈ μ ν μ¬λΆλ₯Ό νμΈνλ €λ μ§κ°μ μ£Όμ
* @return (true : μ νλμ΄ μμ, ν ν°μ λ°μ μ μμ) (false : μ ν μμ, ν ν°μ λ°μ μ μμ)
*/
function isWalletLocked_Receive(address _addr) public constant returns (bool isReceiveLocked, uint until) {
require(_addr != 0x0);
isReceiveLocked = (lockedWalletInfo[_addr].timeLockUpEnd > now && lockedWalletInfo[_addr].receiveLock == true);
if(isReceiveLocked) {
until = lockedWalletInfo[_addr].timeLockUpEnd;
} else {
until = 0;
}
}
/**
* @dev μμ²μμ μ§κ°μ μ‘κΈ κΈ°λ₯μ΄ μ νλμ΄μλμ§ νμΈνλ€.
* @return (true : μ νλμ΄ μμ, ν ν°μ λ³΄λΌ μ μμ) (false : μ ν μμ, ν ν°μ λ³΄λΌ μ μμ)
*/
function isMyWalletLocked_Send() public constant returns (bool isSendLocked, uint until) {
return isWalletLocked_Send(msg.sender);
}
/**
* @dev μμ²μμ μ§κ°μ μ
κΈ κΈ°λ₯μ΄ μ νλμ΄μλμ§ νμΈνλ€.
* @return (true : μ νλμ΄ μμ, ν ν°μ λ³΄λΌ μ μμ) (false : μ ν μμ, ν ν°μ λ³΄λΌ μ μμ)
*/
function isMyWalletLocked_Receive() public constant returns (bool isReceiveLocked, uint until) {
return isWalletLocked_Receive(msg.sender);
}
/**
* @dev μνΌμ€ νλ«νΌμμ μ΄μνλ μ€λ§νΈ 컨νΈλ νΈ μ£Όμλ₯Ό λ±λ‘νκ±°λ ν΄μ νλ€.
* @param manoAddr λ§μ€ν°λ
Έλ μ€λ§νΈ 컨νΈλ 컨νΈλ νΈ
* @param registered true : λ±λ‘, false : ν΄μ
*/
function registerManoContract(address manoAddr, bool registered) onlyOwner public {
manoContracts[manoAddr] = registered;
ManoContractRegistered(manoAddr, registered);
}
/**
* @dev _to μ§κ°μΌλ‘ _apisWei λ§νΌμ ν ν°μ μ‘κΈνλ€.
* @param _to ν ν°μ λ°λ μ§κ° μ£Όμ
* @param _apisWei μ μ‘λλ ν ν°μ μ
*/
function transfer(address _to, uint256 _apisWei) public returns (bool) {
// μμ μκ² μ‘κΈνλ κ²μ λ°©μ§νλ€
require(_to != address(this));
// λ§μ€ν°λ
Έλ 컨νΈλ νΈμΌ κ²½μ°, APIS μ‘μμ μ μ νμ λμ§ μλλ€
if(manoContracts[msg.sender] || manoContracts[_to]) {
return super.transfer(_to, _apisWei);
}
// μ‘κΈ κΈ°λ₯μ΄ μ κΈ΄ μ§κ°μΈμ§ νμΈνλ€.
if(lockedWalletInfo[msg.sender].timeLockUpEnd > now && lockedWalletInfo[msg.sender].sendLock == true) {
RejectedPaymentFromLockedUpWallet(msg.sender, _to, _apisWei);
return false;
}
// μ
κΈ λ°λ κΈ°λ₯μ΄ μ κΈ΄ μ§κ°μΈμ§ νμΈνλ€
else if(lockedWalletInfo[_to].timeLockUpEnd > now && lockedWalletInfo[_to].receiveLock == true) {
RejectedPaymentToLockedUpWallet(msg.sender, _to, _apisWei);
return false;
}
// μ νμ΄ μλ κ²½μ°, μ‘κΈμ μ§ννλ€.
else {
return super.transfer(_to, _apisWei);
}
}
/**
* @dev _to μ§κ°μΌλ‘ _apisWei λ§νΌμ APISλ₯Ό μ‘κΈνκ³ _timeLockUpEnd μκ°λ§νΌ μ§κ°μ μ κ·Όλ€
* @param _to ν ν°μ λ°λ μ§κ° μ£Όμ
* @param _apisWei μ μ‘λλ ν ν°μ μ(wei)
* @param _timeLockUpEnd μ κΈμ΄ ν΄μ λλ μκ°
*/
function transferAndLockUntil(address _to, uint256 _apisWei, uint _timeLockUpEnd) onlyOwner public {
require(transfer(_to, _apisWei));
walletLockBoth(_to, _timeLockUpEnd);
}
/**
* @dev _to μ§κ°μΌλ‘ _apisWei λ§νΌμ APISλ₯Ό μ‘κΈνκ³ μμν μ§κ°μ μ κ·Όλ€
* @param _to ν ν°μ λ°λ μ§κ° μ£Όμ
* @param _apisWei μ μ‘λλ ν ν°μ μ(wei)
*/
function transferAndLockForever(address _to, uint256 _apisWei) onlyOwner public {
require(transfer(_to, _apisWei));
walletLockBothForever(_to);
}
/**
* @dev ν¨μλ₯Ό νΈμΆνλ μ§κ°μ ν ν°μ μκ°νλ€.
*
* zeppelin-solidity/contracts/token/BurnableToken.sol μ°Έμ‘°
* @param _value μκ°νλ €λ ν ν°μ μ(Satoshi)
*/
function burn(uint256 _value) public {
require(_value <= balances[msg.sender]);
require(_value <= totalSupply);
address burner = msg.sender;
balances[burner] -= _value;
totalSupply -= _value;
Burn(burner, _value);
}
/**
* @dev Ethμ λ°μ μ μλλ‘ νλ€.
*/
function () public payable {
revert();
}
}
/**
* @title WhiteList
* @dev ICO μ°Έμ¬κ° κ°λ₯ν νμ΄νΈ 리μ€νΈλ₯Ό κ΄λ¦¬νλ€
*/
contract WhiteList is Ownable {
mapping (address => uint8) internal list;
/**
* @dev νμ΄νΈλ¦¬μ€νΈμ λ³λμ΄ λ°μνμ λ μ΄λ²€νΈ
* @param backer νμ΄νΈλ¦¬μ€νΈμ λ±μ¬νλ €λ μ§κ° μ£Όμ
* @param allowed (true : νμ΄νΈλ¦¬μ€νΈμ μΆκ°) (false : μ κ±°)
*/
event WhiteBacker(address indexed backer, bool allowed);
/**
* @dev νμ΄νΈλ¦¬μ€νΈμ λ±λ‘νκ±°λ ν΄μ νλ€.
* @param _target νμ΄νΈλ¦¬μ€νΈμ λ±μ¬νλ €λ μ§κ° μ£Όμ
* @param _allowed (true : νμ΄νΈλ¦¬μ€νΈμ μΆκ°) (false : μ κ±°)
*/
function setWhiteBacker(address _target, bool _allowed) onlyOwner public {
require(_target != 0x0);
if(_allowed == true) {
list[_target] = 1;
} else {
list[_target] = 0;
}
WhiteBacker(_target, _allowed);
}
/**
* @dev νμ΄νΈ 리μ€νΈμ λ±λ‘(μΆκ°)νλ€
* @param _target μΆκ°ν μ§κ° μ£Όμ
*/
function addWhiteBacker(address _target) onlyOwner public {
setWhiteBacker(_target, true);
}
/**
* @dev νμ΄νΈλ¦¬μ€νΈμ μ¬λ¬ μ§κ° μ£Όμλ₯Ό λμμ λ±μ¬νκ±°λ μ κ±°νλ€.
*
* κ°μ€ μλͺ¨λ₯Ό μ€μ¬λ³΄κΈ° μν¨
* @param _backers λμμ΄ λλ μ§κ°λ€μ 리μ€νΈ
* @param _allows λμμ΄ λλ μ§κ°λ€μ μΆκ° μ¬λΆ 리μ€νΈ (true : μΆκ°) (false : μ κ±°)
*/
function setWhiteBackersByList(address[] _backers, bool[] _allows) onlyOwner public {
require(_backers.length > 0);
require(_backers.length == _allows.length);
for(uint backerIndex = 0; backerIndex < _backers.length; backerIndex++) {
setWhiteBacker(_backers[backerIndex], _allows[backerIndex]);
}
}
/**
* @dev νμ΄νΈλ¦¬μ€νΈμ μ¬λ¬ μ§κ° μ£Όμλ₯Ό λ±μ¬νλ€.
*
* λͺ¨λ μ£Όμλ€μ νμ΄νΈλ¦¬μ€νΈμ μΆκ°λλ€.
* @param _backers λμμ΄ λλ μ§κ°λ€μ 리μ€νΈ
*/
function addWhiteBackersByList(address[] _backers) onlyOwner public {
for(uint backerIndex = 0; backerIndex < _backers.length; backerIndex++) {
setWhiteBacker(_backers[backerIndex], true);
}
}
/**
* @dev ν΄λΉ μ§κ° μ£Όμκ° νμ΄νΈ 리μ€νΈμ λ±λ‘λμ΄μλμ§ νμΈνλ€
* @param _addr λ±μ¬ μ¬λΆλ₯Ό νμΈνλ €λ μ§κ°μ μ£Όμ
* @return (true : λ±λ‘λμ΄μμ) (false : λ±λ‘λμ΄μμ§ μμ)
*/
function isInWhiteList(address _addr) public constant returns (bool) {
require(_addr != 0x0);
return list[_addr] > 0;
}
/**
* @dev μμ²νλ μ§κ°μ΄ νμ΄νΈλ¦¬μ€νΈμ λ±λ‘λμ΄μλμ§ νμΈνλ€.
* @return (true : λ±λ‘λμ΄μμ) (false : λ±λ‘λμ΄μμ§ μμ)
*/
function isMeInWhiteList() public constant returns (bool isWhiteBacker) {
return list[msg.sender] > 0;
}
}
/**
* @title APIS Crowd Pre-Sale
* @dev ν ν°μ ν리μΈμΌμ μννκΈ° μν 컨νΈλνΈ
*/
contract ApisCrowdSale is Ownable {
// μμμ μ리μ. Eth 18μ리μ λ§μΆλ€
uint8 public constant decimals = 18;
// ν¬λΌμ°λ μΈμΌμ ν맀 λͺ©νλ(APIS)
uint256 public fundingGoal;
// νμ¬ μ§ννλ ν맀 λͺ©νλ
// QTUMκ³Ό 곡λμΌλ‘ νλ§€κ° μ§νλκΈ° λλ¬Έμ, QTUM μͺ½ 컨νΈλ νΈμ ν©μ°ν ν맀λμ΄ μ΄ ν맀λͺ©νλ₯Ό λμ§ μλλ‘ νκΈ° μν¨
uint256 public fundingGoalCurrent;
// 1 ETHμΌλ‘ μ΄ μ μλ APISμ κ°―μ
uint256 public priceOfApisPerFund;
// λ°κΈλ Apis κ°―μ (μμ½ + λ°ν)
//uint256 public totalSoldApis;
// λ°ν λκΈ°μ€μΈ APIS κ°―μ
//uint256 public totalReservedApis;
// λ°νλμ μΆκΈλ APIS κ°―μ
//uint256 public totalWithdrawedApis;
// μ
κΈλ ν¬μκΈμ μ΄μ‘ (μμ½ + λ°ν)
//uint256 public totalReceivedFunds;
// ꡬ맀 νμ μ ν¬μκΈμ μ΄μ‘
//uint256 public totalReservedFunds;
// ꡬ맀 νμ λ ν¬μκΈμ μ΄μ‘
//uint256 public totalPaidFunds;
// νλ§€κ° μμλλ μκ°
uint public startTime;
// νλ§€κ° μ’
λ£λλ μκ°
uint public endTime;
// νλ§€κ° μ‘°κΈ°μ μ’
λ£λ κ²½μ°λ₯Ό λλΉνκΈ° μν¨
bool closed = false;
SaleStatus public saleStatus;
// APIS ν ν° μ»¨νΈλ νΈ
ApisToken internal tokenReward;
// νμ΄νΈλ¦¬μ€νΈ 컨νΈλ νΈ
WhiteList internal whiteList;
mapping (address => Property) public fundersProperty;
/**
* @dev APIS ν ν° κ΅¬λ§€μμ μμ° νν©μ μ 리νκΈ° μν ꡬ쑰체
*/
struct Property {
uint256 reservedFunds; // μ
κΈνμ§λ§ μμ§ APISλ‘ λ³νλμ§ μμ Eth (νλΆ κ°λ₯)
uint256 paidFunds; // APISλ‘ λ³νλ Eth (νλΆ λΆκ°)
uint256 reservedApis; // λ°μ μμ μΈ ν ν°
uint256 withdrawedApis; // μ΄λ―Έ λ°μ ν ν°
uint purchaseTime; // ꡬμ
ν μκ°
}
/**
* @dev νμ¬ μΈμΌμ μ§ν νν©μ νμΈν μ μλ€.
* totalSoldApis λ°κΈλ Apis κ°―μ (μμ½ + λ°ν)
* totalReservedApis λ°ν λκΈ° μ€μΈ Apis
* totalWithdrawedApis λ°νλμ μΆκΈλ APIS κ°―μ
*
* totalReceivedFunds μ
κΈλ ν¬μκΈμ μ΄μ‘ (μμ½ + λ°ν)
* totalReservedFunds ꡬ맀 νμ μ ν¬μκΈμ μ΄μ‘
* ttotalPaidFunds ꡬ맀 νμ λ ν¬μκΈμ μ΄μ‘
*/
struct SaleStatus {
uint256 totalReservedFunds;
uint256 totalPaidFunds;
uint256 totalReceivedFunds;
uint256 totalReservedApis;
uint256 totalWithdrawedApis;
uint256 totalSoldApis;
}
/**
* @dev APISλ₯Ό ꡬμ
νκΈ° μν Ethμ μ
κΈνμ λ λ°μνλ μ΄λ²€νΈ
* @param beneficiary APISλ₯Ό ꡬ맀νκ³ μ νλ μ§κ°μ μ£Όμ
* @param amountOfFunds μ
κΈν Ethμ μ (wei)
* @param amountOfApis ν¬μκΈμ μμνλ APIS ν ν°μ μ (wei)
*/
event ReservedApis(address beneficiary, uint256 amountOfFunds, uint256 amountOfApis);
/**
* @dev ν¬λΌμ°λ μΈμΌ 컨νΈλ νΈμμ Ethμ΄ μΈμΆλμμ λ λ°μνλ μ΄λ²€νΈ
* @param addr λ°λ μ§κ°μ μ£Όμ
* @param amount μ‘κΈλλ μ(wei)
*/
event WithdrawalFunds(address addr, uint256 amount);
/**
* @dev ꡬ맀μμκ² ν ν°μ΄ λ°κΈλμμ λ λ°μνλ μ΄λ²€νΈ
* @param funder ν ν°μ λ°λ μ§κ°μ μ£Όμ
* @param amountOfFunds μ
κΈν ν¬μκΈμ μ (wei)
* @param amountOfApis λ°κΈ λ°λ ν ν°μ μ (wei)
*/
event WithdrawalApis(address funder, uint256 amountOfFunds, uint256 amountOfApis);
/**
* @dev ν¬μκΈ μ
κΈ ν, μμ§ ν ν°μ λ°κΈλ°μ§ μμ μνμμ, νλΆ μ²λ¦¬λ₯Ό νμ λ λ°μνλ μ΄λ²€νΈ
* @param _backer νλΆ μ²λ¦¬λ₯Ό μ§ννλ μ§κ°μ μ£Όμ
* @param _amountFunds νλΆνλ ν¬μκΈμ μ
* @param _amountApis μ·¨μλλ APIS μ
*/
event Refund(address _backer, uint256 _amountFunds, uint256 _amountApis);
/**
* @dev ν¬λΌμ°λ μΈμΌ μ§ν μ€μλ§ λμνλλ‘ μ ννκ³ , APISμ κ°κ²©λ μ€μ λμ΄μΌλ§ νλ€.
*/
modifier onSale() {
require(now >= startTime);
require(now < endTime);
require(closed == false);
require(priceOfApisPerFund > 0);
require(fundingGoalCurrent > 0);
_;
}
/**
* @dev ν¬λΌμ°λ μΈμΌ μ’
λ£ νμλ§ λμνλλ‘ μ ν
*/
modifier onFinished() {
require(now >= endTime || closed == true);
_;
}
/**
* @dev νμ΄νΈλ¦¬μ€νΈμ λ±λ‘λμ΄μμ΄μΌνκ³ μμ§ κ΅¬λ§€μλ£ λμ§ μμ ν¬μκΈμ΄ μμ΄μΌλ§ νλ€.
*/
modifier claimable() {
require(whiteList.isInWhiteList(msg.sender) == true);
require(fundersProperty[msg.sender].reservedFunds > 0);
_;
}
/**
* @dev ν¬λΌμ°λ μΈμΌ 컨νΈλ νΈλ₯Ό μμ±νλ€.
* @param _fundingGoalApis ν맀νλ ν ν°μ μ (APIS λ¨μ)
* @param _startTime ν¬λΌμ°λ μΈμΌμ μμνλ μκ°
* @param _endTime ν¬λΌμ°λ μΈμΌμ μ’
λ£νλ μκ°
* @param _addressOfApisTokenUsedAsReward APIS ν ν°μ 컨νΈλ νΈ μ£Όμ
* @param _addressOfWhiteList WhiteList 컨νΈλ νΈ μ£Όμ
*/
function ApisCrowdSale (
uint256 _fundingGoalApis,
uint _startTime,
uint _endTime,
address _addressOfApisTokenUsedAsReward,
address _addressOfWhiteList
) public {
require (_fundingGoalApis > 0);
require (_startTime > now);
require (_endTime > _startTime);
require (_addressOfApisTokenUsedAsReward != 0x0);
require (_addressOfWhiteList != 0x0);
fundingGoal = _fundingGoalApis * 10 ** uint256(decimals);
startTime = _startTime;
endTime = _endTime;
// ν ν° μ€λ§νΈμ»¨νΈλ νΈλ₯Ό λΆλ¬μ¨λ€
tokenReward = ApisToken(_addressOfApisTokenUsedAsReward);
// νμ΄νΈ 리μ€νΈλ₯Ό κ°μ Έμ¨λ€
whiteList = WhiteList(_addressOfWhiteList);
}
/**
* @dev ν맀 μ’
λ£λ 1νλ§ κ°λ₯νλλ‘ μ μ½νλ€. μ’
λ£ ν λ€μ ν맀 μ€μΌλ‘ λ³κ²½ν μ μλ€
*/
function closeSale(bool _closed) onlyOwner public {
require (closed == false);
closed = _closed;
}
/**
* @dev ν¬λΌμ°λ μΈμΌ μμ μ μ 1Ethμ ν΄λΉνλ APIS λμ μ€μ νλ€.
*/
function setPriceOfApis(uint256 price) onlyOwner public {
require(priceOfApisPerFund == 0);
priceOfApisPerFund = price;
}
/**
* @dev ν μμ μμ ν맀 κ°λ₯ν λͺ©νλμ μμ νλ€.
* @param _currentFundingGoalAPIS ν μμ μ ν맀 λͺ©νλμ μ΄ ν맀λ μ μ΄μμ΄μ΄μΌλ§ νλ€.
*/
function setCurrentFundingGoal(uint256 _currentFundingGoalAPIS) onlyOwner public {
uint256 fundingGoalCurrentWei = _currentFundingGoalAPIS * 10 ** uint256(decimals);
require(fundingGoalCurrentWei >= saleStatus.totalSoldApis);
fundingGoalCurrent = fundingGoalCurrentWei;
}
/**
* @dev APIS μκ³ λ₯Ό νμΈνλ€
* @param _addr μκ³ λ₯Ό νμΈνλ €λ μ§κ°μ μ£Όμ
* @return balance μ§κ°μ λ€μ APIS μκ³ (wei)
*/
function balanceOf(address _addr) public view returns (uint256 balance) {
return tokenReward.balanceOf(_addr);
}
/**
* @dev νμ΄νΈλ¦¬μ€νΈ λ±λ‘ μ¬λΆλ₯Ό νμΈνλ€
* @param _addr λ±λ‘ μ¬λΆλ₯Ό νμΈνλ €λ μ£Όμ
* @return addrIsInWhiteList true : λ±λ‘λμμ, false : λ±λ‘λμ΄μμ§ μμ
*/
function whiteListOf(address _addr) public view returns (string message) {
if(whiteList.isInWhiteList(_addr) == true) {
return "The address is in whitelist.";
} else {
return "The address is *NOT* in whitelist.";
}
}
/**
* @dev μ λ¬λ°μ μ§κ°μ΄ APIS μ§κΈ μμ²μ΄ κ°λ₯νμ§ νμΈνλ€.
* @param _addr νμΈνλ μ£Όμ
* @return message κ²°κ³Ό λ©μμ§
*/
function isClaimable(address _addr) public view returns (string message) {
if(fundersProperty[_addr].reservedFunds == 0) {
return "The address has no claimable balance.";
}
if(whiteList.isInWhiteList(_addr) == false) {
return "The address must be registered with KYC and Whitelist";
}
else {
return "The address can claim APIS!";
}
}
/**
* @dev ν¬λΌμ°λ μΈμΌ 컨νΈλ νΈλ‘ λ°λ‘ ν¬μκΈμ μ‘κΈνλ κ²½μ°, buyTokenμΌλ‘ μ°κ²°νλ€
*/
function () onSale public payable {
buyToken(msg.sender);
}
/**
* @dev ν ν°μ ꡬμ
νκΈ° μν΄ Qtumμ μ
κΈλ°λλ€.
* @param _beneficiary ν ν°μ λ°κ² λ μ§κ°μ μ£Όμ
*/
function buyToken(address _beneficiary) onSale public payable {
// μ£Όμ νμΈ
require(_beneficiary != 0x0);
// ν¬λΌμ°λ μΈμΌ 컨νΈλ νΈμ ν ν° μ‘κΈ κΈ°λ₯μ΄ μ μ§λμ΄μμΌλ©΄ ν맀νμ§ μλλ€
bool isLocked = false;
uint timeLock = 0;
(isLocked, timeLock) = tokenReward.isWalletLocked_Send(this);
require(isLocked == false);
uint256 amountFunds = msg.value;
uint256 reservedApis = amountFunds * priceOfApisPerFund;
// λͺ©ν κΈμ‘μ λμ΄μμ§ λͺ»νλλ‘ νλ€
require(saleStatus.totalSoldApis + reservedApis <= fundingGoalCurrent);
require(saleStatus.totalSoldApis + reservedApis <= fundingGoal);
// ν¬μμμ μμ°μ μ
λ°μ΄νΈνλ€
fundersProperty[_beneficiary].reservedFunds += amountFunds;
fundersProperty[_beneficiary].reservedApis += reservedApis;
fundersProperty[_beneficiary].purchaseTime = now;
// μ΄μ‘λ€μ μ
λ°μ΄νΈνλ€
saleStatus.totalReceivedFunds += amountFunds;
saleStatus.totalReservedFunds += amountFunds;
saleStatus.totalSoldApis += reservedApis;
saleStatus.totalReservedApis += reservedApis;
// νμ΄νΈλ¦¬μ€νΈμ λ±λ‘λμ΄μμΌλ©΄ λ°λ‘ μΆκΈνλ€
if(whiteList.isInWhiteList(_beneficiary) == true) {
withdrawal(_beneficiary);
}
else {
// ν ν° λ°ν μμ½ μ΄λ²€νΈ λ°μ
ReservedApis(_beneficiary, amountFunds, reservedApis);
}
}
/**
* @dev κ΄λ¦¬μμ μν΄μ ν ν°μ λ°κΈνλ€. νμ§λ§ κΈ°λ³Έ μ건μ κ°μΆ°μΌλ§ κ°λ₯νλ€
*
* @param _target ν ν° λ°κΈμ μ²κ΅¬νλ €λ μ§κ° μ£Όμ
*/
function claimApis(address _target) public {
// νμ΄νΈ 리μ€νΈμ μμ΄μΌλ§ νκ³
require(whiteList.isInWhiteList(_target) == true);
// μμ½λ ν¬μκΈμ΄ μμ΄μΌλ§ νλ€.
require(fundersProperty[_target].reservedFunds > 0);
withdrawal(_target);
}
/**
* @dev μμ½ν ν ν°μ μ€μ μ§κΈμ μμ²νλλ‘ νλ€.
*
* APISλ₯Ό ꡬ맀νκΈ° μν΄ Qtumμ μ
κΈν κ²½μ°, κ΄λ¦¬μμ κ²ν λ₯Ό μν 7μΌμ μ μκΈ°κ°μ΄ μ‘΄μ¬νλ€.
* μ μκΈ°κ°μ΄ μ§λλ©΄ ν ν° μ§κΈμ μꡬν μ μλ€.
*/
function claimMyApis() claimable public {
withdrawal(msg.sender);
}
/**
* @dev ꡬ맀μμκ² ν ν°μ μ§κΈνλ€.
* @param funder ν ν°μ μ§κΈν μ§κ°μ μ£Όμ
*/
function withdrawal(address funder) internal {
// ꡬ맀μ μ§κ°μΌλ‘ ν ν°μ μ λ¬νλ€
assert(tokenReward.transferFrom(owner, funder, fundersProperty[funder].reservedApis));
fundersProperty[funder].withdrawedApis += fundersProperty[funder].reservedApis;
fundersProperty[funder].paidFunds += fundersProperty[funder].reservedFunds;
// μ΄μ‘μ λ°μ
saleStatus.totalReservedFunds -= fundersProperty[funder].reservedFunds;
saleStatus.totalPaidFunds += fundersProperty[funder].reservedFunds;
saleStatus.totalReservedApis -= fundersProperty[funder].reservedApis;
saleStatus.totalWithdrawedApis += fundersProperty[funder].reservedApis;
// APISκ° μΆκΈ λμμμ μ리λ μ΄λ²€νΈ
WithdrawalApis(funder, fundersProperty[funder].reservedFunds, fundersProperty[funder].reservedApis);
// μΈμΆνμ§ μμ APIS μκ³ λ₯Ό 0μΌλ‘ λ³κ²½ν΄μ, Qtum μ¬μ
κΈ μ μ΄λ―Έ μΆκΈν ν ν°μ΄ λ€μ μΆκΈλμ§ μκ² νλ€.
fundersProperty[funder].reservedFunds = 0;
fundersProperty[funder].reservedApis = 0;
}
/**
* @dev μμ§ ν ν°μ λ°κΈλ°μ§ μμ μ§κ°μ λμμΌλ‘, νλΆμ μ§νν μ μλ€.
* @param _funder νλΆμ μ§ννλ €λ μ§κ°μ μ£Όμ
*/
function refundByOwner(address _funder) onlyOwner public {
require(fundersProperty[_funder].reservedFunds > 0);
uint256 amountFunds = fundersProperty[_funder].reservedFunds;
uint256 amountApis = fundersProperty[_funder].reservedApis;
// Ethμ νλΆνλ€
_funder.transfer(amountFunds);
saleStatus.totalReceivedFunds -= amountFunds;
saleStatus.totalReservedFunds -= amountFunds;
saleStatus.totalSoldApis -= amountApis;
saleStatus.totalReservedApis -= amountApis;
fundersProperty[_funder].reservedFunds = 0;
fundersProperty[_funder].reservedApis = 0;
Refund(_funder, amountFunds, amountApis);
}
/**
* @dev νλ©μ΄ μ’
λ£λ μ΄νλ©΄, μ 립λ ν¬μκΈμ λ°ννλ€.
* @param remainRefundable true : νλΆν μ μλ κΈμ‘μ λ¨κΈ°κ³ λ°ννλ€. false : λͺ¨λ λ°ννλ€
*/
function withdrawalFunds(bool remainRefundable) onlyOwner public {
require(now > endTime || closed == true);
uint256 amount = 0;
if(remainRefundable) {
amount = this.balance - saleStatus.totalReservedFunds;
} else {
amount = this.balance;
}
if(amount > 0) {
msg.sender.transfer(amount);
WithdrawalFunds(msg.sender, amount);
}
}
/**
* @dev ν¬λΌμ°λ μΈμΌμ΄ μ§ν μ€μΈμ§ μ¬λΆλ₯Ό λ°ννλ€.
* @return isOpened true: μ§ν μ€ false : μ§ν μ€μ΄ μλ(μ°Έμ¬ λΆκ°)
*/
function isOpened() public view returns (bool isOpend) {
if(now < startTime) return false;
if(now >= endTime) return false;
if(closed == true) return false;
return true;
}
}