pragma solidity ^0.4.20;
/*
* ERC20 interface
* see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 {
uint public totalSupply;
function balanceOf(address who) constant returns (uint);
function allowance(address owner, address spender) constant returns (uint);
function transfer(address to, uint value) returns (bool ok);
function transferFrom(address from, address to, uint value) returns (bool ok);
function approve(address spender, uint value) returns (bool ok);
event Transfer(address indexed from, address indexed to, uint value);
event Approval(address indexed owner, address indexed spender, uint value);
}
/**
* Math operations with safety checks
*/
contract SafeMath {
function safeMul(uint a, uint b) internal returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeDiv(uint a, uint b) internal returns (uint) {
assert(b > 0);
uint c = a / b;
assert(a == b * c + a % b);
return c;
}
function safeSub(uint a, uint b) internal returns (uint) {
assert(b <= a);
return a - b;
}
function safeAdd(uint a, uint b) internal returns (uint) {
uint c = a + b;
assert(c >= a && c >= b);
return c;
}
function max64(uint64 a, uint64 b) internal constant returns (uint64) {
return a >= b ? a : b;
}
function min64(uint64 a, uint64 b) internal constant returns (uint64) {
return a < b ? a : b;
}
function max256(uint256 a, uint256 b) internal constant returns (uint256) {
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b) internal constant returns (uint256) {
return a < b ? a : b;
}
function assert(bool assertion) internal {
if (!assertion) {
throw;
}
}
}
/**
* Owned contract
*/
contract Owned {
address[] public pools;
address public owner;
function Owned() {
owner = msg.sender;
pools.push(msg.sender);
}
modifier onlyPool {
require(isPool(msg.sender));
_;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
/// add new pool address to pools
function addPool(address newPool) onlyOwner {
assert (newPool != 0);
if (isPool(newPool)) throw;
pools.push(newPool);
}
/// remove a address from pools
function removePool(address pool) onlyOwner{
assert (pool != 0);
if (!isPool(pool)) throw;
for (uint i=0; i<pools.length - 1; i++) {
if (pools[i] == pool) {
pools[i] = pools[pools.length - 1];
break;
}
}
pools.length -= 1;
}
function isPool(address pool) internal returns (bool ok){
for (uint i=0; i<pools.length; i++) {
if (pools[i] == pool)
return true;
}
return false;
}
function transferOwnership(address newOwner) onlyOwner public {
removePool(owner);
addPool(newOwner);
owner = newOwner;
}
}
/**
* BP crowdsale contract
*/
contract BPToken is SafeMath, Owned, ERC20 {
string public constant name = "Backpack Token";
string public constant symbol = "BP";
uint256 public constant decimals = 18;
mapping (address => uint256) balances;
mapping (address => mapping (address => uint256)) allowed;
function BPToken() {
totalSupply = 2000000000 * 10 ** uint256(decimals);
balances[msg.sender] = totalSupply;
}
/// asset pool map
mapping (address => address) addressPool;
/// address base amount
mapping (address => uint256) addressAmount;
/// per month seconds
uint perMonthSecond = 2592000;
/// calc the balance that the user shuold hold
function shouldHadBalance(address who) constant returns (uint256){
if (isPool(who)) return 0;
address apAddress = getAssetPoolAddress(who);
uint256 baseAmount = getBaseAmount(who);
/// Does not belong to AssetPool contract
if( (apAddress == address(0)) || (baseAmount == 0) ) return 0;
/// Instantiate ap contract
AssetPool ap = AssetPool(apAddress);
uint startLockTime = ap.getStartLockTime();
uint stopLockTime = ap.getStopLockTime();
if (block.timestamp > stopLockTime) {
return 0;
}
if (ap.getBaseLockPercent() == 0) {
return 0;
}
// base lock amount
uint256 baseLockAmount = safeDiv(safeMul(baseAmount, ap.getBaseLockPercent()),100);
if (block.timestamp < startLockTime) {
return baseLockAmount;
}
/// will not linear release
if (ap.getLinearRelease() == 0) {
if (block.timestamp < stopLockTime) {
return baseLockAmount;
} else {
return 0;
}
}
/// will linear release
/// now timestamp before start lock time
if (block.timestamp < startLockTime + perMonthSecond) {
return baseLockAmount;
}
// total lock months
uint lockMonth = safeDiv(safeSub(stopLockTime,startLockTime),perMonthSecond);
if (lockMonth <= 0) {
if (block.timestamp >= stopLockTime) {
return 0;
} else {
return baseLockAmount;
}
}
// unlock amount of every month
uint256 monthUnlockAmount = safeDiv(baseLockAmount,lockMonth);
// current timestamp passed month
uint hadPassMonth = safeDiv(safeSub(block.timestamp,startLockTime),perMonthSecond);
return safeSub(baseLockAmount,safeMul(hadPassMonth,monthUnlockAmount));
}
function getAssetPoolAddress(address who) internal returns(address){
return addressPool[who];
}
function getBaseAmount(address who) internal returns(uint256){
return addressAmount[who];
}
function getBalance() constant returns(uint){
return balances[msg.sender];
}
function setPoolAndAmount(address who, uint256 amount) onlyPool returns (bool) {
assert(balances[msg.sender] >= amount);
if (owner == who) {
return true;
}
address apAddress = getAssetPoolAddress(who);
uint256 baseAmount = getBaseAmount(who);
assert((apAddress == msg.sender) || (baseAmount == 0));
addressPool[who] = msg.sender;
addressAmount[who] += amount;
return true;
}
/// get balance of the special address
function balanceOf(address who) constant returns (uint) {
return balances[who];
}
/// @notice Transfer `value` BP tokens from sender's account
/// `msg.sender` to provided account address `to`.
/// @notice This function is disabled during the funding.
/// @dev Required state: Success
/// @param to The address of the recipient
/// @param value The number of BPs to transfer
/// @return Whether the transfer was successful or not
function transfer(address to, uint256 value) returns (bool) {
if (safeSub(balances[msg.sender],value) < shouldHadBalance(msg.sender)) throw;
uint256 senderBalance = balances[msg.sender];
if (senderBalance >= value && value > 0) {
senderBalance = safeSub(senderBalance, value);
balances[msg.sender] = senderBalance;
balances[to] = safeAdd(balances[to], value);
Transfer(msg.sender, to, value);
return true;
} else {
throw;
}
}
/// @notice Transfer `value` BP tokens from sender 'from'
/// to provided account address `to`.
/// @notice This function is disabled during the funding.
/// @dev Required state: Success
/// @param from The address of the sender
/// @param to The address of the recipient
/// @param value The number of BPs to transfer
/// @return Whether the transfer was successful or not
function transferFrom(address from, address to, uint256 value) returns (bool) {
// Abort if not in Success state.
// protect against wrapping uints
if (balances[from] >= value &&
allowed[from][msg.sender] >= value &&
safeAdd(balances[to], value) > balances[to])
{
balances[to] = safeAdd(balances[to], value);
balances[from] = safeSub(balances[from], value);
allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], value);
Transfer(from, to, value);
return true;
} else {
throw;
}
}
/// @notice `msg.sender` approves `spender` to spend `value` tokens
/// @param spender The address of the account able to transfer the tokens
/// @param value The amount of wei to be approved for transfer
/// @return Whether the approval was successful or not
function approve(address spender, uint256 value) returns (bool) {
if (safeSub(balances[msg.sender],value) < shouldHadBalance(msg.sender)) throw;
// Abort if not in Success state.
allowed[msg.sender][spender] = value;
Approval(msg.sender, spender, value);
return true;
}
/// @param owner The address of the account owning tokens
/// @param spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address owner, address spender) constant returns (uint) {
uint allow = allowed[owner][spender];
return allow;
}
}
contract ownedPool {
address public owner;
function ownedPool() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) onlyOwner public {
owner = newOwner;
}
}
/**
* Asset pool contract
*/
contract AssetPool is ownedPool {
uint baseLockPercent;
uint startLockTime;
uint stopLockTime;
uint linearRelease;
address public bpTokenAddress;
BPToken bp;
function AssetPool(address _bpTokenAddress, uint _baseLockPercent, uint _startLockTime, uint _stopLockTime, uint _linearRelease) {
assert(_stopLockTime > _startLockTime);
baseLockPercent = _baseLockPercent;
startLockTime = _startLockTime;
stopLockTime = _stopLockTime;
linearRelease = _linearRelease;
bpTokenAddress = _bpTokenAddress;
bp = BPToken(bpTokenAddress);
owner = msg.sender;
}
/// set role value
function setRule(uint _baseLockPercent, uint _startLockTime, uint _stopLockTime, uint _linearRelease) onlyOwner {
assert(_stopLockTime > _startLockTime);
baseLockPercent = _baseLockPercent;
startLockTime = _startLockTime;
stopLockTime = _stopLockTime;
linearRelease = _linearRelease;
}
/// set bp token contract address
// function setBpToken(address _bpTokenAddress) onlyOwner {
// bpTokenAddress = _bpTokenAddress;
// bp = BPToken(bpTokenAddress);
// }
/// assign BP token to another address
function assign(address to, uint256 amount) onlyOwner returns (bool) {
if (bp.setPoolAndAmount(to,amount)) {
if (bp.transfer(to,amount)) {
return true;
}
}
return false;
}
/// get the balance of current asset pool
function getPoolBalance() constant returns (uint) {
return bp.getBalance();
}
function getStartLockTime() constant returns (uint) {
return startLockTime;
}
function getStopLockTime() constant returns (uint) {
return stopLockTime;
}
function getBaseLockPercent() constant returns (uint) {
return baseLockPercent;
}
function getLinearRelease() constant returns (uint) {
return linearRelease;
}
}
{
"compilationTarget": {
"BPToken.sol": "BPToken"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": false,
"runs": 0
},
"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":true,"inputs":[],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"who","type":"address"},{"name":"amount","type":"uint256"}],"name":"setPoolAndAmount","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":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","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":"pool","type":"address"}],"name":"removePool","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"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":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"pools","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newPool","type":"address"}],"name":"addPool","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"who","type":"address"}],"name":"shouldHadBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","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":"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"}]