文件 1 的 1:SimpleLSTDistribution.sol
pragma solidity ^0.4.18;
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) {
uint256 c = a / b;
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;
}
}
contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function Ownable() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
contract Pausable is Ownable {
event Pause();
event Unpause();
bool public paused = false;
modifier whenNotPaused() {
require(!paused);
_;
}
modifier whenPaused() {
require(paused);
_;
}
function pause() onlyOwner whenNotPaused public {
paused = true;
Pause();
}
function unpause() onlyOwner whenPaused public {
paused = false;
Unpause();
}
}
contract ERC20Basic {
function totalSupply() public view returns (uint256);
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);
}
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);
}
contract BasicToken is ERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
uint256 totalSupply_;
function totalSupply() public view returns (uint256) {
return totalSupply_;
}
function transfer(address _to, uint256 _value) public returns (bool) {
require(_to != address(0));
require(_value <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
Transfer(msg.sender, _to, _value);
return true;
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
contract StandardToken is ERC20, BasicToken {
mapping (address => mapping (address => uint256)) internal allowed;
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;
}
function approve(address _spender, uint256 _value) public returns (bool) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256) {
return allowed[_owner][_spender];
}
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;
}
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;
}
}
contract PausableToken is StandardToken, Pausable {
function transfer(address _to, uint256 _value) public whenNotPaused returns (bool) {
return super.transfer(_to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) public whenNotPaused returns (bool) {
return super.transferFrom(_from, _to, _value);
}
function approve(address _spender, uint256 _value) public whenNotPaused returns (bool) {
return super.approve(_spender, _value);
}
function increaseApproval(address _spender, uint _addedValue) public whenNotPaused returns (bool success) {
return super.increaseApproval(_spender, _addedValue);
}
function decreaseApproval(address _spender, uint _subtractedValue) public whenNotPaused returns (bool success) {
return super.decreaseApproval(_spender, _subtractedValue);
}
}
contract MintableToken is StandardToken, Ownable {
event Mint(address indexed to, uint256 amount);
event MintFinished();
bool public mintingFinished = false;
modifier canMint() {
require(!mintingFinished);
_;
}
function mint(address _to, uint256 _amount) onlyOwner canMint public returns (bool) {
totalSupply_ = totalSupply_.add(_amount);
balances[_to] = balances[_to].add(_amount);
Mint(_to, _amount);
Transfer(address(0), _to, _amount);
return true;
}
function finishMinting() onlyOwner canMint public returns (bool) {
mintingFinished = true;
MintFinished();
return true;
}
}
library SafeERC20 {
function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
assert(token.transfer(to, value));
}
function safeTransferFrom(ERC20 token, address from, address to, uint256 value) internal {
assert(token.transferFrom(from, to, value));
}
function safeApprove(ERC20 token, address spender, uint256 value) internal {
assert(token.approve(spender, value));
}
}
contract TokenVesting is Ownable {
using SafeMath for uint256;
using SafeERC20 for ERC20Basic;
event Released(uint256 amount);
event Revoked();
address public beneficiary;
uint256 public cliff;
uint256 public start;
uint256 public duration;
bool public revocable;
mapping (address => uint256) public released;
mapping (address => bool) public revoked;
function TokenVesting(address _beneficiary, uint256 _start, uint256 _cliff, uint256 _duration, bool _revocable) public {
require(_beneficiary != address(0));
require(_cliff <= _duration);
beneficiary = _beneficiary;
revocable = _revocable;
duration = _duration;
cliff = _start.add(_cliff);
start = _start;
}
function release(ERC20Basic token) public {
uint256 unreleased = releasableAmount(token);
require(unreleased > 0);
released[token] = released[token].add(unreleased);
token.safeTransfer(beneficiary, unreleased);
Released(unreleased);
}
function revoke(ERC20Basic token) public onlyOwner {
require(revocable);
require(!revoked[token]);
uint256 balance = token.balanceOf(this);
uint256 unreleased = releasableAmount(token);
uint256 refund = balance.sub(unreleased);
revoked[token] = true;
token.safeTransfer(owner, refund);
Revoked();
}
function releasableAmount(ERC20Basic token) public view returns (uint256) {
return vestedAmount(token).sub(released[token]);
}
function vestedAmount(ERC20Basic token) public view returns (uint256) {
uint256 currentBalance = token.balanceOf(this);
uint256 totalBalance = currentBalance.add(released[token]);
if (now < cliff) {
return 0;
} else if (now >= start.add(duration) || revoked[token]) {
return totalBalance;
} else {
return totalBalance.mul(now.sub(start)).div(duration);
}
}
}
contract SimplePreTGE is Ownable {
bool public allocationsLocked;
struct Contribution {
bool hasVested;
uint256 weiContributed;
}
mapping (address => Contribution) public contributions;
function disableAllocationModificationsForEver() external onlyOwner returns(bool) {
allocationsLocked = true;
}
function bulkReserveTokensForAddresses(address[] addrs, uint256[] weiContributions, bool[] _vestingDecisions) onlyOwner external returns(bool) {
require(!allocationsLocked);
require((addrs.length == weiContributions.length) && (addrs.length == _vestingDecisions.length));
for (uint i=0; i<addrs.length; i++) {
contributions[addrs[i]].weiContributed = weiContributions[i];
contributions[addrs[i]].hasVested = _vestingDecisions[i];
}
return true;
}
}
contract SimpleTGE is Ownable {
using SafeMath for uint256;
uint256 public publicTGEStartBlockTimeStamp;
uint256 public publicTGEEndBlockTimeStamp;
address public fundsWallet;
uint256 public weiRaised;
uint256 public totalCapInWei;
uint256 public individualCapInWei;
uint256 public TRSOffset = 5 days;
mapping (address => bool) public whitelist;
address[] public contributors;
struct Contribution {
bool hasVested;
uint256 weiContributed;
}
mapping (address => Contribution) public contributions;
modifier whilePublicTGEIsActive() {
require(block.timestamp >= publicTGEStartBlockTimeStamp && block.timestamp <= publicTGEEndBlockTimeStamp);
_;
}
modifier isWhitelisted() {
require(whitelist[msg.sender]);
_;
}
function blacklistAddresses(address[] addrs) external onlyOwner returns(bool) {
require(addrs.length <= 100);
for (uint i = 0; i < addrs.length; i++) {
require(addrs[i] != address(0));
whitelist[addrs[i]] = false;
}
return true;
}
function whitelistAddresses(address[] addrs) external onlyOwner returns(bool) {
require(addrs.length <= 100);
for (uint i = 0; i < addrs.length; i++) {
require(addrs[i] != address(0));
whitelist[addrs[i]] = true;
}
return true;
}
function reclaimEther(address _beneficiary) external onlyOwner {
_beneficiary.transfer(this.balance);
}
function SimpleTGE (
address _fundsWallet,
uint256 _publicTGEStartBlockTimeStamp,
uint256 _publicTGEEndBlockTimeStamp,
uint256 _individualCapInWei,
uint256 _totalCapInWei
) public
{
require(_publicTGEStartBlockTimeStamp >= block.timestamp);
require(_publicTGEEndBlockTimeStamp > _publicTGEStartBlockTimeStamp);
require(_fundsWallet != address(0));
require(_individualCapInWei > 0);
require(_individualCapInWei <= _totalCapInWei);
require(_totalCapInWei > 0);
fundsWallet = _fundsWallet;
publicTGEStartBlockTimeStamp = _publicTGEStartBlockTimeStamp;
publicTGEEndBlockTimeStamp = _publicTGEEndBlockTimeStamp;
individualCapInWei = _individualCapInWei;
totalCapInWei = _totalCapInWei;
}
function changeIndividualCapInWei(uint256 _individualCapInWei) onlyOwner external returns(bool) {
require(_individualCapInWei > 0);
require(_individualCapInWei < totalCapInWei);
individualCapInWei = _individualCapInWei;
return true;
}
function contribute(bool _vestingDecision) internal {
require(msg.sender != address(0));
require(msg.value != 0);
require(weiRaised.add(msg.value) <= totalCapInWei);
require(contributions[msg.sender].weiContributed.add(msg.value) <= individualCapInWei);
if (contributions[msg.sender].weiContributed == 0) {
contributors.push(msg.sender);
}
contributions[msg.sender].weiContributed = contributions[msg.sender].weiContributed.add(msg.value);
weiRaised = weiRaised.add(msg.value);
contributions[msg.sender].hasVested = _vestingDecision;
fundsWallet.transfer(msg.value);
}
function contributeAndVest() external whilePublicTGEIsActive isWhitelisted payable {
contribute(true);
}
function contributeWithoutVesting() public whilePublicTGEIsActive isWhitelisted payable {
contribute(false);
}
function () external payable {
contributeWithoutVesting();
}
function vest(bool _vestingDecision) external isWhitelisted returns(bool) {
bool existingDecision = contributions[msg.sender].hasVested;
require(existingDecision != _vestingDecision);
require(block.timestamp >= publicTGEStartBlockTimeStamp);
require(contributions[msg.sender].weiContributed > 0);
if (block.timestamp > publicTGEEndBlockTimeStamp) {
require(block.timestamp.sub(publicTGEEndBlockTimeStamp) <= TRSOffset);
}
contributions[msg.sender].hasVested = _vestingDecision;
return true;
}
}
contract LendroidSupportToken is MintableToken, PausableToken {
string public constant name = "Lendroid Support Token";
string public constant symbol = "LST";
uint256 public constant decimals = 18;
uint256 public constant MAX_SUPPLY = 12000000000 * (10 ** uint256(decimals));
function LendroidSupportToken() public {
paused = true;
}
function mint(address to, uint256 amount) onlyOwner public returns (bool) {
require(totalSupply_ + amount <= MAX_SUPPLY);
return super.mint(to, amount);
}
}
contract SimpleLSTDistribution is Ownable {
using SafeMath for uint256;
SimplePreTGE public SimplePreTGEContract;
SimpleTGE public SimpleTGEContract;
LendroidSupportToken public token;
uint256 public LSTRatePerWEI = 48000;
uint256 public vestingBonusMultiplier;
uint256 public vestingBonusMultiplierPrecision = 1000000;
uint256 public vestingDuration;
uint256 public vestingStartTime;
struct allocation {
bool shouldVest;
uint256 weiContributed;
uint256 LSTAllocated;
bool hasWithdrawn;
}
mapping (address => allocation) public allocations;
mapping (address => TokenVesting) public vesting;
event LogLSTsWithdrawn(address beneficiary, uint256 tokens);
event LogTimeVestingLSTsWithdrawn(address beneficiary, uint256 tokens, uint256 start, uint256 cliff, uint256 duration);
function SimpleLSTDistribution(
address _SimplePreTGEAddress,
address _SimpleTGEAddress,
uint256 _vestingBonusMultiplier,
uint256 _vestingDuration,
uint256 _vestingStartTime,
address _LSTAddress
) public {
require(_SimplePreTGEAddress != address(0));
require(_SimpleTGEAddress != address(0));
require(_vestingBonusMultiplier >= 1000000);
require(_vestingBonusMultiplier <= 10000000);
require(_vestingDuration > 0);
require(_vestingStartTime > block.timestamp);
token = LendroidSupportToken(_LSTAddress);
SimplePreTGEContract = SimplePreTGE(_SimplePreTGEAddress);
SimpleTGEContract = SimpleTGE(_SimpleTGEAddress);
vestingBonusMultiplier = _vestingBonusMultiplier;
vestingDuration = _vestingDuration;
vestingStartTime = _vestingStartTime;
}
function mintTokens(address beneficiary, uint256 tokens) public onlyOwner {
require(beneficiary != 0x0);
require(tokens > 0);
require(token.mint(beneficiary, tokens));
LogLSTsWithdrawn(beneficiary, tokens);
}
function withdraw() external {
require(!allocations[msg.sender].hasWithdrawn);
require(block.timestamp > SimpleTGEContract.publicTGEEndBlockTimeStamp().add(SimpleTGEContract.TRSOffset()));
require(SimplePreTGEContract.allocationsLocked());
bool _preTGEHasVested;
uint256 _preTGEWeiContributed;
bool _publicTGEHasVested;
uint256 _publicTGEWeiContributed;
(_publicTGEHasVested, _publicTGEWeiContributed) = SimpleTGEContract.contributions(msg.sender);
(_preTGEHasVested, _preTGEWeiContributed) = SimplePreTGEContract.contributions(msg.sender);
uint256 _totalWeiContribution = _preTGEWeiContributed.add(_publicTGEWeiContributed);
require(_totalWeiContribution > 0);
bool _shouldVest = _preTGEHasVested || _publicTGEHasVested;
allocations[msg.sender].hasWithdrawn = true;
allocations[msg.sender].shouldVest = _shouldVest;
allocations[msg.sender].weiContributed = _totalWeiContribution;
uint256 _lstAllocated;
if (!_shouldVest) {
_lstAllocated = LSTRatePerWEI.mul(_totalWeiContribution);
allocations[msg.sender].LSTAllocated = _lstAllocated;
require(token.mint(msg.sender, _lstAllocated));
LogLSTsWithdrawn(msg.sender, _lstAllocated);
}
else {
_lstAllocated = LSTRatePerWEI.mul(_totalWeiContribution).mul(vestingBonusMultiplier).div(vestingBonusMultiplierPrecision);
allocations[msg.sender].LSTAllocated = _lstAllocated;
uint256 _withdrawNow = _lstAllocated.div(10);
uint256 _vestedPortion = _lstAllocated.sub(_withdrawNow);
vesting[msg.sender] = new TokenVesting(msg.sender, vestingStartTime, 0, vestingDuration, false);
require(token.mint(msg.sender, _withdrawNow));
LogLSTsWithdrawn(msg.sender, _withdrawNow);
require(token.mint(address(vesting[msg.sender]), _vestedPortion));
LogTimeVestingLSTsWithdrawn(address(vesting[msg.sender]), _vestedPortion, vestingStartTime, 0, vestingDuration);
}
}
function releaseVestedTokens(address beneficiary) public {
require(beneficiary != 0x0);
TokenVesting tokenVesting = vesting[beneficiary];
tokenVesting.release(token);
}
function unpauseToken() public onlyOwner {
token.unpause();
}
}