Skip to content

Instantly share code, notes, and snippets.

@bitdollarfund
Created June 2, 2018 17:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bitdollarfund/ab4ad8ad8daf392f6b3fa5077fdd99f0 to your computer and use it in GitHub Desktop.
Save bitdollarfund/ab4ad8ad8daf392f6b3fa5077fdd99f0 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.24+commit.e67f0147.js&optimize=true&gist=
pragma solidity 0.4.24;
contract owned {
address public owner;
function owned() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) onlyOwner public {
owner = newOwner;
}
}
contract tokenRecipient {
event receivedEther(address sender, uint amount);
event receivedTokens(address _from, uint256 _value, address _token, bytes _extraData);
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public {
Token t = Token(_token);
require(t.transferFrom(_from, this, _value));
receivedTokens(_from, _value, _token, _extraData);
}
function () payable public {
receivedEther(msg.sender, msg.value);
}
}
contract Token {
function balanceOf(address _owner) public view returns (uint256 balance);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function totalSupply() public view returns (uint256 total);
}
/**
* The shareholder association contract itself
*/
contract BitdollarAssociation is owned, tokenRecipient {
uint public minimumQuorum;
uint public debatingPeriodInMinutes;
Proposal[] public proposals;
uint public numProposals;
Token public sharesTokenAddress;
event ProposalAdded(uint proposalID, address recipient, uint amount, string description);
event Voted(uint proposalID, bool position, address voter);
event ProposalTallied(uint proposalID, int result, uint quorum, bool active);
event ChangeOfRules(uint newMinimumQuorum, uint newDebatingPeriodInMinutes, address newSharesTokenAddress);
event Summary(uint proposalID, uint participationStatistic);
event MCQ(uint proposalID, uint8 option, address voter);
event WinningMCQ(uint indexNumber, uint tally);
struct Proposal {
address recipient;
uint amount;
string description;
uint votingDeadline;
bool executed;
bool proposalPassed;
uint numberOfVotes;
bytes32 proposalHash;
Vote[] votes;
mapping (address => bool) voted;
bool multipleChoice;
uint numberOfChoices;
uint[11] choices; // choices[0] is dummy variable
}
struct Vote {
bool inSupport;
uint8 choice;
address voter;
}
// Modifier that allows only shareholders to vote and create new proposals
modifier onlyShareholders {
require(sharesTokenAddress.balanceOf(msg.sender) > 0);
_;
}
/**
* Constructor function
*
* First time setup
*/
function BitdollarAssociation(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) payable public {
changeVotingRules(sharesAddress, minimumSharesToPassAVote, minutesForDebate);
}
/**
* Change voting rules
*
* Make so that proposals need to be discussed for at least `minutesForDebate/60` hours
* and all voters combined must own more than `minimumSharesToPassAVote` shares of token `sharesAddress` to be executed
*
* @param sharesAddress token address
* @param minimumSharesToPassAVote proposal can vote only if the sum of shares held by all voters exceed this number
* @param minutesForDebate the minimum amount of delay between when a proposal is made and when it can be executed
*/
function changeVotingRules(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) onlyOwner public {
sharesTokenAddress = Token(sharesAddress);
if (minimumSharesToPassAVote == 0 ) minimumSharesToPassAVote = 1;
minimumQuorum = minimumSharesToPassAVote;
debatingPeriodInMinutes = minutesForDebate;
ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, sharesTokenAddress);
}
/**
* Add Proposal
*
* Propose to send `weiAmount / 1e18` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
*
* @param beneficiary who to send the ether to
* @param weiAmount amount of ether to send, in wei
* @param jobDescription Description of job
* @param transactionBytecode bytecode of transaction
*/
function newProposal(
address beneficiary,
uint weiAmount,
string jobDescription,
bytes transactionBytecode
)
onlyShareholders
public returns (uint proposalID)
{
proposalID = proposals.length++;
Proposal storage p = proposals[proposalID];
p.recipient = beneficiary;
p.amount = weiAmount;
p.description = jobDescription;
p.proposalHash = keccak256(beneficiary, weiAmount, transactionBytecode);
p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
p.executed = false;
p.proposalPassed = false;
p.numberOfVotes = 0;
ProposalAdded(proposalID, beneficiary, weiAmount, jobDescription);
numProposals = proposalID+1;
p.multipleChoice = false; // no multiple choice for default yea/nay votes
p.numberOfChoices = 0;
return proposalID;
}
/**
* Add proposal in Ether
*
* Propose to send `etherAmount` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
* This is a convenience function to use if the amount to be given is in round number of ether units.
*
* @param beneficiary who to send the ether to
* @param etherAmount amount of ether to send
* @param jobDescription Description of job
* @param transactionBytecode bytecode of transaction
*/
function newProposalInEther(
address beneficiary,
uint etherAmount,
string jobDescription,
bytes transactionBytecode
)
onlyShareholders
public returns (uint proposalID)
{
return newProposal(beneficiary, etherAmount * 1 ether, jobDescription, transactionBytecode);
}
function newMCQProposal (
address beneficiary,
uint weiAmount,
string jobDescription,
uint numChoices,
bytes transactionBytecode
)
onlyShareholders
public returns (uint proposalID)
{
require(numChoices <= 10);
proposalID = proposals.length++;
Proposal storage p = proposals[proposalID];
p.recipient = beneficiary;
p.amount = weiAmount;
p.description = jobDescription;
p.proposalHash = keccak256(beneficiary, weiAmount, transactionBytecode);
p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
p.executed = false;
p.proposalPassed = false;
p.numberOfVotes = 0;
ProposalAdded(proposalID, beneficiary, weiAmount, jobDescription);
numProposals = proposalID+1;
p.multipleChoice = true; // no multiple choice for default yea/nay votes
p.numberOfChoices = numChoices;
return proposalID;
}
/**
* Check if a proposal code matches
*
* @param proposalNumber ID number of the proposal to query
* @param beneficiary who to send the ether to
* @param weiAmount amount of ether to send
* @param transactionBytecode bytecode of transaction
*/
function checkProposalCode(
uint proposalNumber,
address beneficiary,
uint weiAmount,
bytes transactionBytecode
)
constant
public returns (bool codeChecksOut)
{
Proposal storage p = proposals[proposalNumber];
return p.proposalHash == keccak256(beneficiary, weiAmount, transactionBytecode);
}
/**
* Log a vote for a proposal
*
* Vote `supportsProposal? in support of : against` proposal #`proposalNumber`
*
* @param proposalNumber number of proposal
* @param supportsProposal either in favor or against it
*/
function vote(
uint proposalNumber,
bool supportsProposal
)
onlyShareholders
public returns (uint voteID)
{
Proposal storage p = proposals[proposalNumber];
require(!p.multipleChoice);
require(p.voted[msg.sender] != true);
voteID = p.votes.length++;
p.votes[voteID] = Vote({inSupport: supportsProposal, choice: 0, voter: msg.sender});
p.voted[msg.sender] = true;
p.numberOfVotes = voteID +1;
Voted(proposalNumber, supportsProposal, msg.sender);
return voteID;
}
/**
* Log a vote for an MCQ proposal
*
* Vote `supportsProposal? in support of : against` proposal #`proposalNumber`
*
* @param proposalNumber number of proposal
* @param optionNumber the choice made in MCQ
*/
function multipleChoiceVote(
uint proposalNumber,
uint8 optionNumber
)
onlyShareholders
public returns (uint voteID)
{
Proposal storage p = proposals[proposalNumber];
require(p.multipleChoice);
require(optionNumber <= p.numberOfChoices && optionNumber > 0);
require(p.voted[msg.sender] != true);
voteID = p.votes.length++;
p.votes[voteID] = Vote({inSupport: true, choice: optionNumber, voter: msg.sender});
p.voted[msg.sender] = true;
p.numberOfVotes = voteID +1;
p.choices[optionNumber]++;
MCQ(proposalNumber, optionNumber, msg.sender);
return voteID;
}
/**
* Finish vote
*
* Count the votes proposal #`proposalNumber` and execute it if approved
*
* @param proposalNumber proposal number
* @param transactionBytecode optional: if the transaction contained a bytecode, you need to send it
*/
function executeProposal(uint proposalNumber, bytes transactionBytecode) public {
Proposal storage p = proposals[proposalNumber];
require(now > p.votingDeadline // If it is past the voting deadline
&& !p.executed // and it has not already been executed
&& !p.multipleChoice
&& p.proposalHash == keccak256(p.recipient, p.amount, transactionBytecode)); // and the supplied code matches the proposal...
// ...then tally the results
uint quorum = 0;
uint yea = 0;
uint nay = 0;
for (uint i = 0; i < p.votes.length; ++i) {
Vote storage v = p.votes[i];
uint voteWeight = sharesTokenAddress.balanceOf(v.voter);
quorum += voteWeight;
if (v.inSupport) {
yea += voteWeight;
} else {
nay += voteWeight;
}
}
require(quorum >= minimumQuorum); // Check if a minimum quorum has been reached
if (yea > nay ) {
// Proposal passed; execute the transaction
p.executed = true;
require(p.recipient.call.value(p.amount)(transactionBytecode));
p.proposalPassed = true;
} else {
// Proposal failed
p.proposalPassed = false;
}
// Fire Events
ProposalTallied(proposalNumber, int(yea) - int(nay), quorum, p.proposalPassed);
uint statistic = quorum * 100000 / sharesTokenAddress.totalSupply(); // the percentage of "coins" that voted; at 5 degrees precision
Summary(proposalNumber, statistic);
}
/**
* Finish vote
*
* Count the votes proposal #`proposalNumber` and execute it if approved
*
* @param proposalNumber proposal number
* @param transactionBytecode optional: if the transaction contained a bytecode, you need to send it
*/
function analyzeMCQProposal(uint proposalNumber, bytes transactionBytecode) public {
Proposal storage p = proposals[proposalNumber];
require(now > p.votingDeadline // If it is past the voting deadline
&& !p.executed // and it has not already been executed
&& p.multipleChoice
&& p.proposalHash == keccak256(p.recipient, p.amount, transactionBytecode)); // and the supplied code matches the proposal...
uint max = 0;
uint index = 0;
for(uint j = 1; j <= p.numberOfChoices; j++) {
if(p.choices[j] >= max) {
max = p.choices[j];
index = j;
}
}
uint quorum = 0;
for (uint i = 0; i < p.votes.length; ++i) {
Vote storage v = p.votes[i];
uint voteWeight = sharesTokenAddress.balanceOf(v.voter);
quorum += voteWeight;
}
require(quorum >= minimumQuorum); // Check if a minimum quorum has been reached
uint statistic = quorum * 100000 / sharesTokenAddress.totalSupply(); // the percentage of "coins" that voted; at 5 degrees precision
Summary(proposalNumber, statistic);
WinningMCQ(index, max);
}
}
pragma solidity 0.4.24;
import './BitdollarToken.sol';
import './SafeMath.sol';
// deploy BitdollarToken contract first and pass that address as parameter to this contract's constructor
// deploy BitdollarVault and pass to it the BitdollarToken address and this contract's address as parameters
// finally, assign this contract's address as tokenContoller and the BitdollarVault address as tokenVault in BitdollarToken by invoking
// the changeTokenController function
contract BitdollarCampaign is SafeMath {
BitdollarToken bitdollarTokenContract;
// keeps track of total number of tokens sold throughout all phases
uint256 public totalSold;
// current phase token cap
uint256 public currentPhaseCap;
// tokens sold in current phase
uint256 public currentPhaseTokenSales;
// running total of development allocation accumulated in current phase
uint256 public developmentAllocationRunningTotal;
// current phase development allocation percent (takes 17 digit input for precision)
uint256 public developmentAllocationPercent;
// current phase starting block
uint256 public fundingStartBlock;
// current phase ending block
uint256 public fundingEndBlock;
// current phase minimum purchase threshold
uint256 public minAmount;
// current phase price
Price public currentPrice;
// state variable indicates if active sale phase
bool public icoMode;
// state variable to indicate ico parameters have been entered
bool public icoPrimed;
// amount of tokens unsold during current phase
// fundWallet may add this amount to subsequent phase cap at their discretion
uint256 public tokenCapRollOverToNextPhase;
// vesting fields
address public vestingContract;
bool private vestingSet;
// root control
address public fundWallet;
// control of liquidity and limited control of updatePrice
address public controlWallet;
// time to wait between controlWallet price updates
uint256 public waitTime;
// halted: halt buying due to emergency, tradeable: signal that assets have been acquired
bool public halted;
// is maintained inside token contract
//bool public tradeable;
// last update timestamp
uint256 public previousUpdateTime;
// maps previousUpdateTime to the next price
mapping (uint256 => Price) public prices;
// maps addresses
mapping (address => bool) public whitelist;
// TYPES
struct Price { // tokensPerEth
uint256 numerator;
uint256 denominator;
}
// EVENTS
event Buy(address indexed participant, address indexed beneficiary, uint256 ethValue, uint256 amountTokens);
event AllocatePresale(address indexed participant, uint256 amountTokens);
event Whitelist(address indexed participant);
event PriceUpdate(uint256 numerator, uint256 denominator);
event ICO(uint256 phaseCap, uint256 phaseStart, uint256 phaseEnd);
//enum Phase { Initial, PreSale, Sale, Closed }
enum Phase { PreSale, Sale, Closed }
Phase public phase;
// MODIFIERS
//TODO this modifier is not used ///////////////////////////////////////////////////////////////////
// modifier isTradeable { // exempt vestingContract and fundWallet to allow dev allocations
// require(tradeable || msg.sender == fundWallet || msg.sender == vestingContract);
// _;
// }
modifier onlyWhitelist {
require(whitelist[msg.sender]);
_;
}
modifier onlyFundWallet {
require(msg.sender == fundWallet);
_;
}
modifier onlyManagingWallets {
require(msg.sender == controlWallet || msg.sender == fundWallet);
_;
}
modifier only_if_controlWallet {
if (msg.sender == controlWallet)
_;
}
modifier require_waited {
require(safeSub(now, waitTime) >= previousUpdateTime);
_;
}
modifier only_if_increase (uint256 newNumerator) {
if (newNumerator > currentPrice.numerator)
_;
}
modifier whileSaleActive {
require(block.number >= fundingStartBlock && block.number < fundingEndBlock && icoMode);
_;
}
// CONSTRUCTOR
constructor(address controlWalletInput,
address tokenContractInput,
uint256 priceNumeratorInput) public {
require(controlWalletInput != address(0) && tokenContractInput != address(0) && priceNumeratorInput > 0);
controlWallet = controlWalletInput;
bitdollarTokenContract = BitdollarToken(tokenContractInput);
currentPrice = Price(priceNumeratorInput, 1000); // 1 token = 1 usd at ICO start
previousUpdateTime = now;
fundWallet = msg.sender;
whitelist[fundWallet] = true;
whitelist[controlWallet] = true;
waitTime = 5 hours;
vestingSet = false;
halted = false;
icoMode = false;
// phase = Phase.Initial;
phase = Phase.Closed;
}
// METHODS
// TODO set three vesting contracts
function setVestingContract(address vestingContractInput) external onlyFundWallet {
require(vestingContractInput != address(0));
vestingContract = vestingContractInput;
//whitelist[vestingContract] = true; any reason for vestingContract address to purchase more tokens?
vestingSet = true;
}
// allows controlWallet to update the price within a time contstraint, allows fundWallet complete control
function updatePrice(uint256 newNumerator) external onlyManagingWallets {
require(newNumerator > 0);
require_limited_change(newNumerator);
// either controlWallet command is compliant or transaction came from fundWallet
currentPrice.numerator = newNumerator;
// maps time to new Price (if not during ICO)
prices[previousUpdateTime] = currentPrice;
previousUpdateTime = now;
PriceUpdate(newNumerator, currentPrice.denominator);
}
function require_limited_change (uint256 newNumerator)
private
only_if_controlWallet
require_waited
only_if_increase(newNumerator)
view
{
uint256 percentage_diff = 0;
percentage_diff = safeMul(newNumerator, 100) / currentPrice.numerator;
percentage_diff = safeSub(percentage_diff, 100);
// controlWallet can only increase price by max 20% and only every waitTime
require(percentage_diff <= 20);
}
function updatePriceDenominator(uint256 newDenominator) external onlyFundWallet {
require(!icoMode);
//require(block.number > fundingEndBlock);
require(newDenominator > 0);
currentPrice.denominator = newDenominator;
// maps time to new Price
prices[previousUpdateTime] = currentPrice;
previousUpdateTime = now;
PriceUpdate(currentPrice.numerator, newDenominator);
}
function allocateTokens(address participant, uint256 amountTokens) internal {
//require(vestingSet);
// 15% of total allocated for PR, Marketing, Team, Advisors
// uint256 devAllocation = safeMul(amountTokens, 17647058823529400) / 100000000000000000;
uint256 devAllocation = safeMul(amountTokens, developmentAllocationPercent) / 100000000000000000;
// check that token cap is not exceeded
uint256 newTokens = safeAdd(amountTokens, devAllocation);
require(safeAdd(currentPhaseTokenSales, newTokens) <= currentPhaseCap);
//require(safeAdd(tokenSold, newTokens) <= tokenCap);
// increase token supply, assign tokens to participant
currentPhaseTokenSales = safeAdd(currentPhaseTokenSales, newTokens);
totalSold = safeAdd(totalSold, newTokens);
//tokenSold = safeAdd(tokenSold, newTokens);
developmentAllocationRunningTotal = safeAdd(developmentAllocationRunningTotal, devAllocation);
require(bitdollarTokenContract.generateTokens(participant, amountTokens));
//balances[participant] = safeAdd(balances[participant], amountTokens);
//balances[vestingContract] = safeAdd(balances[vestingContract], developmentAllocation);
}
function allocatePresaleTokens(address participant, uint amountTokens) external onlyFundWallet whileSaleActive {
//require(block.number < fundingEndBlock);
require(participant != address(0) && amountTokens > 0);
whitelist[participant] = true; // automatically whitelist accepted presale
allocateTokens(participant, amountTokens);
Whitelist(participant);
AllocatePresale(participant, amountTokens);
}
function verifyParticipant(address participant) external onlyManagingWallets {
require(participant != address(0));
whitelist[participant] = true;
Whitelist(participant);
}
// fallback function
function() external payable whileSaleActive {
// TODO is this check necessary? //////////////////////////////////////
// require(tx.origin == msg.sender);
buy(msg.sender);
}
function buy(address msgsender) public payable whileSaleActive {
require(!halted);
// if presale phase
if(phase == Phase.PreSale) {
// must be whitelisted participant
if(whitelist[msgsender]) {
buyTo(msgsender);
// else check if minimum amount in ether is supplied
} else if (msg.value > minAmount) {
// add them to whitelist
whitelist[msgsender] = true;
Whitelist(msgsender);
buyTo(msgsender);
}
}
else
require(msg.value > minAmount);
buyTo(msgsender);
}
function buyTo(address participant) internal returns (bool) {
uint256 icoDenominator = icoDenominatorPrice();
uint256 tokensToBuy = safeMul(msg.value, currentPrice.numerator) / icoDenominator;
allocateTokens(participant, tokensToBuy);
// send ether to fundWallet
fundWallet.transfer(msg.value);
Buy(msg.sender, participant, msg.value, tokensToBuy);
}
// time based on blocknumbers, assuming a blocktime of 30s
function icoDenominatorPrice() public constant returns (uint256) {
uint256 icoDuration = safeSub(block.number, fundingStartBlock);
uint256 denominator;
if (icoDuration < 2880) { // #blocks = 24*60*60/30 = 2880
return currentPrice.denominator;
} else if (icoDuration < 80640 ) { // #blocks = 4*7*24*60*60/30 = 80640
denominator = safeMul(currentPrice.denominator, 105) / 100;
return denominator;
} else {
denominator = safeMul(currentPrice.denominator, 110) / 100;
return denominator;
}
}
function changeFundWallet(address newFundWallet) external onlyFundWallet {
require(newFundWallet != address(0));
fundWallet = newFundWallet;
}
function changeControlWallet(address newControlWallet) external onlyFundWallet {
require(newControlWallet != address(0));
controlWallet = newControlWallet;
}
function changeWaitTime(uint256 newWaitTime) external onlyFundWallet {
waitTime = newWaitTime;
}
function updateFundingStartBlock(uint256 newFundingStartBlock) external onlyFundWallet {
require(block.number < fundingStartBlock);
require(block.number < newFundingStartBlock);
require(newFundingStartBlock < fundingEndBlock); // sanity check
fundingStartBlock = newFundingStartBlock;
}
function updateFundingEndBlock(uint256 newFundingEndBlock) external onlyFundWallet {
require(block.number < fundingEndBlock);
require(block.number < newFundingEndBlock);
require(fundingStartBlock < newFundingEndBlock); // sanity check
fundingEndBlock = newFundingEndBlock;
}
// update minimum amount for investment
// @param newMinAmount the units in ether; eg input 10 for a 10 ETH minimum
function updateMinimumEtherAmount(uint256 newMinAmount) external onlyFundWallet {
require(!icoMode);
minAmount = newMinAmount * 1 ether;
}
// update developer percentage allocation
// @param newDevAllocationPercentage takes a 17 digit precision input
function updateDevAllocationPercentage(uint256 newDevAllocationPercentage) external onlyFundWallet {
require(!icoMode);
developmentAllocationPercent = newDevAllocationPercentage;
}
// update currentPhaseCap
// @param newCurrentPhaseCap is expected to be between 100 000 000 and 400 000 000; will be converted internally
function updateCurrentPhaseCap(uint256 newCurrentPhaseCap) external onlyFundWallet {
require(!icoMode);
currentPhaseCap = newCurrentPhaseCap * 10**18;
}
// internal function to select phase state
// @param presale a boolean to indicate if presale, if false will activate Sale phase state
function setPhase(bool presale) internal {
// // cannot change if Initial Phase
// if(phase == Phase.Initial) {
// return;
// } else if(presale) {
// phase = Phase.PreSale;
// } else {
// phase = Phase.Sale;
// }
if(presale) {
phase = Phase.PreSale;
} else {
phase = Phase.Sale;
}
}
// update phase state
// only allows switching from PreSale to Sale and vice versa
function updatePhase() external onlyFundWallet {
if(phase == Phase.PreSale) {
phase = Phase.Sale;
} else if (phase == Phase.Sale) {
phase = Phase.PreSale;
}
}
function halt() external onlyFundWallet {
halted = true;
}
function unhalt() external onlyFundWallet {
halted = false;
}
// enables trading, withdrawals and token transfers are allowed in this state
function enableTrading() external onlyFundWallet {
// cannot enable during an active crowdsale
require(!icoMode);
bitdollarTokenContract.toggleTrading(true);
//tradeable = true;
}
// disables token trading, cannot make withdrawals from BitdollarVault or transfer tokens between accounts in this state
function disableTrading() external onlyFundWallet {
bitdollarTokenContract.toggleTrading(false);
//tradeable = false;
}
function claimTokens(address _token) external onlyFundWallet {
require(_token != address(0));
Token token = Token(_token);
uint256 balance = token.balanceOf(this);
token.transfer(fundWallet, balance);
}
function _balanceOf(address _addr) internal view returns(uint256) {
return bitdollarTokenContract.balanceOf(_addr);
}
function getPrice(uint256 timestamp) external view returns (uint256, uint256) {
return (prices[timestamp].numerator, prices[timestamp].denominator);
}
function getCurrentPrice() external view returns (uint256, uint256) {
return (currentPrice.numerator, currentPrice.denominator);
}
function getPreviousUpdateTime() external view returns (uint256) {
return previousUpdateTime;
}
function setupParameters(uint256 startBlockInput,
uint256 endBlockInput,
uint256 minAmountInput, // in wei
uint256 devPercentInput, // takes 17 digit precision input
uint256 phaseCapInput, // cap for the current phase - must multiply coin count by 10**18
bool isPresale, // set true for presale, false for sale
bool primeICO) // set true if there is confidence in paramaters supplied - ready to activate
external onlyFundWallet {
// must not be in active ico
require(!icoMode);
// specified blocks must be in the future and have valid duration
require(block.number < startBlockInput && startBlockInput < endBlockInput);
// prices must have been previously set - if not updated the new phase will carry the same price as the previous phase
// fundWallet must invoke updatePrice and updatePriceDenominator externally to change prices
// set to current ether equivalent of $100000 minimum to qualify for presale purchase
// set to an arbitrary minimum eg 0.01 ether during normal sale to prevent spam calls from congesting the contract
require(minAmountInput > 0);
minAmount = minAmountInput;
// reset running total
developmentAllocationRunningTotal = 0;
developmentAllocationPercent = devPercentInput;
// reset current token sales count
currentPhaseTokenSales = 0;
currentPhaseCap = phaseCapInput;
// crowdsale parameters
fundingStartBlock = startBlockInput;
fundingEndBlock = endBlockInput;
// cannot transfer BTD when active ICO to avoid price undercutting by current holders at third party exchange
bitdollarTokenContract.toggleTrading(false);
setPhase(isPresale);
// indicate ico parameters are primed
icoPrimed = primeICO;
}
// activates ico to start accepting ether
function activateICO() external onlyFundWallet {
require(!icoMode && icoPrimed);
icoPrimed = false;
icoMode = true;
}
// closes current ico and generates dev allocation tokens
function finalizeCurrentICO() external onlyFundWallet {
require(icoMode);
require(block.number > fundingEndBlock);
//balances[vestingContract] = safeAdd(balances[vestingContract], developmentAllocation);
require(vestingSet);
// generate allocation tokens accumulated throughout the sale
require(bitdollarTokenContract.generateTokens(vestingContract, developmentAllocationRunningTotal));
icoMode = false;
phase = Phase.Closed;
tokenCapRollOverToNextPhase = safeSub(currentPhaseCap, currentPhaseTokenSales);
}
}
pragma solidity 0.4.24;
contract owned {
address public owner;
function owned() public {
owner = msg.sender;
}
modifier onlyOwner {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) onlyOwner public {
owner = newOwner;
}
}
contract tokenRecipient {
event receivedEther(address sender, uint amount);
event receivedTokens(address _from, uint256 _value, address _token, bytes _extraData);
function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData) public {
Token t = Token(_token);
require(t.transferFrom(_from, this, _value));
receivedTokens(_from, _value, _token, _extraData);
}
function () payable public {
receivedEther(msg.sender, msg.value);
}
}
contract Token {
function balanceOf(address _owner) public view returns (uint256 balance);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function totalSupply() public view returns (uint256 total);
}
/**
* The shareholder association contract itself
*/
contract BitdollarMembersAssociation is owned, tokenRecipient {
uint public minimumQuorum;
uint public debatingPeriodInMinutes;
Proposal[] public proposals;
uint public numProposals;
Token public sharesTokenAddress;
mapping (address => uint) public memberId;
Member[] public members;
event ProposalAdded(uint proposalID, address recipient, uint amount, string description);
event Voted(uint proposalID, bool position, address voter);
event ProposalTallied(uint proposalID, int result, uint quorum, bool active);
event ChangeOfRules(uint newMinimumQuorum, uint newDebatingPeriodInMinutes, address newSharesTokenAddress);
event MembershipChanged(address member, bool isMember);
event Summary(uint proposalID, uint participationStatistic);
event MCQ(uint proposalID, uint8 option, address voter);
event WinningMCQ(uint indexNumber, uint tally);
struct Member {
address member;
string name;
uint memberSince;
bool delegated;
uint256 weight;
uint256 representingCount;
}
struct Proposal {
address recipient;
uint amount;
string description;
uint votingDeadline;
bool executed;
bool proposalPassed;
uint numberOfVotes;
bytes32 proposalHash;
Vote[] votes;
mapping (address => bool) voted;
bool multipleChoice;
uint numberOfChoices;
uint[11] choices; // choices[0] is dummy variable
}
struct Vote {
bool inSupport;
uint8 choice;
address voter;
}
// // Modifier that allows only shareholders to vote and create new proposals
// modifier onlyShareholders {
// require(sharesTokenAddress.balanceOf(msg.sender) > 0);
// _;
// }
// Modifier that allows only shareholders to vote and create new proposals
modifier onlyMembers {
require(memberId[msg.sender] != 0);
_;
}
/**
* Constructor function
*
* First time setup
*/
function BitdollarAssociation(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) payable public {
changeVotingRules(sharesAddress, minimumSharesToPassAVote, minutesForDebate);
// It’s necessary to add an empty first member
addMember(0, "");
// and let's add the founder, to save a step later
addMember(owner, 'founder');
}
function delegateVote(address nominee) public onlyMembers returns(bool) {
uint ID = memberId[msg.sender];
Member storage m = members[ID];
m.delegated = true;
uint nomineeID = memberId[nominee];
Member storage n = members[nomineeID];
n.representingCount++;
n.weight = n.weight+m.weight;
return true;
}
function undoDelegation(address nominee) public onlyMembers returns(bool) {
uint ID = memberId[msg.sender];
Member storage m = members[ID];
m.delegated = false;
uint nomineeID = memberId[nominee];
Member storage n = members[nomineeID];
n.representingCount--;
n.weight = n.weight-m.weight;
return true;
}
/**
* Add member
*
* Make `targetMember` a member named `memberName`
*
* @param targetMember ethereum address to be added
* @param memberName public name for that member
* WARNING resets any delegations
*/
function addMember(address targetMember, string memberName) onlyOwner public {
require(memberId[targetMember] ==0);
//if (id == 0)
memberId[targetMember] = members.length;
uint id = members.length++;
uint voteWeight = sharesTokenAddress.balanceOf(msg.sender);
members[id] = Member({member: targetMember, memberSince: now, name: memberName, delegated:false, weight: voteWeight, representingCount: 1});
MembershipChanged(targetMember, true);
}
/**
* Remove member
*
* @notice Remove membership from `targetMember`
*
* @param targetMember ethereum address to be removed
*/
function removeMember(address targetMember) onlyOwner public {
require(memberId[targetMember] != 0);
for (uint i = memberId[targetMember]; i<members.length-1; i++){
members[i] = members[i+1];
}
delete members[members.length-1];
members.length--;
}
/**
* Change voting rules
*
* Make so that proposals need to be discussed for at least `minutesForDebate/60` hours
* and all voters combined must own more than `minimumSharesToPassAVote` shares of token `sharesAddress` to be executed
*
* @param sharesAddress token address
* @param minimumSharesToPassAVote proposal can vote only if the sum of shares held by all voters exceed this number
* @param minutesForDebate the minimum amount of delay between when a proposal is made and when it can be executed
*/
function changeVotingRules(Token sharesAddress, uint minimumSharesToPassAVote, uint minutesForDebate) onlyOwner public {
sharesTokenAddress = Token(sharesAddress);
if (minimumSharesToPassAVote == 0 ) minimumSharesToPassAVote = 1;
minimumQuorum = minimumSharesToPassAVote;
debatingPeriodInMinutes = minutesForDebate;
ChangeOfRules(minimumQuorum, debatingPeriodInMinutes, sharesTokenAddress);
}
/**
* Add Proposal
*
* Propose to send `weiAmount / 1e18` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
*
* @param beneficiary who to send the ether to
* @param weiAmount amount of ether to send, in wei
* @param jobDescription Description of job
* @param transactionBytecode bytecode of transaction
*/
function newProposal(
address beneficiary,
uint weiAmount,
string jobDescription,
bytes transactionBytecode
)
onlyMembers
public returns (uint proposalID)
{
proposalID = proposals.length++;
Proposal storage p = proposals[proposalID];
p.recipient = beneficiary;
p.amount = weiAmount;
p.description = jobDescription;
p.proposalHash = keccak256(beneficiary, weiAmount, transactionBytecode);
p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
p.executed = false;
p.proposalPassed = false;
p.numberOfVotes = 0;
ProposalAdded(proposalID, beneficiary, weiAmount, jobDescription);
numProposals = proposalID+1;
p.multipleChoice = false; // no multiple choice for default yea/nay votes
p.numberOfChoices = 0;
return proposalID;
}
/**
* Add proposal in Ether
*
* Propose to send `etherAmount` ether to `beneficiary` for `jobDescription`. `transactionBytecode ? Contains : Does not contain` code.
* This is a convenience function to use if the amount to be given is in round number of ether units.
*
* @param beneficiary who to send the ether to
* @param etherAmount amount of ether to send
* @param jobDescription Description of job
* @param transactionBytecode bytecode of transaction
*/
function newProposalInEther(
address beneficiary,
uint etherAmount,
string jobDescription,
bytes transactionBytecode
)
onlyMembers
public returns (uint proposalID)
{
return newProposal(beneficiary, etherAmount * 1 ether, jobDescription, transactionBytecode);
}
function newMCQProposal (
address beneficiary,
uint weiAmount,
string jobDescription,
uint numChoices,
bytes transactionBytecode
)
onlyMembers
public returns (uint proposalID)
{
require(numChoices <= 10);
proposalID = proposals.length++;
Proposal storage p = proposals[proposalID];
p.recipient = beneficiary;
p.amount = weiAmount;
p.description = jobDescription;
p.proposalHash = keccak256(beneficiary, weiAmount, transactionBytecode);
p.votingDeadline = now + debatingPeriodInMinutes * 1 minutes;
p.executed = false;
p.proposalPassed = false;
p.numberOfVotes = 0;
ProposalAdded(proposalID, beneficiary, weiAmount, jobDescription);
numProposals = proposalID+1;
p.multipleChoice = true; // no multiple choice for default yea/nay votes
p.numberOfChoices = numChoices;
return proposalID;
}
/**
* Check if a proposal code matches
*
* @param proposalNumber ID number of the proposal to query
* @param beneficiary who to send the ether to
* @param weiAmount amount of ether to send
* @param transactionBytecode bytecode of transaction
*/
function checkProposalCode(
uint proposalNumber,
address beneficiary,
uint weiAmount,
bytes transactionBytecode
)
constant
public returns (bool codeChecksOut)
{
Proposal storage p = proposals[proposalNumber];
return p.proposalHash == keccak256(beneficiary, weiAmount, transactionBytecode);
}
/**
* Log a vote for a proposal
*
* Vote `supportsProposal? in support of : against` proposal #`proposalNumber`
*
* @param proposalNumber number of proposal
* @param supportsProposal either in favor or against it
*/
function vote(
uint proposalNumber,
bool supportsProposal
)
onlyMembers
public returns (uint voteID)
{
Proposal storage p = proposals[proposalNumber];
require(!p.multipleChoice);
require(p.voted[msg.sender] != true);
uint ID = memberId[msg.sender];
require(!members[ID].delegated);
voteID = p.votes.length++;
p.votes[voteID] = Vote({inSupport: supportsProposal, choice: 0, voter: msg.sender});
p.voted[msg.sender] = true;
p.numberOfVotes = voteID +1;
Voted(proposalNumber, supportsProposal, msg.sender);
return voteID;
}
/**
* Log a vote for an MCQ proposal
*
* Vote `supportsProposal? in support of : against` proposal #`proposalNumber`
*
* @param proposalNumber number of proposal
* @param optionNumber the choice made in MCQ
*/
function multipleChoiceVote(
uint proposalNumber,
uint8 optionNumber
)
onlyMembers
public returns (uint voteID)
{
Proposal storage p = proposals[proposalNumber];
require(p.multipleChoice);
require(optionNumber <= p.numberOfChoices && optionNumber > 0);
require(p.voted[msg.sender] != true);
uint ID = memberId[msg.sender];
Member storage m = members[ID];
require(!m.delegated);
voteID = p.votes.length++;
p.votes[voteID] = Vote({inSupport: true, choice: optionNumber, voter: msg.sender});
p.voted[msg.sender] = true;
p.numberOfVotes = voteID +1;
uint count = m.representingCount;
p.choices[optionNumber] = p.choices[optionNumber] + count;
MCQ(proposalNumber, optionNumber, msg.sender);
return voteID;
}
/**
* Finish vote
*
* Count the votes proposal #`proposalNumber` and execute it if approved
*
* @param proposalNumber proposal number
* @param transactionBytecode optional: if the transaction contained a bytecode, you need to send it
*/
function executeProposal(uint proposalNumber, bytes transactionBytecode) public {
Proposal storage p = proposals[proposalNumber];
require(now > p.votingDeadline // If it is past the voting deadline
&& !p.executed // and it has not already been executed
&& !p.multipleChoice
&& p.proposalHash == keccak256(p.recipient, p.amount, transactionBytecode)); // and the supplied code matches the proposal...
// ...then tally the results
uint quorum = 0;
uint yea = 0;
uint nay = 0;
for (uint i = 0; i < p.votes.length; ++i) {
Vote storage v = p.votes[i];
uint ID = memberId[v.voter];
uint voteWeight = members[ID].weight;//sharesTokenAddress.balanceOf(v.voter);
quorum += voteWeight;
if (v.inSupport) {
yea += voteWeight;
} else {
nay += voteWeight;
}
}
require(quorum >= minimumQuorum); // Check if a minimum quorum has been reached
if (yea > nay ) {
// Proposal passed; execute the transaction
p.executed = true;
require(p.recipient.call.value(p.amount)(transactionBytecode));
p.proposalPassed = true;
} else {
// Proposal failed
p.proposalPassed = false;
}
// Fire Events
ProposalTallied(proposalNumber, int(yea) - int(nay), quorum, p.proposalPassed);
uint statistic = quorum * 100000 / sharesTokenAddress.totalSupply(); // the percentage of "coins" that voted; at 5 degrees precision
Summary(proposalNumber, statistic);
}
/**
* Finish vote
*
* Count the votes proposal #`proposalNumber` and execute it if approved
*
* @param proposalNumber proposal number
* @param transactionBytecode optional: if the transaction contained a bytecode, you need to send it
*/
function analyzeMCQProposal(uint proposalNumber, bytes transactionBytecode) public {
Proposal storage p = proposals[proposalNumber];
require(now > p.votingDeadline // If it is past the voting deadline
&& !p.executed // and it has not already been executed
&& p.multipleChoice
&& p.proposalHash == keccak256(p.recipient, p.amount, transactionBytecode)); // and the supplied code matches the proposal...
uint max = 0;
uint index = 0;
for(uint j = 1; j <= p.numberOfChoices; j++) {
if(p.choices[j] >= max) {
max = p.choices[j];
index = j;
}
}
uint quorum = 0;
for (uint i = 0; i < p.votes.length; ++i) {
Vote storage v = p.votes[i];
uint ID = memberId[v.voter];
uint voteWeight = members[ID].weight;//sharesTokenAddress.balanceOf(v.voter);
quorum += voteWeight;
}
require(quorum >= minimumQuorum); // Check if a minimum quorum has been reached
uint statistic = quorum * 100000 / sharesTokenAddress.totalSupply(); // the percentage of "coins" that voted; at 5 degrees precision
Summary(proposalNumber, statistic);
WinningMCQ(index, max);
}
}
pragma solidity 0.4.24;
import './Token.sol';
import './TokenController.sol';
import './SafeMath.sol';
// assign tokenVault address to BitdollarVault to enable transferFrom super user privilege
// assign tokenController address to BitdollarCampaign to enable generateTokens to be called by the contract
contract BitdollarToken is Token, TokenController, SafeMath {
string public constant name = "Bitdollar Fund Token";
string public constant symbol = "BTD";
uint8 public constant decimals = 18; // ERC20 standard is uint8 not uint256
string public version = "1.0";
// the maximum number of Bitdollars there may exist is capped at 1 billion tokens
uint256 public constant maximumTokenIssue = 1000000000 * 10**18;
uint256 internal totalSupply_;
mapping (address => uint256) internal balances;
mapping (address => mapping (address => uint256)) internal allowed;
bool internal tradeable = false;
modifier isTradeable {
require(tradeable);
_;
}
function toggleTrading(bool _toggle) external onlyTokenController {
tradeable = _toggle;
}
function totalSupply() public view returns (uint256 total) {
return totalSupply_;
}
function transfer(address _to, uint256 _value) onlyPayloadSize(2) isTradeable public returns (bool success) {
return _transfer(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) onlyPayloadSize(3) isTradeable public returns (bool success) {
// The tokenVault contract can move tokens around at will
if (msg.sender != tokenVault) {
require(allowed[_from][msg.sender] >= _value);
allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _value);
}
return _transfer(_from, _to, _value);
}
function _transfer(address _from, address _to, uint256 _value) internal returns (bool) {
require((_to != address(0)) && (_to != address(this)));
require(balances[_from] >= _value && _value > 0);
balances[_from] = safeSub(balances[_from], _value);
balances[_to] = safeAdd(balances[_to], _value);
emit Transfer(_from, _to, _value);
return true;
}
/*
function transfer(address _to, uint256 _value) onlyPayloadSize(2) isTradeable public returns (bool success) {
require(_to != address(0));
require(balances[msg.sender] >= _value && _value > 0);
balances[msg.sender] = safeSub(balances[msg.sender], _value);
balances[_to] = safeAdd(balances[_to], _value);
Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) onlyPayloadSize(3) isTradeable public returns (bool success) {
require(_to != address(0));
require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0);
balances[_from] = safeSub(balances[_from], _value);
balances[_to] = safeAdd(balances[_to], _value);
allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _value);
Transfer(_from, _to, _value);
return true;
}
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
// To change the approve amount you first have to reduce the addresses'
// allowance to zero by calling 'approve(_spender, 0)' if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
function approve(address _spender, uint256 _value) onlyPayloadSize(2) public returns (bool success) {
require((_value == 0) || (allowed[msg.sender][_spender] == 0));
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function changeApproval(address _spender, uint256 _oldValue, uint256 _newValue) onlyPayloadSize(3) public returns (bool success) {
require(allowed[msg.sender][_spender] == _oldValue);
allowed[msg.sender][_spender] = _newValue;
emit Approval(msg.sender, _spender, _newValue);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
function isTrading() public view returns (bool trading) {
return tradeable;
}
// if ether is sent to this address revert the transaction
function () public payable {
revert();
}
function generateTokens(address _to, uint _amount) public onlyTokenController returns (bool) {
require(safeAdd(totalSupply_, _amount) <= maximumTokenIssue);
totalSupply_ = safeAdd(totalSupply_, _amount);
balances[_to] = safeAdd(balances[_to], _amount);
emit Transfer(address(0), _to, _amount);
return true;
}
}
pragma solidity 0.4.24;
import './BitdollarToken.sol';
import './BitdollarCampaign.sol';
import './SafeMath.sol';
// assign TokenController tokenVault parameter to this contracts address
// has super user privelege to transfer tokens from any account to fundWallet
// deploy BitdollarToken and BitdollarCampaign first and supply their addresses as parameter to this contracts constructor
contract BitdollarVault is SafeMath {
BitdollarToken bitdollarTokenContract;
BitdollarCampaign bitdollarCampaignContract;
//uint256 previousUpdateTime;
// root control
address public fundWallet;
// control of liquidity and limited control of updatePrice
address public controlWallet;
// map participant address to a withdrawal request
mapping (address => Withdrawal) public withdrawals;
struct Withdrawal {
uint256 tokens;
uint256 time; // time for each withdrawal is set to the previousUpdateTime
}
event AddLiquidity(uint256 ethAmount);
event RemoveLiquidity(uint256 ethAmount);
event WithdrawRequest(address indexed participant, uint256 amountTokens);
event Withdraw(address indexed participant, uint256 amountTokens, uint256 etherAmount);
modifier onlyFundWallet {
require(msg.sender == fundWallet);
_;
}
modifier onlyManagingWallets {
require(msg.sender == controlWallet || msg.sender == fundWallet);
_;
}
constructor(address controlWalletInput, address tokenContractInput, address campaignContractInput) public {
controlWallet = controlWalletInput;
bitdollarTokenContract = BitdollarToken(tokenContractInput);
bitdollarCampaignContract = BitdollarCampaign(campaignContractInput);
}
function requestWithdrawal(uint256 amountTokensToWithdraw) external {
//require(block.number > fundingEndBlock);
require(amountTokensToWithdraw > 0);
address participant = msg.sender;
// transferFrom already checks for sufficient balance
//require(_balanceOf(participant) >= amountTokensToWithdraw);
require(withdrawals[participant].tokens == 0); // participant cannot have outstanding withdrawals
//balances[participant] = safeSub(balances[participant], amountTokensToWithdraw);
//uint256 remainingBalance = safeSub(_balanceOf(participant), amountTokensToWithdraw);
uint256 previousUpdateTime = bitdollarCampaignContract.getPreviousUpdateTime();
withdrawals[participant] = Withdrawal({tokens: amountTokensToWithdraw, time: previousUpdateTime});
WithdrawRequest(participant, amountTokensToWithdraw);
}
function withdraw() external {
address participant = msg.sender;
uint256 tokens = withdrawals[participant].tokens;
require(tokens > 0); // participant must have requested a withdrawal
uint256 requestTime = withdrawals[participant].time;
// obtain the next price that was set after the request
// Price storage price = prices[requestTime];
uint256 numerator;
uint256 denominator;
(numerator, denominator) = bitdollarCampaignContract.getPrice(requestTime);
require(numerator > 0); // price must have been set
uint256 withdrawValue = safeMul(tokens, denominator) / numerator;
// if contract ethbal > then send + transfer tokens to fundWallet, otherwise give tokens back
withdrawals[participant].tokens = 0;
if (address(this).balance >= withdrawValue)
enact_withdrawal_greater_equal(participant, withdrawValue, tokens);
else
enact_withdrawal_less(participant, withdrawValue, tokens);
}
function enact_withdrawal_greater_equal(address participant, uint256 withdrawValue, uint256 tokens)
internal
{
assert(address(this).balance >= withdrawValue);
// balances[fundWallet] = safeAdd(balances[fundWallet], tokens);
// will revert if tradeable boolean is false in the token contract
require(bitdollarTokenContract.transferFrom(participant, fundWallet, tokens));
participant.transfer(withdrawValue);
Withdraw(participant, tokens, withdrawValue);
}
function enact_withdrawal_less(address participant, uint256 withdrawValue, uint256 tokens)
internal
{
assert(address(this).balance < withdrawValue);
//balances[participant] = safeAdd(balances[participant], tokens);
Withdraw(participant, tokens, 0); // indicate a failed withdrawal
}
function checkWithdrawValue(uint256 amountTokensToWithdraw) constant public returns (uint256 etherValue) {
require(amountTokensToWithdraw > 0);
require(_balanceOf(msg.sender) >= amountTokensToWithdraw);
uint256 numerator;
uint256 denominator;
(numerator, denominator) = bitdollarCampaignContract.getCurrentPrice();
//is this computation correct?
uint256 withdrawValue = safeMul(amountTokensToWithdraw, denominator) / numerator;
//is this check necessary? it only returns the eth value??
//require(this.balance >= withdrawValue);
return withdrawValue;
}
// allow fundWallet or controlWallet to add ether to contract
function addLiquidity() external onlyManagingWallets payable {
require(msg.value > 0);
AddLiquidity(msg.value);
}
// allow fundWallet to remove ether from contract
function removeLiquidity(uint256 amount) external onlyManagingWallets {
require(amount <= address(this).balance);
fundWallet.transfer(amount);
RemoveLiquidity(amount);
}
function changeFundWallet(address newFundWallet) external onlyFundWallet {
require(newFundWallet != address(0));
fundWallet = newFundWallet;
}
function changeControlWallet(address newControlWallet) external onlyFundWallet {
require(newControlWallet != address(0));
controlWallet = newControlWallet;
}
function _balanceOf(address _addr) internal view returns(uint256) {
return bitdollarTokenContract.balanceOf(_addr);
}
}
pragma solidity 0.4.24;
import './Token.sol';
import './SafeMath.sol';
/**
* @title BTDVesting1Yr
* @dev BTDVesting1Yr is a token holder contract that allows the specified beneficiary
* to claim stored tokens after 3 month intervals
*/
contract BTDVesting1Yr is SafeMath {
address public beneficiary;
uint256 public fundingEndBlock;
bool private initClaim = false; // state tracking variables
uint256 public firstRelease; // vesting times
bool private firstDone = false;
uint256 public secondRelease;
bool private secondDone = false;
uint256 public thirdRelease;
bool private thirdDone = false;
uint256 public fourthRelease;
Token public ERC20Token; // ERC20 basic token contract to hold
enum Stages {
initClaim,
firstRelease,
secondRelease,
thirdRelease,
fourthRelease
}
Stages public stage = Stages.initClaim;
modifier atStage(Stages _stage) {
if(stage == _stage) _;
}
function BTDVesting1Yr(address _beneficiary, address _token, uint256 fundingEndBlockInput) public {
require(_token != address(0));
beneficiary = _beneficiary;
fundingEndBlock = fundingEndBlockInput;
ERC20Token = Token(_token);
}
function changeBeneficiary(address newBeneficiary) external {
require(newBeneficiary != address(0));
require(msg.sender == beneficiary);
beneficiary = newBeneficiary;
}
function updateFundingEndBlock(uint256 newFundingEndBlock) public {
require(msg.sender == beneficiary);
require(block.number < fundingEndBlock);
require(block.number < newFundingEndBlock);
fundingEndBlock = newFundingEndBlock;
}
function checkBalance() constant public returns (uint256 tokenBalance) {
return ERC20Token.balanceOf(this);
}
// in total 15% of BTD tokens will be sent to this contract
// EXPENSE ALLOCATION: 6.0% | TEAM ALLOCATION: 9.0% (vest over 1 years)
// 3.0% - Marketing | initalPayment: 1.8%
// 1% - Security | firstRelease: 1.8%
// 1% - Legal | secondRelease: 1.8%
// 0.5% - Advisors | thirdRelease: 1.8%
// 0.5% - Bounty | fourthRelease: 1.8%
// initial claim is tot expenses + initial team payment
// initial claim is thus (6.0 + 1.8)/15 = 52.0% of BTD tokens sent here
// each other release (for team) is 12.0% of tokens sent here
function claim() external {
require(msg.sender == beneficiary);
require(block.number > fundingEndBlock);
uint256 balance = ERC20Token.balanceOf(this);
// in reverse order so stages changes don't carry within one claim
fourth_release(balance);
third_release(balance);
second_release(balance);
first_release(balance);
init_claim(balance);
}
function nextStage() private {
stage = Stages(uint256(stage) + 1);
}
function init_claim(uint256 balance) private atStage(Stages.initClaim) {
firstRelease = now + 13 weeks; // assign 4 claiming times
secondRelease = firstRelease + 13 weeks;
thirdRelease = secondRelease + 13 weeks;
fourthRelease = thirdRelease + 13 weeks;
uint256 amountToTransfer = safeMul(balance, 52000000000) / 100000000000;
ERC20Token.transfer(beneficiary, amountToTransfer); // now 48.0% tokens left
nextStage();
}
function first_release(uint256 balance) private atStage(Stages.firstRelease) {
require(now > firstRelease);
uint256 amountToTransfer = balance / 4;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 % of team releases
nextStage();
}
function second_release(uint256 balance) private atStage(Stages.secondRelease) {
require(now > secondRelease);
uint256 amountToTransfer = balance / 3;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 % of team releases
nextStage();
}
function third_release(uint256 balance) private atStage(Stages.thirdRelease) {
require(now > thirdRelease);
uint256 amountToTransfer = balance / 2;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 % of team releases
nextStage();
}
function fourth_release(uint256 balance) private atStage(Stages.fourthRelease) {
require(now > fourthRelease);
ERC20Token.transfer(beneficiary, balance); // send remaining 25 % of team releases
}
function claimOtherTokens(address _token) external {
require(msg.sender == beneficiary);
require(_token != address(0));
Token token = Token(_token);
require(token != ERC20Token);
uint256 balance = token.balanceOf(this);
token.transfer(beneficiary, balance);
}
}
pragma solidity 0.4.24;
import './Token.sol';
import './SafeMath.sol';
/**
* @title BTDVesting4Wk
* @dev BTDVesting4Wk is a token holder contract that allows the specified beneficiary
* to claim stored tokens after 1 week intervals
*/
contract BTDVesting4Wk is SafeMath {
address public beneficiary;
uint256 public fundingEndBlock;
bool private initClaim = false; // state tracking variables
uint256 public firstRelease; // vesting times
bool private firstDone = false;
uint256 public secondRelease;
bool private secondDone = false;
uint256 public thirdRelease;
bool private thirdDone = false;
uint256 public fourthRelease;
Token public ERC20Token; // ERC20 basic token contract to hold
enum Stages {
initClaim,
firstRelease,
secondRelease,
thirdRelease,
fourthRelease
}
Stages public stage = Stages.initClaim;
modifier atStage(Stages _stage) {
if(stage == _stage) _;
}
function BTDVesting4Wk(address _beneficiary, address _token, uint256 fundingEndBlockInput) public {
require(_token != address(0));
beneficiary = _beneficiary;
fundingEndBlock = fundingEndBlockInput;
ERC20Token = Token(_token);
}
function changeBeneficiary(address newBeneficiary) external {
require(newBeneficiary != address(0));
require(msg.sender == beneficiary);
beneficiary = newBeneficiary;
}
function updateFundingEndBlock(uint256 newFundingEndBlock) public {
require(msg.sender == beneficiary);
require(block.number < fundingEndBlock);
require(block.number < newFundingEndBlock);
fundingEndBlock = newFundingEndBlock;
}
function checkBalance() constant public returns (uint256 tokenBalance) {
return ERC20Token.balanceOf(this);
}
function claim() external {
require(msg.sender == beneficiary);
require(block.number > fundingEndBlock);
uint256 balance = ERC20Token.balanceOf(this);
// in reverse order so stages changes don't carry within one claim
fourth_release(balance);
third_release(balance);
second_release(balance);
first_release(balance);
init_claim(balance);
}
function nextStage() private {
stage = Stages(uint256(stage) + 1);
}
function init_claim(uint256 balance) private atStage(Stages.initClaim) {
firstRelease = now + 1 weeks; // assign 4 claiming times
secondRelease = firstRelease + 1 weeks;
thirdRelease = secondRelease + 1 weeks;
fourthRelease = thirdRelease + 1 weeks;
uint256 amountToTransfer = safeMul(balance, 20000000000) / 100000000000;
ERC20Token.transfer(beneficiary, amountToTransfer); // now 80.0% tokens left
nextStage();
}
function first_release(uint256 balance) private atStage(Stages.firstRelease) {
require(now > firstRelease);
uint256 amountToTransfer = balance / 4;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 %
nextStage();
}
function second_release(uint256 balance) private atStage(Stages.secondRelease) {
require(now > secondRelease);
uint256 amountToTransfer = balance / 3;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 %
nextStage();
}
function third_release(uint256 balance) private atStage(Stages.thirdRelease) {
require(now > thirdRelease);
uint256 amountToTransfer = balance / 2;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 %
nextStage();
}
function fourth_release(uint256 balance) private atStage(Stages.fourthRelease) {
require(now > fourthRelease);
ERC20Token.transfer(beneficiary, balance); // send remaining 25 %
}
function claimOtherTokens(address _token) external {
require(msg.sender == beneficiary);
require(_token != address(0));
Token token = Token(_token);
require(token != ERC20Token);
uint256 balance = token.balanceOf(this);
token.transfer(beneficiary, balance);
}
}
pragma solidity 0.4.18;
contract Token { // ERC20 standard
function balanceOf(address _owner) constant public returns (uint256 balance);
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
function allowance(address _owner, address _spender) constant public returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract SafeMath {
function safeMul(uint a, uint b) internal pure returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeSub(uint a, uint b) internal pure returns (uint) {
assert(b <= a);
return a - b;
}
function safeAdd(uint a, uint b) internal pure returns (uint) {
uint c = a + b;
assert(c>=a && c>=b);
return c;
}
modifier onlyPayloadSize(uint numWords) {
assert(msg.data.length >= numWords * 32 + 4);
_;
}
}
contract TokenController {
// assign to BitdollarCampaign
address public tokenController;
// assign to BitdollarVault
address public tokenVault;
// root control
address public fundWallet;
function TokenController() public {
fundWallet = msg.sender;
}
modifier onlyTokenController {
require(msg.sender == tokenController);
_;
}
modifier onlyFundWallet {
require(msg.sender == fundWallet);
_;
}
function changeTokenController(address newTokenController, address newTokenVault) external onlyTokenController {
require(newTokenController != address(0) && newTokenVault != address(0));
tokenController = newTokenController;
tokenVault = newTokenVault;
}
}
/**
* @title BTDVesting1Yr
* @dev BTDVesting1Yr is a token holder contract that allows the specified beneficiary
* to claim stored tokens after 3 month intervals
*/
contract BTDVesting1Yr is SafeMath {
address public beneficiary;
uint256 public fundingEndBlock;
bool private initClaim = false; // state tracking variables
uint256 public firstRelease; // vesting times
bool private firstDone = false;
uint256 public secondRelease;
bool private secondDone = false;
uint256 public thirdRelease;
bool private thirdDone = false;
uint256 public fourthRelease;
Token public ERC20Token; // ERC20 basic token contract to hold
enum Stages {
initClaim,
firstRelease,
secondRelease,
thirdRelease,
fourthRelease
}
Stages public stage = Stages.initClaim;
modifier atStage(Stages _stage) {
if(stage == _stage) _;
}
function BTDVesting1Yr(address _beneficiary, address _token, uint256 fundingEndBlockInput) public {
require(_token != address(0));
beneficiary = _beneficiary;
fundingEndBlock = fundingEndBlockInput;
ERC20Token = Token(_token);
}
function changeBeneficiary(address newBeneficiary) external {
require(newBeneficiary != address(0));
require(msg.sender == beneficiary);
beneficiary = newBeneficiary;
}
function updateFundingEndBlock(uint256 newFundingEndBlock) public {
require(msg.sender == beneficiary);
require(block.number < fundingEndBlock);
require(block.number < newFundingEndBlock);
fundingEndBlock = newFundingEndBlock;
}
function checkBalance() constant public returns (uint256 tokenBalance) {
return ERC20Token.balanceOf(this);
}
// in total 15% of BTD tokens will be sent to this contract
// EXPENSE ALLOCATION: 6.0% | TEAM ALLOCATION: 9.0% (vest over 1 years)
// 3.0% - Marketing | initalPayment: 1.8%
// 1% - Security | firstRelease: 1.8%
// 1% - Advisors | secondRelease: 1.8%
// 0.5% - Legal | thirdRelease: 1.8%
// 0.5% - Bounty | fourthRelease: 1.8%
// initial claim is tot expenses + initial team payment
// initial claim is thus (6.0 + 1.8)/15 = 52.0% of BTD tokens sent here
// each other release (for team) is 12.0% of tokens sent here
function claim() external {
require(msg.sender == beneficiary);
require(block.number > fundingEndBlock);
uint256 balance = ERC20Token.balanceOf(this);
// in reverse order so stages changes don't carry within one claim
fourth_release(balance);
third_release(balance);
second_release(balance);
first_release(balance);
init_claim(balance);
}
function nextStage() private {
stage = Stages(uint256(stage) + 1);
}
function init_claim(uint256 balance) private atStage(Stages.initClaim) {
firstRelease = now + 13 weeks; // assign 4 claiming times
secondRelease = firstRelease + 13 weeks;
thirdRelease = secondRelease + 13 weeks;
fourthRelease = thirdRelease + 13 weeks;
uint256 amountToTransfer = safeMul(balance, 52000000000) / 100000000000;
ERC20Token.transfer(beneficiary, amountToTransfer); // now 48.0% tokens left
nextStage();
}
function first_release(uint256 balance) private atStage(Stages.firstRelease) {
require(now > firstRelease);
uint256 amountToTransfer = balance / 4;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 % of team releases
nextStage();
}
function second_release(uint256 balance) private atStage(Stages.secondRelease) {
require(now > secondRelease);
uint256 amountToTransfer = balance / 3;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 % of team releases
nextStage();
}
function third_release(uint256 balance) private atStage(Stages.thirdRelease) {
require(now > thirdRelease);
uint256 amountToTransfer = balance / 2;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 % of team releases
nextStage();
}
function fourth_release(uint256 balance) private atStage(Stages.fourthRelease) {
require(now > fourthRelease);
ERC20Token.transfer(beneficiary, balance); // send remaining 25 % of team releases
}
function claimOtherTokens(address _token) external {
require(msg.sender == beneficiary);
require(_token != address(0));
Token token = Token(_token);
require(token != ERC20Token);
uint256 balance = token.balanceOf(this);
token.transfer(beneficiary, balance);
}
}
/**
* @title BTDVesting4Wk
* @dev BTDVesting4Wk is a token holder contract that allows the specified beneficiary
* to claim stored tokens after 1 week intervals
*/
contract BTDVesting4Wk is SafeMath {
address public beneficiary;
uint256 public fundingEndBlock;
bool private initClaim = false; // state tracking variables
uint256 public firstRelease; // vesting times
bool private firstDone = false;
uint256 public secondRelease;
bool private secondDone = false;
uint256 public thirdRelease;
bool private thirdDone = false;
uint256 public fourthRelease;
Token public ERC20Token; // ERC20 basic token contract to hold
enum Stages {
initClaim,
firstRelease,
secondRelease,
thirdRelease,
fourthRelease
}
Stages public stage = Stages.initClaim;
modifier atStage(Stages _stage) {
if(stage == _stage) _;
}
function BTDVesting4Wk(address _beneficiary, address _token, uint256 fundingEndBlockInput) public {
require(_token != address(0));
beneficiary = _beneficiary;
fundingEndBlock = fundingEndBlockInput;
ERC20Token = Token(_token);
}
function changeBeneficiary(address newBeneficiary) external {
require(newBeneficiary != address(0));
require(msg.sender == beneficiary);
beneficiary = newBeneficiary;
}
function updateFundingEndBlock(uint256 newFundingEndBlock) public {
require(msg.sender == beneficiary);
require(block.number < fundingEndBlock);
require(block.number < newFundingEndBlock);
fundingEndBlock = newFundingEndBlock;
}
function checkBalance() constant public returns (uint256 tokenBalance) {
return ERC20Token.balanceOf(this);
}
function claim() external {
require(msg.sender == beneficiary);
require(block.number > fundingEndBlock);
uint256 balance = ERC20Token.balanceOf(this);
// in reverse order so stages changes don't carry within one claim
fourth_release(balance);
third_release(balance);
second_release(balance);
first_release(balance);
init_claim(balance);
}
function nextStage() private {
stage = Stages(uint256(stage) + 1);
}
function init_claim(uint256 balance) private atStage(Stages.initClaim) {
firstRelease = now + 1 weeks; // assign 4 claiming times
secondRelease = firstRelease + 1 weeks;
thirdRelease = secondRelease + 1 weeks;
fourthRelease = thirdRelease + 1 weeks;
uint256 amountToTransfer = safeMul(balance, 20000000000) / 100000000000;
ERC20Token.transfer(beneficiary, amountToTransfer); // now 80.0% tokens left
nextStage();
}
function first_release(uint256 balance) private atStage(Stages.firstRelease) {
require(now > firstRelease);
uint256 amountToTransfer = balance / 4;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 %
nextStage();
}
function second_release(uint256 balance) private atStage(Stages.secondRelease) {
require(now > secondRelease);
uint256 amountToTransfer = balance / 3;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 %
nextStage();
}
function third_release(uint256 balance) private atStage(Stages.thirdRelease) {
require(now > thirdRelease);
uint256 amountToTransfer = balance / 2;
ERC20Token.transfer(beneficiary, amountToTransfer); // send 25 %
nextStage();
}
function fourth_release(uint256 balance) private atStage(Stages.fourthRelease) {
require(now > fourthRelease);
ERC20Token.transfer(beneficiary, balance); // send remaining 25 %
}
function claimOtherTokens(address _token) external {
require(msg.sender == beneficiary);
require(_token != address(0));
Token token = Token(_token);
require(token != ERC20Token);
uint256 balance = token.balanceOf(this);
token.transfer(beneficiary, balance);
}
}
// assign tokenVault address to BitdollarVault to enable destroyTokens privelege
// assign tokenController address to BitdollarCampaign to enable generateTokens to be called by the contract
contract BitdollarToken is Token, TokenController, SafeMath {
string public constant name = "Bitdollar Fund Token";
string public constant symbol = "BTD";
uint8 public constant decimals = 18; // ERC20 standard is uint8 not uint256
string public version = "1.0";
// the maximum number of Bitdollars there may exist is capped at 1 billion tokens
uint256 public constant maximumTokenIssue = 1000000000 * 10**18;
uint256 internal totalSupply_;
mapping (address => uint256) internal balances;
mapping (address => mapping (address => uint256)) internal allowed;
bool internal tradeable = false;
modifier isTradeable {
require(tradeable);
_;
}
function toggleTrading(bool _toggle) external onlyTokenController {
tradeable = _toggle;
}
function totalSupply() public view returns (uint256 total) {
return totalSupply_;
}
function transfer(address _to, uint256 _value) onlyPayloadSize(2) isTradeable public returns (bool success) {
return _transfer(msg.sender, _to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) onlyPayloadSize(3) isTradeable public returns (bool success) {
if(msg.sender != tokenVault) {
require(allowed[_from][msg.sender] >= _value);
allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _value);
}
return _transfer(_from, _to, _value);
}
function _transfer(address _from, address _to, uint256 _value) internal returns (bool) {
require((_to != address(0)) && (_to != address(this)));
require(balances[_from] >= _value && _value > 0);
balances[_from] = safeSub(balances[_from], _value);
balances[_to] = safeAdd(balances[_to], _value);
Transfer(_from, _to, _value);
return true;
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
// To change the approve amount you first have to reduce the addresses'
// allowance to zero by calling 'approve(_spender, 0)' if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
function approve(address _spender, uint256 _value) onlyPayloadSize(2) public returns (bool success) {
require((_value == 0) || (allowed[msg.sender][_spender] == 0));
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
function changeApproval(address _spender, uint256 _oldValue, uint256 _newValue) onlyPayloadSize(3) public returns (bool success) {
require(allowed[msg.sender][_spender] == _oldValue);
allowed[msg.sender][_spender] = _newValue;
Approval(msg.sender, _spender, _newValue);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowed[_owner][_spender];
}
function isTrading() public view returns (bool trading) {
return tradeable;
}
// if ether is sent to this address revert the transaction
function () public payable {
revert();
}
function generateTokens(address _to, uint _amount) public onlyTokenController returns (bool) {
require(safeAdd(totalSupply_, _amount) <= maximumTokenIssue);
totalSupply_ = safeAdd(totalSupply_, _amount);
balances[_to] = safeAdd(balances[_to], _amount);
Transfer(address(0), _to, _amount);
return true;
}
function destroyTokens(address _from, uint _amount) public onlyFundWallet returns (bool) {
// cannot destroy tokens outside of fundWallet
require(_from == fundWallet);
require(_amount <= balances[_from]);
balances[_from] = safeSub(balances[_from],_amount);
totalSupply_ = safeSub(totalSupply_,_amount);
Transfer(_from, address(0), _amount);
return true;
}
}
// deploy BitdollarToken contract first and pass that address as parameter to this contract's constructor
// deploy BitdollarVault and pass to it the BitdollarToken address and this contract's address as parameters
// finally, assign this contract's address as tokenContoller and the BitdollarVault address as tokenVault in BitdollarToken by invoking
// the changeTokenController function
contract BitdollarCampaign is SafeMath {
BitdollarToken bitdollarTokenContract;
// keeps track of total number of tokens sold throughout all phases
uint256 public totalSold;
// current phase token cap
uint256 public currentPhaseCap;
// tokens sold in current phase
uint256 public currentPhaseTokenSales;
// running total of development allocation accumulated in current phase
uint256 public developmentAllocationRunningTotal;
// current phase development allocation percent (takes 17 digit input for precision)
uint256 public developmentAllocationPercent;
// current phase starting block
uint256 public fundingStartBlock;
// current phase ending block
uint256 public fundingEndBlock;
// current phase minimum purchase threshold
uint256 public minAmount;
// current phase price
Price public currentPrice;
// state variable indicates if active sale phase
bool public icoMode;
// state variable to indicate ico parameters have been entered
bool public icoPrimed;
// amount of tokens unsold during current phase
// fundWallet may add this amount to subsequent phase cap at their discretion
uint256 public tokenCapRollOverToNextPhase;
// vesting fields
BTDVesting1Yr public vestingContract;
bool private vestingSet;
// root control
address public fundWallet;
// control of liquidity and limited control of updatePrice
address public controlWallet;
// time to wait between controlWallet price updates
uint256 public waitTime;
// halted: halt buying due to emergency, tradeable: signal that assets have been acquired
bool public halted;
bool public vestSoldTokens;
// last update timestamp
uint256 public previousUpdateTime;
// maps previousUpdateTime to the next price
mapping (uint256 => Price) public prices;
// maps verified addresses
mapping (address => bool) public whitelist;
// maps list of BTD owners who may skip whitelist and ico minimum requirements
mapping (address => bool) public verified;
mapping (address => address) public vestingAddresses;
// TYPES
struct Price { // tokensPerEth
uint256 numerator;
uint256 denominator;
}
// EVENTS
event Buy(address indexed participant, address indexed beneficiary, uint256 ethValue, uint256 amountTokens);
event AllocatePresale(address indexed participant, uint256 amountTokens);
event Whitelist(address indexed participant);
event PriceUpdate(uint256 numerator, uint256 denominator);
event ICO(uint256 phaseCap, uint256 phaseStart, uint256 phaseEnd);
// enum Phase { Initial, PreSale, Sale, Closed }
// enum Phase { PreSale, Sale, Closed }
// Phase public phase;
// MODIFIERS
//TODO this modifier is not used ///////////////////////////////////////////////////////////////////
// modifier isTradeable { // exempt vestingContract and fundWallet to allow dev allocations
// require(tradeable || msg.sender == fundWallet || msg.sender == vestingContract);
// _;
// }
modifier onlyWhitelist {
require(whitelist[msg.sender]);
_;
}
modifier onlyFundWallet {
require(msg.sender == fundWallet);
_;
}
modifier onlyManagingWallets {
require(msg.sender == controlWallet || msg.sender == fundWallet);
_;
}
modifier only_if_controlWallet {
if (msg.sender == controlWallet)
_;
}
modifier require_waited {
require(safeSub(now, waitTime) >= previousUpdateTime);
_;
}
modifier only_if_increase (uint256 newNumerator) {
if (newNumerator > currentPrice.numerator)
_;
}
modifier whileSaleActive {
require(block.number >= fundingStartBlock && block.number < fundingEndBlock && icoMode);
_;
}
// CONSTRUCTOR
function BitdollarCampaign( address controlWalletInput,
address tokenContractInput,
uint256 priceNumeratorInput)
public {
require(controlWalletInput != address(0) && tokenContractInput != address(0) && priceNumeratorInput > 0);
controlWallet = controlWalletInput;
bitdollarTokenContract = BitdollarToken(tokenContractInput);
currentPrice = Price(priceNumeratorInput, 1000); // 1 token = 1 usd at ICO start
previousUpdateTime = now;
fundWallet = msg.sender;
//whitelist[fundWallet] = true;
//whitelist[controlWallet] = true;
waitTime = 5 hours;
vestingSet = false;
halted = false;
icoMode = false;
// phase = Phase.Initial;
// phase = Phase.Closed;
}
// METHODS
function setVestingContract(uint256 phaseEndBlock) public onlyFundWallet returns (address) {
vestingContract = new BTDVesting1Yr(fundWallet, address(bitdollarTokenContract), phaseEndBlock);
//whitelist[vestingContract] = true; any reason for vestingContract address to purchase more tokens?
vestingSet = true;
}
// // METHODS
// // TODO set three vesting contracts
// function setVestingContract(address vestingContractInput) external onlyFundWallet {
// require(vestingContractInput != address(0));
// vestingContract = vestingContractInput;
// //whitelist[vestingContract] = true; any reason for vestingContract address to purchase more tokens?
// vestingSet = true;
// }
// allows controlWallet to update the price within a time contstraint, allows fundWallet complete control
function updatePrice(uint256 newNumerator) external onlyManagingWallets {
require(newNumerator > 0);
require_limited_change(newNumerator);
// either controlWallet command is compliant or transaction came from fundWallet
currentPrice.numerator = newNumerator;
// maps time to new Price (if not during ICO)
prices[previousUpdateTime] = currentPrice;
previousUpdateTime = now;
PriceUpdate(newNumerator, currentPrice.denominator);
}
function require_limited_change (uint256 newNumerator)
private
only_if_controlWallet
require_waited
only_if_increase(newNumerator)
view
{
uint256 percentage_diff = 0;
percentage_diff = safeMul(newNumerator, 100) / currentPrice.numerator;
percentage_diff = safeSub(percentage_diff, 100);
// controlWallet can only increase price by max 20% and only every waitTime
require(percentage_diff <= 20);
}
function updatePriceDenominator(uint256 newDenominator) external onlyFundWallet {
require(!icoMode);
//require(block.number > fundingEndBlock);
require(newDenominator > 0);
currentPrice.denominator = newDenominator;
// maps time to new Price
prices[previousUpdateTime] = currentPrice;
previousUpdateTime = now;
PriceUpdate(currentPrice.numerator, newDenominator);
}
function allocateTokens(address participant, uint256 amountTokens) internal {
//require(vestingSet);
// 15% of total allocated for PR, Marketing, Team, Advisors
// uint256 devAllocation = safeMul(amountTokens, 17647058823529400) / 100000000000000000;
uint256 devAllocation = safeMul(amountTokens, developmentAllocationPercent) / 100000000000000000;
// check that token cap is not exceeded
uint256 newTokens = safeAdd(amountTokens, devAllocation);
require(safeAdd(currentPhaseTokenSales, newTokens) <= currentPhaseCap);
//require(safeAdd(tokenSold, newTokens) <= tokenCap);
// increase token supply, assign tokens to participant
currentPhaseTokenSales = safeAdd(currentPhaseTokenSales, newTokens);
totalSold = safeAdd(totalSold, newTokens);
//tokenSold = safeAdd(tokenSold, newTokens);
developmentAllocationRunningTotal = safeAdd(developmentAllocationRunningTotal, devAllocation);
if(!vestSoldTokens) {
require(bitdollarTokenContract.generateTokens(participant, amountTokens));
} else {
BTDVesting4Wk vestment = new BTDVesting4Wk(participant, address(bitdollarTokenContract), fundingEndBlock);
require(bitdollarTokenContract.generateTokens(address(vestment), amountTokens));
// WILL BE OVERWRITTEN IF PARTICIPANT BUYS AGAIN
vestingAddresses[participant] = address(vestment);
}
verified[participant] = true;
//balances[participant] = safeAdd(balances[participant], amountTokens);
//balances[vestingContract] = safeAdd(balances[vestingContract], developmentAllocation);
}
function allocatePresaleTokens(address participant, uint amountTokens) external onlyFundWallet whileSaleActive {
//require(block.number < fundingEndBlock);
require(participant != address(0) && amountTokens > 0);
whitelist[participant] = true; // automatically whitelist accepted presale
allocateTokens(participant, amountTokens);
Whitelist(participant);
AllocatePresale(participant, amountTokens);
}
function verifyParticipant(address participant) external onlyManagingWallets {
require(participant != address(0));
whitelist[participant] = true;
Whitelist(participant);
}
function getMyVestingContractAddress() public view returns (address) {
return vestingAddresses[msg.sender];
}
function getVestingAddresses(address _owner) public view onlyFundWallet returns (address) {
return vestingAddresses[_owner];
}
// fallback function
function() external payable whileSaleActive onlyWhitelist {
// TODO is this check necessary? //////////////////////////////////////
// require(tx.origin == msg.sender);
buy(msg.sender);
}
function buy(address msgsender) public payable whileSaleActive onlyWhitelist {
require(!halted);
// if investor is already ownder of BTD - they will have been previously verified and whitelisted
if(verified[msgsender] == true) {
// no minimum requirements for tokenHolders
buyTo(msgsender);
} else {
// new investor must meet current rounds minimum to buy BTD at the current round price
require(msg.value >= minAmount);
buyTo(msgsender);
}
// if presale phase
// if(phase == Phase.PreSale) {
// // must be whitelisted participant
// if(whitelist[msgsender]) {
// return buyTo(msgsender);
// // else check if minimum amount in ether is supplied
// } else if (msg.value > minAmount) {
// // add them to whitelist
// whitelist[msgsender] = true;
// Whitelist(msgsender);
// return buyTo(msgsender);
// }
// }
// else
// require(msg.value > minAmount);
// return buyTo(msgsender);
}
function buyTo(address participant) internal returns (bool) {
uint256 icoDenominator = icoDenominatorPrice();
uint256 tokensToBuy = safeMul(msg.value, currentPrice.numerator) / icoDenominator;
allocateTokens(participant, tokensToBuy);
// send ether to fundWallet
fundWallet.transfer(msg.value);
Buy(msg.sender, participant, msg.value, tokensToBuy);
}
// time based on blocknumbers, assuming a blocktime of 30s
function icoDenominatorPrice() public constant returns (uint256) {
uint256 icoDuration = safeSub(block.number, fundingStartBlock);
uint256 denominator;
if (icoDuration < 2880) { // #blocks = 24*60*60/30 = 2880
return currentPrice.denominator;
} else if (icoDuration < 80640 ) { // #blocks = 4*7*24*60*60/30 = 80640
denominator = safeMul(currentPrice.denominator, 105) / 100;
return denominator;
} else {
denominator = safeMul(currentPrice.denominator, 110) / 100;
return denominator;
}
}
function changeFundWallet(address newFundWallet) external onlyFundWallet {
require(newFundWallet != address(0));
fundWallet = newFundWallet;
}
function changeControlWallet(address newControlWallet) external onlyFundWallet {
require(newControlWallet != address(0));
controlWallet = newControlWallet;
}
function changeWaitTime(uint256 newWaitTime) external onlyFundWallet {
waitTime = newWaitTime;
}
function updateFundingStartBlock(uint256 newFundingStartBlock) external onlyFundWallet {
require(block.number < fundingStartBlock);
require(block.number < newFundingStartBlock);
require(newFundingStartBlock < fundingEndBlock); // sanity check
fundingStartBlock = newFundingStartBlock;
}
function updateFundingEndBlock(uint256 newFundingEndBlock) external onlyFundWallet {
require(block.number < fundingEndBlock);
require(block.number < newFundingEndBlock);
require(fundingStartBlock < newFundingEndBlock); // sanity check
fundingEndBlock = newFundingEndBlock;
}
// update minimum amount for investment
// @param newMinAmount the units in ether; eg input 10 for a 10 ETH minimum
function updateMinimumEtherAmount(uint256 newMinAmount) external onlyFundWallet {
//require(!icoMode);
minAmount = newMinAmount * 1 ether;
}
// update developer percentage allocation
// @param newDevAllocationPercentage takes a 17 digit precision input
function updateDevAllocationPercentage(uint256 newDevAllocationPercentage) external onlyFundWallet {
require(!icoMode);
developmentAllocationPercent = newDevAllocationPercentage;
}
// update currentPhaseCap
// @param newCurrentPhaseCap is expected to be between 100 000 000 and 400 000 000; will be converted internally
function updateCurrentPhaseCap(uint256 newCurrentPhaseCap) external onlyFundWallet {
require(!icoMode);
currentPhaseCap = newCurrentPhaseCap * 10**18;
}
// internal function to select phase state
// @param presale a boolean to indicate if presale, if false will activate Sale phase state
// function setPhase(bool presale) internal {
// // // cannot change if Initial Phase
// // if(phase == Phase.Initial) {
// // return;
// // } else if(presale) {
// // phase = Phase.PreSale;
// // } else {
// // phase = Phase.Sale;
// // }
// if(presale) {
// phase = Phase.PreSale;
// } else {
// phase = Phase.Sale;
// }
// }
// update phase state
// only allows switching from PreSale to Sale and vice versa
// function updatePhase() external onlyFundWallet {
// if(phase == Phase.PreSale) {
// phase = Phase.Sale;
// } else if (phase == Phase.Sale) {
// phase = Phase.PreSale;
// }
// }
function halt() external onlyFundWallet {
halted = true;
}
function unhalt() external onlyFundWallet {
halted = false;
}
// enables trading, withdrawals and token transfers are allowed in this state
function enableTrading() external onlyFundWallet {
bitdollarTokenContract.toggleTrading(true);
}
// disables token trading, cannot make withdrawals from BitdollarVault or transfer tokens between accounts in this state
function disableTrading() external onlyFundWallet {
bitdollarTokenContract.toggleTrading(false);
}
function claimTokens(address _token) external onlyFundWallet {
require(_token != address(0));
Token token = Token(_token);
uint256 balance = token.balanceOf(this);
token.transfer(fundWallet, balance);
}
function _balanceOf(address _addr) internal view returns (uint256) {
return bitdollarTokenContract.balanceOf(_addr);
}
function getPrice(uint256 timestamp) external view returns (uint256, uint256) {
return (prices[timestamp].numerator, prices[timestamp].denominator);
}
function getCurrentPrice() external view returns (uint256, uint256) {
return (currentPrice.numerator, currentPrice.denominator);
}
function getPreviousUpdateTime() external view returns (uint256) {
return previousUpdateTime;
}
function setupParameters(uint256 startBlockInput,
uint256 endBlockInput,
uint256 minAmountInput, // in wei
uint256 devPercentInput, // takes 17 digit precision input
uint256 phaseCapInput, // cap for the current phase - must multiply coin count by 10**18
bool vestedRelease,
bool primeICO) // set true if there is confidence in paramaters supplied - ready to activate
external onlyFundWallet {
// must not be in active ico
require(!icoMode);
// specified blocks must be in the future and have valid duration
require(block.number < startBlockInput && startBlockInput < endBlockInput);
// prices must have been previously set - if not updated the new phase will carry the same price as the previous phase
// fundWallet must invoke updatePrice and updatePriceDenominator externally to change prices
// set to current ether equivalent of $100000 minimum to qualify for presale purchase
// set to an arbitrary minimum eg 0.01 ether during normal sale to prevent spam calls from congesting the contract
require(minAmountInput > 0);
minAmount = minAmountInput;
// reset running total
developmentAllocationRunningTotal = 0;
developmentAllocationPercent = devPercentInput;
// reset current token sales count
currentPhaseTokenSales = 0;
currentPhaseCap = phaseCapInput;
// crowdsale parameters
fundingStartBlock = startBlockInput;
fundingEndBlock = endBlockInput;
vestSoldTokens = vestedRelease;
setVestingContract(endBlockInput);
// setPhase(isPresale);
// indicate ico parameters are primed
icoPrimed = primeICO;
}
// activates ico to start accepting ether
function activateICO() external onlyFundWallet {
require(!icoMode && icoPrimed);
icoPrimed = false;
icoMode = true;
}
// closes current ico and generates dev allocation tokens
function finalizeCurrentICO() external onlyFundWallet {
require(icoMode);
require(block.number > fundingEndBlock);
//balances[vestingContract] = safeAdd(balances[vestingContract], developmentAllocation);
require(vestingSet);
// generate allocation tokens accumulated throughout the sale
require(bitdollarTokenContract.generateTokens(address(vestingContract), developmentAllocationRunningTotal));
icoMode = false;
tokenCapRollOverToNextPhase = safeSub(currentPhaseCap, currentPhaseTokenSales);
}
}
// assign TokenController tokenVault parameter to this contracts address
// has super user privelege to transfer tokens from any account to fundWallet
// deploy BitdollarToken and BitdollarCampaign first and supply their addresses as parameter to this contracts constructor
contract BitdollarVault is SafeMath {
BitdollarToken bitdollarTokenContract;
BitdollarCampaign bitdollarCampaignContract;
//uint256 previousUpdateTime;
// root control
address public fundWallet;
// control of liquidity and limited control of updatePrice
address public controlWallet;
// map participant address to a withdrawal request
mapping (address => Withdrawal) public withdrawals;
struct Withdrawal {
uint256 tokens;
uint256 time; // time for each withdrawal is set to the previousUpdateTime
}
event AddLiquidity(uint256 ethAmount);
event RemoveLiquidity(uint256 ethAmount);
event WithdrawRequest(address indexed participant, uint256 amountTokens);
event Withdraw(address indexed participant, uint256 amountTokens, uint256 etherAmount);
modifier onlyFundWallet {
require(msg.sender == fundWallet);
_;
}
modifier onlyManagingWallets {
require(msg.sender == controlWallet || msg.sender == fundWallet);
_;
}
function BitdollarVault(address controlWalletInput, address tokenContractInput, address campaignContractInput) public {
controlWallet = controlWalletInput;
bitdollarTokenContract = BitdollarToken(tokenContractInput);
bitdollarCampaignContract = BitdollarCampaign(campaignContractInput);
fundWallet = msg.sender;
}
function requestWithdrawal(uint256 amountTokensToWithdraw) external {
//require(block.number > fundingEndBlock);
require(amountTokensToWithdraw > 0);
address participant = msg.sender;
require(_balanceOf(participant) >= amountTokensToWithdraw);
require(withdrawals[participant].tokens == 0); // participant cannot have outstanding withdrawals
//balances[participant] = safeSub(balances[participant], amountTokensToWithdraw);
//uint256 remainingBalance = safeSub(_balanceOf(participant), amountTokensToWithdraw);
uint256 previousUpdateTime = bitdollarCampaignContract.getPreviousUpdateTime();
withdrawals[participant] = Withdrawal({tokens: amountTokensToWithdraw, time: previousUpdateTime});
WithdrawRequest(participant, amountTokensToWithdraw);
}
function withdraw() external {
address participant = msg.sender;
uint256 tokens = withdrawals[participant].tokens;
require(tokens > 0); // participant must have requested a withdrawal
uint256 requestTime = withdrawals[participant].time;
// obtain the next price that was set after the request
// Price storage price = prices[requestTime];
uint256 numerator;
uint256 denominator;
(numerator, denominator) = bitdollarCampaignContract.getPrice(requestTime);
require(numerator > 0); // price must have been set
uint256 withdrawValue = safeMul(tokens, denominator) / numerator;
// if contract ethbal > then send + transfer tokens to fundWallet, otherwise give tokens back
withdrawals[participant].tokens = 0;
if (this.balance >= withdrawValue)
enact_withdrawal_greater_equal(participant, withdrawValue, tokens);
else
enact_withdrawal_less(participant, withdrawValue, tokens);
}
function enact_withdrawal_greater_equal(address participant, uint256 withdrawValue, uint256 tokens)
internal
{
assert(this.balance >= withdrawValue);
// balances[fundWallet] = safeAdd(balances[fundWallet], tokens);
// will revert if tradeable boolean is false in the token contract
// require(bitdollarTokenContract.destroyTokens(participant,tokens));
require(bitdollarTokenContract.transferFrom(participant, fundWallet, tokens));
participant.transfer(withdrawValue);
Withdraw(participant, tokens, withdrawValue);
}
function enact_withdrawal_less(address participant, uint256 withdrawValue, uint256 tokens)
internal
{
assert(this.balance < withdrawValue);
//balances[participant] = safeAdd(balances[participant], tokens);
Withdraw(participant, tokens, 0); // indicate a failed withdrawal
}
function checkWithdrawValue(uint256 amountTokensToWithdraw) constant public returns (uint256 etherValue) {
require(amountTokensToWithdraw > 0);
require(_balanceOf(msg.sender) >= amountTokensToWithdraw);
uint256 numerator;
uint256 denominator;
(numerator, denominator) = bitdollarCampaignContract.getCurrentPrice();
//is this computation correct?
uint256 withdrawValue = safeMul(amountTokensToWithdraw, denominator) / numerator;
//is this check necessary? it only returns the eth value??
//require(this.balance >= withdrawValue);
return withdrawValue;
}
// allow fundWallet or controlWallet to add ether to contract
function addLiquidity() external onlyManagingWallets payable {
require(msg.value > 0);
AddLiquidity(msg.value);
}
// allow fundWallet to remove ether from contract
function removeLiquidity(uint256 amount) external onlyManagingWallets {
require(amount <= this.balance);
fundWallet.transfer(amount);
RemoveLiquidity(amount);
}
function changeFundWallet(address newFundWallet) external onlyFundWallet {
require(newFundWallet != address(0));
fundWallet = newFundWallet;
}
function changeControlWallet(address newControlWallet) external onlyFundWallet {
require(newControlWallet != address(0));
controlWallet = newControlWallet;
}
function _balanceOf(address _addr) internal view returns (uint256) {
return bitdollarTokenContract.balanceOf(_addr);
}
}
pragma solidity 0.4.24;
contract SafeMath {
function safeMul(uint a, uint b) internal pure returns (uint) {
uint c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function safeSub(uint a, uint b) internal pure returns (uint) {
assert(b <= a);
return a - b;
}
function safeAdd(uint a, uint b) internal pure returns (uint) {
uint c = a + b;
assert(c>=a && c>=b);
return c;
}
modifier onlyPayloadSize(uint numWords) {
assert(msg.data.length >= numWords * 32 + 4);
_;
}
}
pragma solidity 0.4.24;
contract Token { // ERC20 standard
function balanceOf(address _owner) constant public returns (uint256 balance);
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
function allowance(address _owner, address _spender) constant public returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
pragma solidity 0.4.24;
contract TokenController {
// assign to BitdollarCampaign
address public tokenController;
// assign to BitdollarVault
address public tokenVault;
constructor() public {
tokenController = msg.sender;
}
modifier onlyTokenController {
require(msg.sender == tokenController);
_;
}
function changeTokenController(address newTokenController, address newTokenVault) external onlyTokenController {
require(newTokenController != address(0) && newTokenVault != address(0));
tokenController = newTokenController;
tokenVault = newTokenVault;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment