Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- contract ManagedAccountInterface {
- // The only address with permission to withdraw from this account
- address public owner;
- // If true, only the owner of the account can receive ether from it
- bool public payOwnerOnly;
- // The sum of ether (in wei) which has been sent to this contract
- uint public accumulatedInput;
- /// @notice Sends `_amount` of wei to _recipient
- /// @param _amount The amount of wei to send to `_recipient`
- /// @param _recipient The address to receive `_amount` of wei
- /// @return True if the send completed
- function payOut(address _recipient, uint _amount) returns (bool);
- event PayOut(address indexed _recipient, uint _amount);
- }
- contract ManagedAccount is ManagedAccountInterface{
- // The constructor sets the owner of the account
- function ManagedAccount(address _owner, bool _payOwnerOnly) {
- owner = _owner;
- payOwnerOnly = _payOwnerOnly;
- }
- // When the contract receives a transaction without data this is called.
- // It counts the amount of ether it receives and stores it in
- // accumulatedInput.
- function() {
- accumulatedInput += msg.value;
- }
- function payOut(address _recipient, uint _amount) returns (bool) {
- if (msg.sender != owner || msg.value > 0 || (payOwnerOnly && _recipient != owner))
- throw;
- if (_recipient.call.value(_amount)()) {
- PayOut(_recipient, _amount);
- return true;
- } else {
- return false;
- }
- }
- }
- contract TokenInterface {
- mapping (address => uint256) balances;
- mapping (address => mapping (address => uint256)) allowed;
- /// Total amount of tokens
- uint256 public totalSupply;
- /// @param _owner The address from which the balance will be retrieved
- /// @return The balance
- function balanceOf(address _owner) constant returns (uint256 balance);
- /// @notice Send `_amount` tokens to `_to` from `msg.sender`
- /// @param _to The address of the recipient
- /// @param _amount The amount of tokens to be transferred
- /// @return Whether the transfer was successful or not
- function transfer(address _to, uint256 _amount) returns (bool success);
- /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
- /// is approved by `_from`
- /// @param _from The address of the origin of the transfer
- /// @param _to The address of the recipient
- /// @param _amount The amount of tokens to be transferred
- /// @return Whether the transfer was successful or not
- function transferFrom(address _from, address _to, uint256 _amount) returns (bool success);
- /// @notice `msg.sender` approves `_spender` to spend `_amount` tokens on
- /// its behalf
- /// @param _spender The address of the account able to transfer the tokens
- /// @param _amount The amount of tokens to be approved for transfer
- /// @return Whether the approval was successful or not
- function approve(address _spender, uint256 _amount) returns (bool success);
- /// @param _owner The address of the account owning tokens
- /// @param _spender The address of the account able to transfer the tokens
- /// @return Amount of remaining tokens of _owner that _spender is allowed
- /// to spend
- function allowance(
- address _owner,
- address _spender
- ) constant returns (uint256 remaining);
- event Transfer(address indexed _from, address indexed _to, uint256 _amount);
- event Approval(
- address indexed _owner,
- address indexed _spender,
- uint256 _amount
- );
- }
- contract Token is TokenInterface {
- // Protects users by preventing the execution of method calls that
- // inadvertently also transferred ether
- modifier noEther() {if (msg.value > 0) throw; _}
- function balanceOf(address _owner) constant returns (uint256 balance) {
- return balances[_owner];
- }
- function transfer(address _to, uint256 _amount) noEther returns (bool success) {
- if (balances[msg.sender] >= _amount && _amount > 0) {
- balances[msg.sender] -= _amount;
- balances[_to] += _amount;
- Transfer(msg.sender, _to, _amount);
- return true;
- } else {
- return false;
- }
- }
- function transferFrom(
- address _from,
- address _to,
- uint256 _amount
- ) noEther returns (bool success) {
- if (balances[_from] >= _amount
- && allowed[_from][msg.sender] >= _amount
- && _amount > 0) {
- balances[_to] += _amount;
- balances[_from] -= _amount;
- allowed[_from][msg.sender] -= _amount;
- Transfer(_from, _to, _amount);
- return true;
- } else {
- return false;
- }
- }
- function approve(address _spender, uint256 _amount) returns (bool success) {
- allowed[msg.sender][_spender] = _amount;
- Approval(msg.sender, _spender, _amount);
- return true;
- }
- function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
- return allowed[_owner][_spender];
- }
- }
- contract TokenCreationInterface {
- // End of token creation, in Unix time
- uint public closingTime;
- // Minimum fueling goal of the token creation, denominated in tokens to
- // be created
- uint public minTokensToCreate;
- // True if the DAO reached its minimum fueling goal, false otherwise
- bool public isFueled;
- // For DAO splits - if privateCreation is 0, then it is a public token
- // creation, otherwise only the address stored in privateCreation is
- // allowed to create tokens
- address public privateCreation;
- // hold extra ether which has been sent after the DAO token
- // creation rate has increased
- ManagedAccount public extraBalance;
- // tracks the amount of wei given from each contributor (used for refund)
- mapping (address => uint256) weiGiven;
- /// @dev Constructor setting the minimum fueling goal and the
- /// end of the Token Creation
- /// @param _minTokensToCreate Minimum fueling goal in number of
- /// Tokens to be created
- /// @param _closingTime Date (in Unix time) of the end of the Token Creation
- /// @param _privateCreation Zero means that the creation is public. A
- /// non-zero address represents the only address that can create Tokens
- /// (the address can also create Tokens on behalf of other accounts)
- // This is the constructor: it can not be overloaded so it is commented out
- // function TokenCreation(
- // uint _minTokensTocreate,
- // uint _closingTime,
- // address _privateCreation
- // );
- /// @notice Create Token with `_tokenHolder` as the initial owner of the Token
- /// @param _tokenHolder The address of the Tokens's recipient
- /// @return Whether the token creation was successful
- function createTokenProxy(address _tokenHolder) returns (bool success);
- /// @notice Refund `msg.sender` in the case the Token Creation did
- /// not reach its minimum fueling goal
- function refund();
- /// @return The divisor used to calculate the token creation rate during
- /// the creation phase
- function divisor() constant returns (uint divisor);
- event FuelingToDate(uint value);
- event CreatedToken(address indexed to, uint amount);
- event Refund(address indexed to, uint value);
- }
- contract TokenCreation is TokenCreationInterface, Token {
- function TokenCreation(
- uint _minTokensToCreate,
- uint _closingTime,
- address _privateCreation) {
- closingTime = _closingTime;
- minTokensToCreate = _minTokensToCreate;
- privateCreation = _privateCreation;
- extraBalance = new ManagedAccount(address(this), true);
- }
- function createTokenProxy(address _tokenHolder) returns (bool success) {
- if (now < closingTime && msg.value > 0
- && (privateCreation == 0 || privateCreation == msg.sender)) {
- uint token = (msg.value * 20) / divisor();
- extraBalance.call.value(msg.value - token)();
- balances[_tokenHolder] += token;
- totalSupply += token;
- weiGiven[_tokenHolder] += msg.value;
- CreatedToken(_tokenHolder, token);
- if (totalSupply >= minTokensToCreate && !isFueled) {
- isFueled = true;
- FuelingToDate(totalSupply);
- }
- return true;
- }
- throw;
- }
- function refund() noEther {
- if (now > closingTime && !isFueled) {
- // Get extraBalance - will only succeed when called for the first time
- if (extraBalance.balance >= extraBalance.accumulatedInput())
- extraBalance.payOut(address(this), extraBalance.accumulatedInput());
- // Execute refund
- if (msg.sender.call.value(weiGiven[msg.sender])()) {
- Refund(msg.sender, weiGiven[msg.sender]);
- totalSupply -= balances[msg.sender];
- balances[msg.sender] = 0;
- weiGiven[msg.sender] = 0;
- }
- }
- }
- function divisor() constant returns (uint divisor) {
- // The number of (base unit) tokens per wei is calculated
- // as `msg.value` * 20 / `divisor`
- // The fueling period starts with a 1:1 ratio
- if (closingTime - 2 weeks > now) {
- return 20;
- // Followed by 10 days with a daily creation rate increase of 5%
- } else if (closingTime - 4 days > now) {
- return (20 + (now - (closingTime - 2 weeks)) / (1 days));
- // The last 4 days there is a constant creation rate ratio of 1:1.5
- } else {
- return 30;
- }
- }
- }
- contract DAOInterface {
- // The amount of days for which people who try to participate in the
- // creation by calling the fallback function will still get their ether back
- uint constant creationGracePeriod = 40 days;
- // The minimum debate period that a generic proposal can have
- uint constant minProposalDebatePeriod = 2 weeks;
- // The minimum debate period that a split proposal can have
- uint constant minSplitDebatePeriod = 1 weeks;
- // Period of days inside which it's possible to execute a DAO split
- uint constant splitExecutionPeriod = 27 days;
- // Period of time after which the minimum Quorum is halved
- uint constant quorumHalvingPeriod = 25 weeks;
- // Period after which a proposal is closed
- // (used in the case `executeProposal` fails because it throws)
- uint constant executeProposalPeriod = 10 days;
- // Denotes the maximum proposal deposit that can be given. It is given as
- // a fraction of total Ether spent plus balance of the DAO
- uint constant maxDepositDivisor = 100;
- // Proposals to spend the DAO's ether or to choose a new Curator
- Proposal[] public proposals;
- // The quorum needed for each proposal is partially calculated by
- // totalSupply / minQuorumDivisor
- uint public minQuorumDivisor;
- // The unix time of the last time quorum was reached on a proposal
- uint public lastTimeMinQuorumMet;
- // Address of the curator
- address public curator;
- // The whitelist: List of addresses the DAO is allowed to send ether to
- mapping (address => bool) public allowedRecipients;
- // Tracks the addresses that own Reward Tokens. Those addresses can only be
- // DAOs that have split from the original DAO. Conceptually, Reward Tokens
- // represent the proportion of the rewards that the DAO has the right to
- // receive. These Reward Tokens are generated when the DAO spends ether.
- mapping (address => uint) public rewardToken;
- // Total supply of rewardToken
- uint public totalRewardToken;
- // The account used to manage the rewards which are to be distributed to the
- // DAO Token Holders of this DAO
- ManagedAccount public rewardAccount;
- // The account used to manage the rewards which are to be distributed to
- // any DAO that holds Reward Tokens
- ManagedAccount public DAOrewardAccount;
- // Amount of rewards (in wei) already paid out to a certain DAO
- mapping (address => uint) public DAOpaidOut;
- // Amount of rewards (in wei) already paid out to a certain address
- mapping (address => uint) public paidOut;
- // Map of addresses blocked during a vote (not allowed to transfer DAO
- // tokens). The address points to the proposal ID.
- mapping (address => uint) public blocked;
- // The minimum deposit (in wei) required to submit any proposal that is not
- // requesting a new Curator (no deposit is required for splits)
- uint public proposalDeposit;
- // the accumulated sum of all current proposal deposits
- uint sumOfProposalDeposits;
- // Contract that is able to create a new DAO (with the same code as
- // this one), used for splits
- DAO_Creator public daoCreator;
- // A proposal with `newCurator == false` represents a transaction
- // to be issued by this DAO
- // A proposal with `newCurator == true` represents a DAO split
- struct Proposal {
- // The address where the `amount` will go to if the proposal is accepted
- // or if `newCurator` is true, the proposed Curator of
- // the new DAO).
- address recipient;
- // The amount to transfer to `recipient` if the proposal is accepted.
- uint amount;
- // A plain text description of the proposal
- string description;
- // A unix timestamp, denoting the end of the voting period
- uint votingDeadline;
- // True if the proposal's votes have yet to be counted, otherwise False
- bool open;
- // True if quorum has been reached, the votes have been counted, and
- // the majority said yes
- bool proposalPassed;
- // A hash to check validity of a proposal
- bytes32 proposalHash;
- // Deposit in wei the creator added when submitting their proposal. It
- // is taken from the msg.value of a newProposal call.
- uint proposalDeposit;
- // True if this proposal is to assign a new Curator
- bool newCurator;
- // Data needed for splitting the DAO
- SplitData[] splitData;
- // Number of Tokens in favor of the proposal
- uint yea;
- // Number of Tokens opposed to the proposal
- uint nay;
- // Simple mapping to check if a shareholder has voted for it
- mapping (address => bool) votedYes;
- // Simple mapping to check if a shareholder has voted against it
- mapping (address => bool) votedNo;
- // Address of the shareholder who created the proposal
- address creator;
- }
- // Used only in the case of a newCurator proposal.
- struct SplitData {
- // The balance of the current DAO minus the deposit at the time of split
- uint splitBalance;
- // The total amount of DAO Tokens in existence at the time of split.
- uint totalSupply;
- // Amount of Reward Tokens owned by the DAO at the time of split.
- uint rewardToken;
- // The new DAO contract created at the time of split.
- DAO newDAO;
- }
- // Used to restrict access to certain functions to only DAO Token Holders
- modifier onlyTokenholders {}
- /// @dev Constructor setting the Curator and the address
- /// for the contract able to create another DAO as well as the parameters
- /// for the DAO Token Creation
- /// @param _curator The Curator
- /// @param _daoCreator The contract able to (re)create this DAO
- /// @param _proposalDeposit The deposit to be paid for a regular proposal
- /// @param _minTokensToCreate Minimum required wei-equivalent tokens
- /// to be created for a successful DAO Token Creation
- /// @param _closingTime Date (in Unix time) of the end of the DAO Token Creation
- /// @param _privateCreation If zero the DAO Token Creation is open to public, a
- /// non-zero address means that the DAO Token Creation is only for the address
- // This is the constructor: it can not be overloaded so it is commented out
- // function DAO(
- // address _curator,
- // DAO_Creator _daoCreator,
- // uint _proposalDeposit,
- // uint _minTokensToCreate,
- // uint _closingTime,
- // address _privateCreation
- // );
- /// @notice Create Token with `msg.sender` as the beneficiary
- /// @return Whether the token creation was successful
- function () returns (bool success);
- /// @dev This function is used to send ether back
- /// to the DAO, it can also be used to receive payments that should not be
- /// counted as rewards (donations, grants, etc.)
- /// @return Whether the DAO received the ether successfully
- function receiveEther() returns(bool);
- /// @notice `msg.sender` creates a proposal to send `_amount` Wei to
- /// `_recipient` with the transaction data `_transactionData`. If
- /// `_newCurator` is true, then this is a proposal that splits the
- /// DAO and sets `_recipient` as the new DAO's Curator.
- /// @param _recipient Address of the recipient of the proposed transaction
- /// @param _amount Amount of wei to be sent with the proposed transaction
- /// @param _description String describing the proposal
- /// @param _transactionData Data of the proposed transaction
- /// @param _debatingPeriod Time used for debating a proposal, at least 2
- /// weeks for a regular proposal, 10 days for new Curator proposal
- /// @param _newCurator Bool defining whether this proposal is about
- /// a new Curator or not
- /// @return The proposal ID. Needed for voting on the proposal
- function newProposal(
- address _recipient,
- uint _amount,
- string _description,
- bytes _transactionData,
- uint _debatingPeriod,
- bool _newCurator
- ) onlyTokenholders returns (uint _proposalID);
- /// @notice Check that the proposal with the ID `_proposalID` matches the
- /// transaction which sends `_amount` with data `_transactionData`
- /// to `_recipient`
- /// @param _proposalID The proposal ID
- /// @param _recipient The recipient of the proposed transaction
- /// @param _amount The amount of wei to be sent in the proposed transaction
- /// @param _transactionData The data of the proposed transaction
- /// @return Whether the proposal ID matches the transaction data or not
- function checkProposalCode(
- uint _proposalID,
- address _recipient,
- uint _amount,
- bytes _transactionData
- ) constant returns (bool _codeChecksOut);
- /// @notice Vote on proposal `_proposalID` with `_supportsProposal`
- /// @param _proposalID The proposal ID
- /// @param _supportsProposal Yes/No - support of the proposal
- /// @return The vote ID.
- function vote(
- uint _proposalID,
- bool _supportsProposal
- ) onlyTokenholders returns (uint _voteID);
- /// @notice Checks whether proposal `_proposalID` with transaction data
- /// `_transactionData` has been voted for or rejected, and executes the
- /// transaction in the case it has been voted for.
- /// @param _proposalID The proposal ID
- /// @param _transactionData The data of the proposed transaction
- /// @return Whether the proposed transaction has been executed or not
- function executeProposal(
- uint _proposalID,
- bytes _transactionData
- ) returns (bool _success);
- /// @notice ATTENTION! I confirm to move my remaining ether to a new DAO
- /// with `_newCurator` as the new Curator, as has been
- /// proposed in proposal `_proposalID`. This will burn my tokens. This can
- /// not be undone and will split the DAO into two DAO's, with two
- /// different underlying tokens.
- /// @param _proposalID The proposal ID
- /// @param _newCurator The new Curator of the new DAO
- /// @dev This function, when called for the first time for this proposal,
- /// will create a new DAO and send the sender's portion of the remaining
- /// ether and Reward Tokens to the new DAO. It will also burn the DAO Tokens
- /// of the sender.
- function splitDAO(
- uint _proposalID,
- address _newCurator
- ) returns (bool _success);
- /// @dev can only be called by the DAO itself through a proposal
- /// updates the contract of the DAO by sending all ether and rewardTokens
- /// to the new DAO. The new DAO needs to be approved by the Curator
- /// @param _newContract the address of the new contract
- function newContract(address _newContract);
- /// @notice Add a new possible recipient `_recipient` to the whitelist so
- /// that the DAO can send transactions to them (using proposals)
- /// @param _recipient New recipient address
- /// @dev Can only be called by the current Curator
- /// @return Whether successful or not
- function changeAllowedRecipients(address _recipient, bool _allowed) external returns (bool _success);
- /// @notice Change the minimum deposit required to submit a proposal
- /// @param _proposalDeposit The new proposal deposit
- /// @dev Can only be called by this DAO (through proposals with the
- /// recipient being this DAO itself)
- function changeProposalDeposit(uint _proposalDeposit) external;
- /// @notice Move rewards from the DAORewards managed account
- /// @param _toMembers If true rewards are moved to the actual reward account
- /// for the DAO. If not then it's moved to the DAO itself
- /// @return Whether the call was successful
- function retrieveDAOReward(bool _toMembers) external returns (bool _success);
- /// @notice Get my portion of the reward that was sent to `rewardAccount`
- /// @return Whether the call was successful
- function getMyReward() returns(bool _success);
- /// @notice Withdraw `_account`'s portion of the reward from `rewardAccount`
- /// to `_account`'s balance
- /// @return Whether the call was successful
- function withdrawRewardFor(address _account) internal returns (bool _success);
- /// @notice Send `_amount` tokens to `_to` from `msg.sender`. Prior to this
- /// getMyReward() is called.
- /// @param _to The address of the recipient
- /// @param _amount The amount of tokens to be transfered
- /// @return Whether the transfer was successful or not
- function transferWithoutReward(address _to, uint256 _amount) returns (bool success);
- /// @notice Send `_amount` tokens to `_to` from `_from` on the condition it
- /// is approved by `_from`. Prior to this getMyReward() is called.
- /// @param _from The address of the sender
- /// @param _to The address of the recipient
- /// @param _amount The amount of tokens to be transfered
- /// @return Whether the transfer was successful or not
- function transferFromWithoutReward(
- address _from,
- address _to,
- uint256 _amount
- ) returns (bool success);
- /// @notice Doubles the 'minQuorumDivisor' in the case quorum has not been
- /// achieved in 52 weeks
- /// @return Whether the change was successful or not
- function halveMinQuorum() returns (bool _success);
- /// @return total number of proposals ever created
- function numberOfProposals() constant returns (uint _numberOfProposals);
- /// @param _proposalID Id of the new curator proposal
- /// @return Address of the new DAO
- function getNewDAOAddress(uint _proposalID) constant returns (address _newDAO);
- /// @param _account The address of the account which is checked.
- /// @return Whether the account is blocked (not allowed to transfer tokens) or not.
- function isBlocked(address _account) internal returns (bool);
- /// @notice If the caller is blocked by a proposal whose voting deadline
- /// has exprired then unblock him.
- /// @return Whether the account is blocked (not allowed to transfer tokens) or not.
- function unblockMe() returns (bool);
- event ProposalAdded(
- uint indexed proposalID,
- address recipient,
- uint amount,
- bool newCurator,
- string description
- );
- event Voted(uint indexed proposalID, bool position, address indexed voter);
- event ProposalTallied(uint indexed proposalID, bool result, uint quorum);
- event NewCurator(address indexed _newCurator);
- event AllowedRecipientChanged(address indexed _recipient, bool _allowed);
- }
- // The DAO contract itself
- contract DAO is DAOInterface, Token, TokenCreation {
- // Modifier that allows only shareholders to vote and create new proposals
- modifier onlyTokenholders {
- if (balanceOf(msg.sender) == 0) throw;
- _
- }
- function DAO(
- address _curator,
- DAO_Creator _daoCreator,
- uint _proposalDeposit,
- uint _minTokensToCreate,
- uint _closingTime,
- address _privateCreation
- ) TokenCreation(_minTokensToCreate, _closingTime, _privateCreation) {
- curator = _curator;
- daoCreator = _daoCreator;
- proposalDeposit = _proposalDeposit;
- rewardAccount = new ManagedAccount(address(this), false);
- DAOrewardAccount = new ManagedAccount(address(this), false);
- if (address(rewardAccount) == 0)
- throw;
- if (address(DAOrewardAccount) == 0)
- throw;
- lastTimeMinQuorumMet = now;
- minQuorumDivisor = 5; // sets the minimal quorum to 20%
- proposals.length = 1; // avoids a proposal with ID 0 because it is used
- allowedRecipients[address(this)] = true;
- allowedRecipients[curator] = true;
- }
- function () returns (bool success) {
- if (now < closingTime + creationGracePeriod && msg.sender != address(extraBalance))
- return createTokenProxy(msg.sender);
- else
- return receiveEther();
- }
- function receiveEther() returns (bool) {
- return true;
- }
- function newProposal(
- address _recipient,
- uint _amount,
- string _description,
- bytes _transactionData,
- uint _debatingPeriod,
- bool _newCurator
- ) onlyTokenholders returns (uint _proposalID) {
- // Sanity check
- if (_newCurator && (
- _amount != 0
- || _transactionData.length != 0
- || _recipient == curator
- || msg.value > 0
- || _debatingPeriod < minSplitDebatePeriod)) {
- throw;
- } else if (
- !_newCurator
- && (!isRecipientAllowed(_recipient) || (_debatingPeriod < minProposalDebatePeriod))
- ) {
- throw;
- }
- if (_debatingPeriod > 8 weeks)
- throw;
- if (!isFueled
- || now < closingTime
- || (msg.value < proposalDeposit && !_newCurator)) {
- throw;
- }
- if (now + _debatingPeriod < now) // prevents overflow
- throw;
- // to prevent a 51% attacker to convert the ether into deposit
- if (msg.sender == address(this))
- throw;
- _proposalID = proposals.length++;
- Proposal p = proposals[_proposalID];
- p.recipient = _recipient;
- p.amount = _amount;
- p.description = _description;
- p.proposalHash = sha3(_recipient, _amount, _transactionData);
- p.votingDeadline = now + _debatingPeriod;
- p.open = true;
- //p.proposalPassed = False; // that's default
- p.newCurator = _newCurator;
- if (_newCurator)
- p.splitData.length++;
- p.creator = msg.sender;
- p.proposalDeposit = msg.value;
- sumOfProposalDeposits += msg.value;
- ProposalAdded(
- _proposalID,
- _recipient,
- _amount,
- _newCurator,
- _description
- );
- }
- function checkProposalCode(
- uint _proposalID,
- address _recipient,
- uint _amount,
- bytes _transactionData
- ) noEther constant returns (bool _codeChecksOut) {
- Proposal p = proposals[_proposalID];
- return p.proposalHash == sha3(_recipient, _amount, _transactionData);
- }
- function vote(
- uint _proposalID,
- bool _supportsProposal
- ) onlyTokenholders noEther returns (uint _voteID) {
- Proposal p = proposals[_proposalID];
- if (p.votedYes[msg.sender]
- || p.votedNo[msg.sender]
- || now >= p.votingDeadline) {
- throw;
- }
- if (_supportsProposal) {
- p.yea += balances[msg.sender];
- p.votedYes[msg.sender] = true;
- } else {
- p.nay += balances[msg.sender];
- p.votedNo[msg.sender] = true;
- }
- if (blocked[msg.sender] == 0) {
- blocked[msg.sender] = _proposalID;
- } else if (p.votingDeadline > proposals[blocked[msg.sender]].votingDeadline) {
- // this proposal's voting deadline is further into the future than
- // the proposal that blocks the sender so make it the blocker
- blocked[msg.sender] = _proposalID;
- }
- Voted(_proposalID, _supportsProposal, msg.sender);
- }
- function executeProposal(
- uint _proposalID,
- bytes _transactionData
- ) noEther returns (bool _success) {
- Proposal p = proposals[_proposalID];
- uint waitPeriod = p.newCurator
- ? splitExecutionPeriod
- : executeProposalPeriod;
- // If we are over deadline and waiting period, assert proposal is closed
- if (p.open && now > p.votingDeadline + waitPeriod) {
- closeProposal(_proposalID);
- return;
- }
- // Check if the proposal can be executed
- if (now < p.votingDeadline // has the voting deadline arrived?
- // Have the votes been counted?
- || !p.open
- // Does the transaction code match the proposal?
- || p.proposalHash != sha3(p.recipient, p.amount, _transactionData)) {
- throw;
- }
- // If the curator removed the recipient from the whitelist, close the proposal
- // in order to free the deposit and allow unblocking of voters
- if (!isRecipientAllowed(p.recipient)) {
- closeProposal(_proposalID);
- p.creator.send(p.proposalDeposit);
- return;
- }
- bool proposalCheck = true;
- if (p.amount > actualBalance())
- proposalCheck = false;
- uint quorum = p.yea + p.nay;
- // require 53% for calling newContract()
- if (_transactionData.length >= 4 && _transactionData[0] == 0x68
- && _transactionData[1] == 0x37 && _transactionData[2] == 0xff
- && _transactionData[3] == 0x1e
- && quorum < minQuorum(actualBalance() + rewardToken[address(this)])) {
- proposalCheck = false;
- }
- if (quorum >= minQuorum(p.amount)) {
- if (!p.creator.send(p.proposalDeposit))
- throw;
- lastTimeMinQuorumMet = now;
- // set the minQuorum to 20% again, in the case it has been reached
- if (quorum > totalSupply / 5)
- minQuorumDivisor = 5;
- }
- // Execute result
- if (quorum >= minQuorum(p.amount) && p.yea > p.nay && proposalCheck) {
- if (!p.recipient.call.value(p.amount)(_transactionData))
- throw;
- p.proposalPassed = true;
- _success = true;
- // only create reward tokens when ether is not sent to the DAO itself and
- // related addresses. Proxy addresses should be forbidden by the curator.
- if (p.recipient != address(this) && p.recipient != address(rewardAccount)
- && p.recipient != address(DAOrewardAccount)
- && p.recipient != address(extraBalance)
- && p.recipient != address(curator)) {
- rewardToken[address(this)] += p.amount;
- totalRewardToken += p.amount;
- }
- }
- closeProposal(_proposalID);
- // Initiate event
- ProposalTallied(_proposalID, _success, quorum);
- }
- function closeProposal(uint _proposalID) internal {
- Proposal p = proposals[_proposalID];
- if (p.open)
- sumOfProposalDeposits -= p.proposalDeposit;
- p.open = false;
- }
- function splitDAO(
- uint _proposalID,
- address _newCurator
- ) noEther onlyTokenholders returns (bool _success) {
- Proposal p = proposals[_proposalID];
- // Sanity check
- if (now < p.votingDeadline // has the voting deadline arrived?
- //The request for a split expires XX days after the voting deadline
- || now > p.votingDeadline + splitExecutionPeriod
- // Does the new Curator address match?
- || p.recipient != _newCurator
- // Is it a new curator proposal?
- || !p.newCurator
- // Have you voted for this split?
- || !p.votedYes[msg.sender]
- // Did you already vote on another proposal?
- || (blocked[msg.sender] != _proposalID && blocked[msg.sender] != 0) ) {
- throw;
- }
- // If the new DAO doesn't exist yet, create the new DAO and store the
- // current split data
- if (address(p.splitData[0].newDAO) == 0) {
- p.splitData[0].newDAO = createNewDAO(_newCurator);
- // Call depth limit reached, etc.
- if (address(p.splitData[0].newDAO) == 0)
- throw;
- // should never happen
- if (this.balance < sumOfProposalDeposits)
- throw;
- p.splitData[0].splitBalance = actualBalance();
- p.splitData[0].rewardToken = rewardToken[address(this)];
- p.splitData[0].totalSupply = totalSupply;
- p.proposalPassed = true;
- }
- // Move ether and assign new Tokens
- uint fundsToBeMoved =
- (balances[msg.sender] * p.splitData[0].splitBalance) /
- p.splitData[0].totalSupply;
- if (p.splitData[0].newDAO.createTokenProxy.value(fundsToBeMoved)(msg.sender) == false)
- throw;
- // Assign reward rights to new DAO
- uint rewardTokenToBeMoved =
- (balances[msg.sender] * p.splitData[0].rewardToken) /
- p.splitData[0].totalSupply;
- uint paidOutToBeMoved = DAOpaidOut[address(this)] * rewardTokenToBeMoved /
- rewardToken[address(this)];
- rewardToken[address(p.splitData[0].newDAO)] += rewardTokenToBeMoved;
- if (rewardToken[address(this)] < rewardTokenToBeMoved)
- throw;
- rewardToken[address(this)] -= rewardTokenToBeMoved;
- DAOpaidOut[address(p.splitData[0].newDAO)] += paidOutToBeMoved;
- if (DAOpaidOut[address(this)] < paidOutToBeMoved)
- throw;
- DAOpaidOut[address(this)] -= paidOutToBeMoved;
- // Burn DAO Tokens
- Transfer(msg.sender, 0, balances[msg.sender]);
- withdrawRewardFor(msg.sender); // be nice, and get his rewards
- totalSupply -= balances[msg.sender];
- balances[msg.sender] = 0;
- paidOut[msg.sender] = 0;
- return true;
- }
- function newContract(address _newContract){
- if (msg.sender != address(this) || !allowedRecipients[_newContract]) return;
- // move all ether
- if (!_newContract.call.value(address(this).balance)()) {
- throw;
- }
- //move all reward tokens
- rewardToken[_newContract] += rewardToken[address(this)];
- rewardToken[address(this)] = 0;
- DAOpaidOut[_newContract] += DAOpaidOut[address(this)];
- DAOpaidOut[address(this)] = 0;
- }
- function retrieveDAOReward(bool _toMembers) external noEther returns (bool _success) {
- DAO dao = DAO(msg.sender);
- if ((rewardToken[msg.sender] * DAOrewardAccount.accumulatedInput()) /
- totalRewardToken < DAOpaidOut[msg.sender])
- throw;
- uint reward =
- (rewardToken[msg.sender] * DAOrewardAccount.accumulatedInput()) /
- totalRewardToken - DAOpaidOut[msg.sender];
- if(_toMembers) {
- if (!DAOrewardAccount.payOut(dao.rewardAccount(), reward))
- throw;
- }
- else {
- if (!DAOrewardAccount.payOut(dao, reward))
- throw;
- }
- DAOpaidOut[msg.sender] += reward;
- return true;
- }
- function getMyReward() noEther returns (bool _success) {
- return withdrawRewardFor(msg.sender);
- }
- function withdrawRewardFor(address _account) noEther internal returns (bool _success) {
- if ((balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply < paidOut[_account])
- throw;
- uint reward =
- (balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply - paidOut[_account];
- if (!rewardAccount.payOut(_account, reward))
- throw;
- paidOut[_account] += reward;
- return true;
- }
- function transfer(address _to, uint256 _value) returns (bool success) {
- if (isFueled
- && now > closingTime
- && !isBlocked(msg.sender)
- && transferPaidOut(msg.sender, _to, _value)
- && super.transfer(_to, _value)) {
- return true;
- } else {
- throw;
- }
- }
- function transferWithoutReward(address _to, uint256 _value) returns (bool success) {
- if (!getMyReward())
- throw;
- return transfer(_to, _value);
- }
- function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
- if (isFueled
- && now > closingTime
- && !isBlocked(_from)
- && transferPaidOut(_from, _to, _value)
- && super.transferFrom(_from, _to, _value)) {
- return true;
- } else {
- throw;
- }
- }
- function transferFromWithoutReward(
- address _from,
- address _to,
- uint256 _value
- ) returns (bool success) {
- if (!withdrawRewardFor(_from))
- throw;
- return transferFrom(_from, _to, _value);
- }
- function transferPaidOut(
- address _from,
- address _to,
- uint256 _value
- ) internal returns (bool success) {
- uint transferPaidOut = paidOut[_from] * _value / balanceOf(_from);
- if (transferPaidOut > paidOut[_from])
- throw;
- paidOut[_from] -= transferPaidOut;
- paidOut[_to] += transferPaidOut;
- return true;
- }
- function changeProposalDeposit(uint _proposalDeposit) noEther external {
- if (msg.sender != address(this) || _proposalDeposit > (actualBalance() + rewardToken[address(this)])
- / maxDepositDivisor) {
- throw;
- }
- proposalDeposit = _proposalDeposit;
- }
- function changeAllowedRecipients(address _recipient, bool _allowed) noEther external returns (bool _success) {
- if (msg.sender != curator)
- throw;
- allowedRecipients[_recipient] = _allowed;
- AllowedRecipientChanged(_recipient, _allowed);
- return true;
- }
- function isRecipientAllowed(address _recipient) internal returns (bool _isAllowed) {
- if (allowedRecipients[_recipient]
- || (_recipient == address(extraBalance)
- // only allowed when at least the amount held in the
- // extraBalance account has been spent from the DAO
- && totalRewardToken > extraBalance.accumulatedInput()))
- return true;
- else
- return false;
- }
- function actualBalance() constant returns (uint _actualBalance) {
- return this.balance - sumOfProposalDeposits;
- }
- function minQuorum(uint _value) internal constant returns (uint _minQuorum) {
- // minimum of 20% and maximum of 53.33%
- return totalSupply / minQuorumDivisor +
- (_value * totalSupply) / (3 * (actualBalance() + rewardToken[address(this)]));
- }
- function halveMinQuorum() returns (bool _success) {
- // this can only be called after `quorumHalvingPeriod` has passed or at anytime
- // by the curator with a delay of at least `minProposalDebatePeriod` between the calls
- if ((lastTimeMinQuorumMet < (now - quorumHalvingPeriod) || msg.sender == curator)
- && lastTimeMinQuorumMet < (now - minProposalDebatePeriod)) {
- lastTimeMinQuorumMet = now;
- minQuorumDivisor *= 2;
- return true;
- } else {
- return false;
- }
- }
- function createNewDAO(address _newCurator) internal returns (DAO _newDAO) {
- NewCurator(_newCurator);
- return daoCreator.createDAO(_newCurator, 0, 0, now + splitExecutionPeriod);
- }
- function numberOfProposals() constant returns (uint _numberOfProposals) {
- // Don't count index 0. It's used by isBlocked() and exists from start
- return proposals.length - 1;
- }
- function getNewDAOAddress(uint _proposalID) constant returns (address _newDAO) {
- return proposals[_proposalID].splitData[0].newDAO;
- }
- function isBlocked(address _account) internal returns (bool) {
- if (blocked[_account] == 0)
- return false;
- Proposal p = proposals[blocked[_account]];
- if (now > p.votingDeadline) {
- blocked[_account] = 0;
- return false;
- } else {
- return true;
- }
- }
- function unblockMe() returns (bool) {
- return isBlocked(msg.sender);
- }
- }
- contract DAO_Creator {
- function createDAO(
- address _curator,
- uint _proposalDeposit,
- uint _minTokensToCreate,
- uint _closingTime
- ) returns (DAO _newDAO) {
- return new DAO(
- _curator,
- DAO_Creator(this),
- _proposalDeposit,
- _minTokensToCreate,
- _closingTime,
- msg.sender
- );
- }
- }
- contract DAOSecurity {
- // The total cost of the Offer. Exactly this amount is transfered from the
- // Client to the Offer contract when the Offer is signed by the Client.
- // Set once by the Offerer.
- uint totalCosts;
- // Initial withdraw to the Contractor. It is done the moment the Offer is
- // signed.
- // Set once by the Offerer.
- uint oneTimeCosts;
- // The minimal daily withdraw limit that the Contractor accepts.
- // Set once by the Offerer.
- uint128 minDailyWithdrawLimit;
- // The amount of wei the Contractor has right to withdraw daily above the
- // initial withdraw. The Contractor does not have to do the withdraws every
- // day as this amount accumulates.
- uint128 dailyWithdrawLimit;
- // The address of the Contractor.
- address contractor;
- // The hash of the Proposal/Offer document.
- bytes32 hashOfTheProposalDocument;
- // The time of the last withdraw to the Contractor.
- uint lastPayment;
- uint dateOfSignature;
- DAO client; // address of DAO
- DAO originalClient; // address of DAO who signed the contract
- bool isContractValid;
- modifier onlyClient {
- if (msg.sender != address(client))
- throw;
- _
- }
- // Prevents methods from perfoming any value transfer
- modifier noEther() {if (msg.value > 0) throw; _}
- function DAOSecurity(
- address _contractor,
- address _client,
- bytes32 _hashOfTheProposalDocument,
- uint _totalCosts,
- uint _oneTimeCosts,
- uint128 _minDailyWithdrawLimit
- ) {
- contractor = _contractor;
- originalClient = DAO(_client);
- client = DAO(_client);
- hashOfTheProposalDocument = _hashOfTheProposalDocument;
- totalCosts = _totalCosts;
- oneTimeCosts = _oneTimeCosts;
- minDailyWithdrawLimit = _minDailyWithdrawLimit;
- dailyWithdrawLimit = _minDailyWithdrawLimit;
- }
- // non-value-transfer getters
- function getTotalCosts() noEther constant returns (uint) {
- return totalCosts;
- }
- function getOneTimeCosts() noEther constant returns (uint) {
- return oneTimeCosts;
- }
- function getMinDailyWithdrawLimit() noEther constant returns (uint128) {
- return minDailyWithdrawLimit;
- }
- function getDailyWithdrawLimit() noEther constant returns (uint128) {
- return dailyWithdrawLimit;
- }
- function getContractor() noEther constant returns (address) {
- return contractor;
- }
- function getHashOfTheProposalDocument() noEther constant returns (bytes32) {
- return hashOfTheProposalDocument;
- }
- function getLastPayment() noEther constant returns (uint) {
- return lastPayment;
- }
- function getDateOfSignature() noEther constant returns (uint) {
- return dateOfSignature;
- }
- function getClient() noEther constant returns (DAO) {
- return client;
- }
- function getOriginalClient() noEther constant returns (DAO) {
- return originalClient;
- }
- function getIsContractValid() noEther constant returns (bool) {
- return isContractValid;
- }
- function sign() {
- if (msg.sender != address(originalClient) // no good samaritans give us ether
- || msg.value != totalCosts // no under/over payment
- || dateOfSignature != 0) // don't sign twice
- throw;
- if (!contractor.send(oneTimeCosts))
- throw;
- dateOfSignature = now;
- isContractValid = true;
- lastPayment = now;
- }
- function setDailyWithdrawLimit(uint128 _dailyWithdrawLimit) onlyClient noEther {
- if (_dailyWithdrawLimit >= minDailyWithdrawLimit)
- dailyWithdrawLimit = _dailyWithdrawLimit;
- }
- // "fire the contractor"
- function returnRemainingEther() onlyClient {
- if (originalClient.DAOrewardAccount().call.value(this.balance)())
- isContractValid = false;
- }
- // Withdraw to the Contractor.
- //
- // Withdraw the amount of ether the Contractor has right to according to
- // the current withdraw limit.
- // Executing this function before the Offer is signed off by the Client
- // makes no sense as this contract has no ether.
- function getDailyPayment() noEther {
- if (msg.sender != contractor)
- throw;
- uint timeSinceLastPayment = now - lastPayment;
- // Calculate the amount using 1 second precision.
- uint amount = (timeSinceLastPayment * dailyWithdrawLimit) / (1 days);
- if (amount > this.balance) {
- amount = this.balance;
- }
- if (contractor.send(amount))
- lastPayment = now;
- }
- // Change the client DAO by giving the new DAO's address
- // warning: The new DAO must come either from a split of the original
- // DAO or an update via `newContract()` so that it can claim rewards
- function updateClientAddress(DAO _newClient) onlyClient noEther {
- client = _newClient;
- }
- function () {
- throw; // this is a business contract, no donations
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement