SingularDTV Crowdsale Completed Within Fifteen Minutes and SingularDTV Raises $7.5M to Incentivize Creative Output.
Website – https://singulardtv.com/.
Reddit – https://www.reddit.com/r/SingularDTV.
From the reddit site sidebar:
TOKEN SALE SPECS
The SingularDTV token is called “SNGLS”. SNGLS are fungible and conform to Ethereum’s universal token standards. SNGLS represent a pro rata gross revenue/asset share in SingularDTV projects and intellectual property.
The total number of SNGLS in the SingularDTV ecosystem is 1 Billion. 500 million of these will be generated for the SingularDTV audience at the ETH equivalent of 1.5 cents per token for a total ETH equivalent of $7.5m to:
1.) launch a documentary film division dedicated to educating the world about Ethereum, blockchain and decentralization;
2.) produce Season 1 of our sci-fi epic television series ‘Singular’, about the human race’s journey into a technological Singularity;
3.) build a rights, revenue and royalty management platform and;
4.) build a transaction video on-demand portal.
Of the remaining 500 million SNGLS tokens not offered to the world, 400 million belong to the founders and 100 million to seed/development investors. All gross revenue claimed by the 400 million founders tokens will be re-invested back into the SingularDTV ecosystem to create film/TV content as well as decentralized tech/apps for the entertainment industry. It is important to note the SingularDTV founders will only receive dividends or revenue from these 400 million tokens in the event of a future exit. Founders will receive commensurate compensation as budgeted on a per project basis to act as SingularDTV’s executive team. The remaining 100 million tokens held by our seed/development investors enjoy the same attributes as the 500 million sold to the world. They can be held to receive revenue and asset benefits from SingularDTV projects in perpetuity, or traded on the open market. Please see our Summary Overview on www.SingularDTV.com for more details or please ask us anything.
The tokens were apparently on sale for 862.065 SNGL per 1 ETH. 1 ETH = USD 13.208 currently. 1 SNGL = ~USD 13.208 / 862.065 = ~ USD 0.015 . Which is approximately 1.5 cents per SNGL.
At 1 ETH = 0.02160640 BTC, 1 SNGL = ~ 0.00002506 BTC.
The contract code at https://github.com/ConsenSys/singulardtv-contracts listed below:
AbstractCampaign.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
contract Campaign { /// @notice the campaign name /// @return contractual metadata which specifies the campaign name as a string function name() constant returns(string) {} /// @notice use to determine the contribution method abi /// @return will return a string that is the exact contributeMethodABI function contributeMethodABI() constant returns(string) {} /// @notice use to determine the contribution method abi /// @return will return a string that is the exact contributeMethodABI function refundMethodABI() constant returns(string) {} /// @notice use to determine the contribution method abi /// @return will return a string that is the exact contributeMethodABI function payoutMethodABI() constant returns(string) {} /// @notice use to determine the beneficiary destination for the campaign /// @return the beneficiary address that will receive the campaign payout function beneficiary() constant returns(address) {} /// @notice the time at which the campaign fails or succeeds /// @return the uint unix timestamp at which time the campaign expires function expiry() constant returns(uint256 timestamp) {} /// @notice the goal the campaign must reach in order for it to succeed /// @return the campaign funding goal specified in wei as a uint256 function fundingGoal() constant returns(uint256 amount) {} /// @notice the goal the campaign must reach in order for it to succeed /// @return the campaign funding goal specified in wei as a uint256 function amountRaised() constant returns(uint256 amount) {} // Campaign events event ContributionMade (address _contributor); event RefundPayoutClaimed(uint256 _contributionID); event BeneficiaryPayoutClaimed (address _beneficiary, uint256 _payoutAmount); } |
AbstractToken.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/// Implements ERC 20 Token standard: https://github.com/ethereum/EIPs/issues/20 /// @title Abstract token contract - Functions to be implemented by token contracts. /// @author Stefan George - <stefan.george@consensys.net> contract Token { // This is not an abstract function, because solc won't recognize generated getter functions for public variables as functions function totalSupply() constant returns (uint256 supply) {} function balanceOf(address owner) constant returns (uint256 balance); function transfer(address to, uint256 value) returns (bool success); function transferFrom(address from, address to, uint256 value) returns (bool success); function approve(address spender, uint256 value) returns (bool success); function allowance(address owner, address spender) constant returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } |
AbstractSingularDTVToken.sol
1 2 3 4 5 |
import "AbstractToken.sol"; contract SingularDTVToken is Token { function issueTokens(address _for, uint tokenCount) returns (bool); } |
AbstractSingularDTVFund.sol
1 2 3 4 |
contract SingularDTVFund { function workshop() returns (address); function softWithdrawRevenueFor(address forAddress) returns (uint); } |
AbstractSingularDTVCrowdfunding.sol
1 2 3 4 5 6 7 8 9 |
contract SingularDTVCrowdfunding { function twoYearsPassed() returns (bool); function startDate() returns (uint); function CROWDFUNDING_PERIOD() returns (uint); function TOKEN_TARGET() returns (uint); function valuePerShare() returns (uint); function fundBalance() returns (uint); function campaignEndedSuccessfully() returns (bool); } |
SingularDTVFund.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
import "AbstractSingularDTVToken.sol"; import "AbstractSingularDTVCrowdfunding.sol"; /// @title Fund contract - Implements revenue distribution. /// @author Stefan George - <stefan.george@consensys.net> contract SingularDTVFund { /* * External contracts */ SingularDTVToken public singularDTVToken; SingularDTVCrowdfunding public singularDTVCrowdfunding; /* * Storage */ address public owner; address constant public workshop = {{MistWallet}}; uint public totalRevenue; // User's address => Revenue at time of withdraw mapping (address => uint) public revenueAtTimeOfWithdraw; // User's address => Revenue which can be withdrawn mapping (address => uint) public owed; /* * Modifiers */ modifier noEther() { if (msg.value > 0) { throw; } _ } modifier onlyOwner() { // Only guard is allowed to do this action. if (msg.sender != owner) { throw; } _ } modifier campaignEndedSuccessfully() { if (!singularDTVCrowdfunding.campaignEndedSuccessfully()) { throw; } _ } /* * Contract functions */ /// @dev Deposits revenue. Returns success. function depositRevenue() external campaignEndedSuccessfully returns (bool) { totalRevenue += msg.value; return true; } /// @dev Withdraws revenue share for user. Returns revenue share. /// @param forAddress Shareholder's address. function calcRevenue(address forAddress) internal returns (uint) { return singularDTVToken.balanceOf(forAddress) * (totalRevenue - revenueAtTimeOfWithdraw[forAddress]) / singularDTVToken.totalSupply(); } /// @dev Withdraws revenue share for user. Returns revenue share. function withdrawRevenue() external noEther returns (uint) { uint value = calcRevenue(msg.sender) + owed[msg.sender]; revenueAtTimeOfWithdraw[msg.sender] = totalRevenue; owed[msg.sender] = 0; if (value > 0 && !msg.sender.send(value)) { throw; } return value; } /// @dev Credits revenue share to owed balance. /// @param forAddress Shareholder's address. function softWithdrawRevenueFor(address forAddress) external noEther returns (uint) { uint value = calcRevenue(forAddress); revenueAtTimeOfWithdraw[forAddress] = totalRevenue; owed[forAddress] += value; return value; } /// @dev Setup function sets external contracts' addresses. /// @param singularDTVTokenAddress Token address. function setup(address singularDTVCrowdfundingAddress, address singularDTVTokenAddress) external noEther onlyOwner returns (bool) { if (address(singularDTVCrowdfunding) == 0 && address(singularDTVToken) == 0) { singularDTVCrowdfunding = SingularDTVCrowdfunding(singularDTVCrowdfundingAddress); singularDTVToken = SingularDTVToken(singularDTVTokenAddress); return true; } return false; } /// @dev Contract constructor function sets guard and initial token balances. function SingularDTVFund() noEther { // Set owner address owner = msg.sender; } } |
SingularDTVCrowdfunding.sol
Contract deployed at 0xbdf5c4f1c1a9d7335a6a68d9aa011d5f40cf5520.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 |
import "AbstractSingularDTVToken.sol"; import "AbstractSingularDTVFund.sol"; /// @title Crowdfunding contract - Implements crowdfunding functionality. /// @author Stefan George - <stefan.george@consensys.net> contract SingularDTVCrowdfunding { /* * External contracts */ SingularDTVToken public singularDTVToken; SingularDTVFund public singularDTVFund; /* * Constants */ uint constant public CAP = 1000000000; // 1B tokens is the maximum amount of tokens uint constant public CROWDFUNDING_PERIOD = 4 weeks; // 1 month uint constant public TOKEN_LOCKING_PERIOD = 2 years; // 2 years uint constant public TOKEN_TARGET = 534000000; // 34M Tokens more than the initial 500M, around 42,500 ETH /* * Enums */ enum Stages { CrowdfundingGoingAndGoalNotReached, CrowdfundingEndedAndGoalNotReached, CrowdfundingGoingAndGoalReached, CrowdfundingEndedAndGoalReached } /* * Storage */ address public owner; uint public startDate; uint public fundBalance; uint public baseValue = 1250 szabo; // 0.00125 ETH uint public valuePerShare = baseValue; // 0.00125 ETH // investor address => investment in Wei mapping (address => uint) public investments; // Initialize stage Stages public stage = Stages.CrowdfundingGoingAndGoalNotReached; /* * Modifiers */ modifier noEther() { if (msg.value > 0) { throw; } _ } modifier onlyOwner() { // Only owner is allowed to do this action. if (msg.sender != owner) { throw; } _ } modifier minInvestment() { // User has to invest at least the ether value of one share. if (msg.value < valuePerShare) { throw; } _ } modifier atStage(Stages _stage) { if (stage != _stage) { throw; } _ } modifier atStageOR(Stages _stage1, Stages _stage2) { if (stage != _stage1 && stage != _stage2) { throw; } _ } modifier timedTransitions() { uint crowdfundDuration = now - startDate; if (crowdfundDuration >= 22 days) { valuePerShare = baseValue * 1500 / 1000; } else if (crowdfundDuration >= 18 days) { valuePerShare = baseValue * 1375 / 1000; } else if (crowdfundDuration >= 14 days) { valuePerShare = baseValue * 1250 / 1000; } else if (crowdfundDuration >= 10 days) { valuePerShare = baseValue * 1125 / 1000; } else { valuePerShare = baseValue; } if (crowdfundDuration >= CROWDFUNDING_PERIOD) { if (stage == Stages.CrowdfundingGoingAndGoalNotReached) { stage = Stages.CrowdfundingEndedAndGoalNotReached; } else if (stage == Stages.CrowdfundingGoingAndGoalReached) { stage = Stages.CrowdfundingEndedAndGoalReached; } } _ } /* * Contract functions */ /// dev Validates invariants. function checkInvariants() constant internal { if (fundBalance > this.balance) { throw; } } /// @dev Can be triggered if an invariant fails. function emergencyCall() external noEther returns (bool) { if (fundBalance > this.balance) { if (this.balance > 0 && !singularDTVFund.workshop().send(this.balance)) { throw; } return true; } return false; } /// @dev Allows user to fund the campaign if campaign is still going and cap not reached. Returns share count. function fund() external timedTransitions atStageOR(Stages.CrowdfundingGoingAndGoalNotReached, Stages.CrowdfundingGoingAndGoalReached) minInvestment returns (uint) { uint tokenCount = msg.value / valuePerShare; // Token count is rounded down. Investment should be multiples of valuePerShare. if (singularDTVToken.totalSupply() + tokenCount > CAP) { // User wants to buy more shares than available. Set shares to possible maximum. tokenCount = CAP - singularDTVToken.totalSupply(); } uint investment = tokenCount * valuePerShare; // Ether invested by backer. // Send change back to user. if (msg.value > investment && !msg.sender.send(msg.value - investment)) { throw; } // Update fund's and user's balance and total supply of shares. fundBalance += investment; investments[msg.sender] += investment; if (!singularDTVToken.issueTokens(msg.sender, tokenCount)) { // Tokens could not be issued. throw; } // Update stage if (stage == Stages.CrowdfundingGoingAndGoalNotReached) { if (singularDTVToken.totalSupply() >= TOKEN_TARGET) { stage = Stages.CrowdfundingGoingAndGoalReached; } } // not an else clause for the edge case that the CAP and TOKEN_TARGET are reached with one big funding if (stage == Stages.CrowdfundingGoingAndGoalReached) { if (singularDTVToken.totalSupply() == CAP) { stage = Stages.CrowdfundingEndedAndGoalReached; } } checkInvariants(); return tokenCount; } /// @dev Allows user to withdraw his funding if crowdfunding ended and target was not reached. Returns success. function withdrawFunding() external noEther timedTransitions atStage(Stages.CrowdfundingEndedAndGoalNotReached) returns (bool) { // Update fund's and user's balance and total supply of shares. uint investment = investments[msg.sender]; investments[msg.sender] = 0; fundBalance -= investment; // Send funds back to user. if (investment > 0 && !msg.sender.send(investment)) { throw; } checkInvariants(); return true; } /// @dev Withdraws funding for workshop. Returns success. function withdrawForWorkshop() external noEther timedTransitions atStage(Stages.CrowdfundingEndedAndGoalReached) returns (bool) { uint value = fundBalance; fundBalance = 0; if (value > 0 && !singularDTVFund.workshop().send(value)) { throw; } checkInvariants(); return true; } /// @dev Sets token value in Wei. /// @param valueInWei New value. function changeBaseValue(uint valueInWei) external noEther onlyOwner returns (bool) { baseValue = valueInWei; return true; } /// @dev Returns if 1 year passed since beginning of crowdfunding. function twoYearsPassed() constant external noEther returns (bool) { return now - startDate >= TOKEN_LOCKING_PERIOD; } /// @dev Returns if campaign ended successfully. function campaignEndedSuccessfully() constant external noEther returns (bool) { if (stage == Stages.CrowdfundingEndedAndGoalReached) { return true; } return false; } // updateStage allows calls to receive correct stage. It can be used for transactions but is not part of the regular crowdfunding routine. // It is not marked as constant because timedTransitions modifier is altering state and constant is not yet enforced by solc. /// @dev returns correct stage, even if a function with timedTransitions modifier has not yet been called successfully. function updateStage() external timedTransitions noEther returns (Stages) { return stage; } /// @dev Setup function sets external contracts' addresses. /// @param singularDTVFundAddress Crowdfunding address. /// @param singularDTVTokenAddress Token address. function setup(address singularDTVFundAddress, address singularDTVTokenAddress) external onlyOwner noEther returns (bool) { if (address(singularDTVFund) == 0 && address(singularDTVToken) == 0) { singularDTVFund = SingularDTVFund(singularDTVFundAddress); singularDTVToken = SingularDTVToken(singularDTVTokenAddress); return true; } return false; } /// @dev Contract constructor function sets owner and start date. function SingularDTVCrowdfunding() noEther { // Set owner address owner = msg.sender; // Set start-date of crowdfunding startDate = now; } /// @dev Fallback function always fails. Use fund function to fund the contract with Ether. function () { throw; } } |
StandardToken.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
import "AbstractToken.sol"; contract StandardToken is Token { /* * Data structures */ mapping (address => uint256) balances; mapping (address => mapping (address => uint256)) allowed; uint256 public totalSupply; /* * Read and write storage functions */ /// @dev Transfers sender's tokens to a given address. Returns success. /// @param _to Address of token receiver. /// @param _value Number of tokens to transfer. function transfer(address _to, uint256 _value) returns (bool success) { if (balances[msg.sender] >= _value && _value > 0) { balances[msg.sender] -= _value; balances[_to] += _value; Transfer(msg.sender, _to, _value); return true; } else { return false; } } /// @dev Allows allowed third party to transfer tokens from one address to another. Returns success. /// @param _from Address from where tokens are withdrawn. /// @param _to Address to where tokens are sent. /// @param _value Number of tokens to transfer. function transferFrom(address _from, address _to, uint256 _value) returns (bool success) { if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) { balances[_to] += _value; balances[_from] -= _value; allowed[_from][msg.sender] -= _value; Transfer(_from, _to, _value); return true; } else { return false; } } /// @dev Returns number of tokens owned by given address. /// @param _owner Address of token owner. function balanceOf(address _owner) constant returns (uint256 balance) { return balances[_owner]; } /// @dev Sets approved amount of tokens for spender. Returns success. /// @param _spender Address of allowed account. /// @param _value Number of approved tokens. function approve(address _spender, uint256 _value) returns (bool success) { allowed[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; } /* * Read storage functions */ /// @dev Returns number of allowed tokens for given address. /// @param _owner Address of token owner. /// @param _spender Address of token spender. function allowance(address _owner, address _spender) constant returns (uint256 remaining) { return allowed[_owner][_spender]; } } |
SingularDTVToken.sol
Contract deployed at 0xaec2e87e0a235266d9c5adc9deb4b2e29b54d009.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
import "StandardToken.sol"; import "AbstractSingularDTVFund.sol"; import "AbstractSingularDTVCrowdfunding.sol"; /// @title Token contract - Implements token issuance. /// @author Stefan George - <stefan.george@consensys.net> contract SingularDTVToken is StandardToken { /* * External contracts */ SingularDTVFund constant singularDTVFund = SingularDTVFund({{SingularDTVFund}}); SingularDTVCrowdfunding constant singularDTVCrowdfunding = SingularDTVCrowdfunding({{SingularDTVCrowdfunding}}); /* * Token meta data */ string constant public name = "SingularDTV"; string constant public symbol = "SNGLS"; uint8 constant public decimals = 0; /* * Modifiers */ modifier noEther() { if (msg.value > 0) { throw; } _ } modifier workshopWaitedTwoYears() { // Workshop can only transfer shares after a two years period. if (msg.sender == singularDTVFund.workshop() && !singularDTVCrowdfunding.twoYearsPassed()) { throw; } _ } modifier isCrowdfundingContract () { // Only crowdfunding contract is allowed to proceed. if (msg.sender != address(singularDTVCrowdfunding)) { throw; } _ } /* * Contract functions */ /// @dev Crowdfunding contract issues new tokens for address. Returns success. /// @param _for Address of receiver. /// @param tokenCount Number of tokens to issue. function issueTokens(address _for, uint tokenCount) external isCrowdfundingContract returns (bool) { if (tokenCount == 0) { return false; } balances[_for] += tokenCount; totalSupply += tokenCount; return true; } /// @dev Transfers sender's tokens to a given address. Returns success. /// @param to Address of token receiver. /// @param value Number of tokens to transfer. function transfer(address to, uint256 value) noEther workshopWaitedTwoYears returns (bool) { // Both parties withdraw their revenue first singularDTVFund.softWithdrawRevenueFor(msg.sender); singularDTVFund.softWithdrawRevenueFor(to); return super.transfer(to, value); } /// @dev Allows allowed third party to transfer tokens from one address to another. Returns success. /// @param from Address from where tokens are withdrawn. /// @param to Address to where tokens are sent. /// @param value Number of tokens to transfer. function transferFrom(address from, address to, uint256 value) noEther workshopWaitedTwoYears returns (bool) { // Both parties withdraw their revenue first singularDTVFund.softWithdrawRevenueFor(from); singularDTVFund.softWithdrawRevenueFor(to); return super.transferFrom(from, to, value); } /// @dev Contract constructor function sets initial token balances. function SingularDTVToken() noEther { // Set initial share distribution balances[singularDTVFund.workshop()] = 400000000; // ~400M // Series A investors balances[0x0196b712a0459cbee711e7c1d34d2c85a9910379] = 5000000; balances[0x0f94dc84ce0f5fa2a8cc8d27a6969e25b5a39273] = 200000; balances[0x122b7eb5f629d806c8adb0baa0560266abb3ec80] = 450000; balances[0x13870d30fcdb7d7ae875668f2a1219225295d57c] = 50000; balances[0x26640e826547bc700b8c7a9cc2c1c39a4ab3cbb3] = 900000; balances[0x26bbfc6b23bc36e84447f061c6804f3a8b1a3698] = 250000; balances[0x2d37383a45b5122a27efade69f7180eee4d965da] = 1270000; balances[0x2e79b81121193d55c4934c0f32ad3d0474ca7b9c] = 4200000; balances[0x3114844fc0e3de03963bbd1d983ba17ca89ad010] = 5000000; balances[0x378e6582e4e3723f7076c7769eef6febf51258e1] = 680000; balances[0x3e18530a4ee49a0357ffc8e74c08bfdee3915482] = 2490000; balances[0x43fed1208d25ca0ef5681a5c17180af50c19f826] = 100000; balances[0x4f183b18302c0ac5804b8c455018efc51af15a56] = 10000; balances[0x55a886834658ccb6f26c39d5fdf6d833df3a276a] = 100000; balances[0x5faa1624422db662c654ab35ce57bf3242888937] = 5000000; balances[0x6407b662b306e2353b627488da952337a5a0bbaa] = 5000000; balances[0x66c334fff8c8b8224b480d8da658ca3b032fe625] = 10000000; balances[0x6c24991c6a40cd5ad6fab78388651fb324b35458] = 250000; balances[0x781ba492f786b2be48c2884b733874639f50022c] = 500000; balances[0x79b48f6f1ac373648c509b74a2c04a3281066457] = 2000000; balances[0x835898804ed30e20aa29f2fe35c9f225175b049f] = 100000; balances[0x93c56ea8848150389e0917de868b0a23c87cf7b1] = 2790000; balances[0x93f959df3df3c6ee01ee9748327b881b2137bf2a] = 450000; balances[0x9adc0215372e4ffd8c89621a6bd9cfddf230349f] = 550000; balances[0xae4dbd3dae66722315541d66fe9457b342ac76d9] = 500000; balances[0xbae02fe006f115e45b372f2ddc053eedca2d6fff] = 1800000; balances[0xcc835821f643e090d8157de05451b416cd1202c4] = 300000; balances[0xce75342b92a7d0b1a2c6e9835b6b85787e12e585] = 670000; balances[0xd2b388467d9d0c30bab0a68070c6f49c473583a0] = 990000; balances[0xdca0724ddde95bbace1b557cab4375d9a813da49] = 3500000; balances[0xe3ef62165b60cac0fcbe9c2dc6a03aab4c5c8462] = 150000; balances[0xe4f7d5083baeea7810b6d816581bb0ee7cd4b6f4] = 10560000; balances[0xef08eb55d3482973c178b02bd4d5f2cea420325f] = 80000; balances[0xfdecc9f2ee374cedc94f72ab4da2de896ce58c19] = 5000000; balances[0xe5ff71dc1dea8cd2552eec59e9a5e8813da9bb01] = 29110000; totalSupply = 500000000; // 500M } } |
SingularDTVWeifund.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import "AbstractCampaign.sol"; import "AbstractSingularDTVFund.sol"; import "AbstractSingularDTVCrowdfunding.sol"; /// @title Crowdfunding contract - Implements crowdfunding functionality. /// @author Stefan George - <stefan.george@consensys.net> contract SingularDTVWeifund is Campaign { /* * External contracts */ SingularDTVFund constant singularDTVFund = SingularDTVFund({{SingularDTVFund}}); SingularDTVCrowdfunding constant singularDTVCrowdfunding = SingularDTVCrowdfunding({{SingularDTVCrowdfunding}}); string constant public name = "SingularDTV Campaign"; string constant public contributeMethodABI = "fund()"; string constant public refundMethodABI = "withdrawFunding()"; string constant public payoutMethodABI = "withdrawForWorkshop()"; /// @notice use to determine the beneficiary destination for the campaign /// @return the beneficiary address that will receive the campaign payout function beneficiary() constant returns(address) { return singularDTVFund.workshop(); } /// @notice the time at which the campaign fails or succeeds /// @return the uint unix timestamp at which time the campaign expires function expiry() constant returns(uint256 timestamp) { return singularDTVCrowdfunding.startDate() + singularDTVCrowdfunding.CROWDFUNDING_PERIOD(); } /// @notice the goal the campaign must reach in order for it to succeed /// @return the campaign funding goal specified in wei as a uint256 function fundingGoal() constant returns(uint256 amount) { return singularDTVCrowdfunding.TOKEN_TARGET() * singularDTVCrowdfunding.valuePerShare(); } /// @notice the goal the campaign must reach in order for it to succeed /// @return the campaign funding goal specified in wei as a uint256 function amountRaised() constant returns(uint256 amount) { return singularDTVCrowdfunding.fundBalance(); } } |
MistWallet.sol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 |
//sol Wallet // Multi-sig, daily-limited account proxy/wallet. // @authors: // Gav Wood <g@ethdev.com> // inheritable "property" contract that enables methods to be protected by requiring the acquiescence of either a // single, or, crucially, each of a number of, designated owners. // usage: // use modifiers onlyowner (just own owned) or onlymanyowners(hash), whereby the same hash must be provided by // some number (specified in constructor) of the set of owners (specified in the constructor, modifiable) before the // interior is executed. contract multiowned { // TYPES // struct for the status of a pending operation. struct PendingState { uint yetNeeded; uint ownersDone; uint index; } // EVENTS // this contract only has five types of events: it can accept a confirmation, in which case // we record owner and operation (hash) alongside it. event Confirmation(address owner, bytes32 operation); event Revoke(address owner, bytes32 operation); // some others are in the case of an owner changing. event OwnerChanged(address oldOwner, address newOwner); event OwnerAdded(address newOwner); event OwnerRemoved(address oldOwner); // the last one is emitted if the required signatures change event RequirementChanged(uint newRequirement); // MODIFIERS // simple single-sig function modifier. modifier onlyowner { if (isOwner(msg.sender)) _ } // multi-sig function modifier: the operation must have an intrinsic hash in order // that later attempts can be realised as the same underlying operation and // thus count as confirmations. modifier onlymanyowners(bytes32 _operation) { if (confirmAndCheck(_operation)) _ } // METHODS // constructor is given number of sigs required to do protected "onlymanyowners" transactions // as well as the selection of addresses capable of confirming them. function multiowned(address[] _owners, uint _required) { m_numOwners = _owners.length + 1; m_owners[1] = uint(msg.sender); m_ownerIndex[uint(msg.sender)] = 1; for (uint i = 0; i < _owners.length; ++i) { m_owners[2 + i] = uint(_owners[i]); m_ownerIndex[uint(_owners[i])] = 2 + i; } m_required = _required; } // Revokes a prior confirmation of the given operation function revoke(bytes32 _operation) external { uint ownerIndex = m_ownerIndex[uint(msg.sender)]; // make sure they're an owner if (ownerIndex == 0) return; uint ownerIndexBit = 2**ownerIndex; var pending = m_pending[_operation]; if (pending.ownersDone & ownerIndexBit > 0) { pending.yetNeeded++; pending.ownersDone -= ownerIndexBit; Revoke(msg.sender, _operation); } } // Replaces an owner `_from` with another `_to`. function changeOwner(address _from, address _to) onlymanyowners(sha3(msg.data)) external { if (isOwner(_to)) return; uint ownerIndex = m_ownerIndex[uint(_from)]; if (ownerIndex == 0) return; clearPending(); m_owners[ownerIndex] = uint(_to); m_ownerIndex[uint(_from)] = 0; m_ownerIndex[uint(_to)] = ownerIndex; OwnerChanged(_from, _to); } function addOwner(address _owner) onlymanyowners(sha3(msg.data)) external { if (isOwner(_owner)) return; clearPending(); if (m_numOwners >= c_maxOwners) reorganizeOwners(); if (m_numOwners >= c_maxOwners) return; m_numOwners++; m_owners[m_numOwners] = uint(_owner); m_ownerIndex[uint(_owner)] = m_numOwners; OwnerAdded(_owner); } function removeOwner(address _owner) onlymanyowners(sha3(msg.data)) external { uint ownerIndex = m_ownerIndex[uint(_owner)]; if (ownerIndex == 0) return; if (m_required > m_numOwners - 1) return; m_owners[ownerIndex] = 0; m_ownerIndex[uint(_owner)] = 0; clearPending(); reorganizeOwners(); //make sure m_numOwner is equal to the number of owners and always points to the optimal free slot OwnerRemoved(_owner); } function changeRequirement(uint _newRequired) onlymanyowners(sha3(msg.data)) external { if (_newRequired > m_numOwners) return; m_required = _newRequired; clearPending(); RequirementChanged(_newRequired); } function isOwner(address _addr) returns (bool) { return m_ownerIndex[uint(_addr)] > 0; } function hasConfirmed(bytes32 _operation, address _owner) constant returns (bool) { var pending = m_pending[_operation]; uint ownerIndex = m_ownerIndex[uint(_owner)]; // make sure they're an owner if (ownerIndex == 0) return false; // determine the bit to set for this owner. uint ownerIndexBit = 2**ownerIndex; return !(pending.ownersDone & ownerIndexBit == 0); } // INTERNAL METHODS function confirmAndCheck(bytes32 _operation) internal returns (bool) { // determine what index the present sender is: uint ownerIndex = m_ownerIndex[uint(msg.sender)]; // make sure they're an owner if (ownerIndex == 0) return; var pending = m_pending[_operation]; // if we're not yet working on this operation, switch over and reset the confirmation status. if (pending.yetNeeded == 0) { // reset count of confirmations needed. pending.yetNeeded = m_required; // reset which owners have confirmed (none) - set our bitmap to 0. pending.ownersDone = 0; pending.index = m_pendingIndex.length++; m_pendingIndex[pending.index] = _operation; } // determine the bit to set for this owner. uint ownerIndexBit = 2**ownerIndex; // make sure we (the message sender) haven't confirmed this operation previously. if (pending.ownersDone & ownerIndexBit == 0) { Confirmation(msg.sender, _operation); // ok - check if count is enough to go ahead. if (pending.yetNeeded <= 1) { // enough confirmations: reset and run interior. delete m_pendingIndex[m_pending[_operation].index]; delete m_pending[_operation]; return true; } else { // not enough: record that this owner in particular confirmed. pending.yetNeeded--; pending.ownersDone |= ownerIndexBit; } } } function reorganizeOwners() private { uint free = 1; while (free < m_numOwners) { while (free < m_numOwners && m_owners[free] != 0) free++; while (m_numOwners > 1 && m_owners[m_numOwners] == 0) m_numOwners--; if (free < m_numOwners && m_owners[m_numOwners] != 0 && m_owners[free] == 0) { m_owners[free] = m_owners[m_numOwners]; m_ownerIndex[m_owners[free]] = free; m_owners[m_numOwners] = 0; } } } function clearPending() internal { uint length = m_pendingIndex.length; for (uint i = 0; i < length; ++i) if (m_pendingIndex[i] != 0) delete m_pending[m_pendingIndex[i]]; delete m_pendingIndex; } // FIELDS // the number of owners that must confirm the same operation before it is run. uint public m_required; // pointer used to find a free slot in m_owners uint public m_numOwners; // list of owners uint[256] m_owners; uint constant c_maxOwners = 250; // index on the list of owners to allow reverse lookup mapping(uint => uint) m_ownerIndex; // the ongoing operations. mapping(bytes32 => PendingState) m_pending; bytes32[] m_pendingIndex; } // inheritable "property" contract that enables methods to be protected by placing a linear limit (specifiable) // on a particular resource per calendar day. is multiowned to allow the limit to be altered. resource that method // uses is specified in the modifier. contract daylimit is multiowned { // MODIFIERS // simple modifier for daily limit. modifier limitedDaily(uint _value) { if (underLimit(_value)) _ } // METHODS // constructor - stores initial daily limit and records the present day's index. function daylimit(uint _limit) { m_dailyLimit = _limit; m_lastDay = today(); } // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. function setDailyLimit(uint _newLimit) onlymanyowners(sha3(msg.data)) external { m_dailyLimit = _newLimit; } // (re)sets the daily limit. needs many of the owners to confirm. doesn't alter the amount already spent today. function resetSpentToday() onlymanyowners(sha3(msg.data)) external { m_spentToday = 0; } // INTERNAL METHODS // checks to see if there is at least `_value` left from the daily limit today. if there is, subtracts it and // returns true. otherwise just returns false. function underLimit(uint _value) internal onlyowner returns (bool) { // reset the spend limit if we're on a different day to last time. if (today() > m_lastDay) { m_spentToday = 0; m_lastDay = today(); } // check to see if there's enough left - if so, subtract and return true. if (m_spentToday + _value >= m_spentToday && m_spentToday + _value <= m_dailyLimit) { m_spentToday += _value; return true; } return false; } // determines today's index. function today() private constant returns (uint) { return now / 1 days; } // FIELDS uint public m_dailyLimit; uint m_spentToday; uint m_lastDay; } // interface contract for multisig proxy contracts; see below for docs. contract multisig { // EVENTS // logged events: // Funds has arrived into the wallet (record how much). event Deposit(address _from, uint value); // Single transaction going out of the wallet (record who signed for it, how much, and to whom it's going). event SingleTransact(address owner, uint value, address to, bytes data); // Multi-sig transaction going out of the wallet (record who signed for it last, the operation hash, how much, and to whom it's going). event MultiTransact(address owner, bytes32 operation, uint value, address to, bytes data); // Confirmation still needed for a transaction. event ConfirmationNeeded(bytes32 operation, address initiator, uint value, address to, bytes data); // FUNCTIONS // TODO: document function changeOwner(address _from, address _to) external; function execute(address _to, uint _value, bytes _data) external returns (bytes32); function confirm(bytes32 _h) returns (bool); } // usage: // bytes32 h = Wallet(w).from(oneOwner).transact(to, value, data); // Wallet(w).from(anotherOwner).confirm(h); contract Wallet is multisig, multiowned, daylimit { // TYPES // Transaction structure to remember details of transaction lest it need be saved for a later call. struct Transaction { address to; uint value; bytes data; } // METHODS // constructor - just pass on the owner array to the multiowned and // the limit to daylimit function Wallet(address[] _owners, uint _required, uint _daylimit) multiowned(_owners, _required) daylimit(_daylimit) { } // kills the contract sending everything to `_to`. function kill(address _to) onlymanyowners(sha3(msg.data)) external { suicide(_to); } // gets called when no other function matches function() { // just being sent some cash? if (msg.value > 0) Deposit(msg.sender, msg.value); } // Outside-visible transact entry point. Executes transacion immediately if below daily spend limit. // If not, goes into multisig process. We provide a hash on return to allow the sender to provide // shortcuts for the other confirmations (allowing them to avoid replicating the _to, _value // and _data arguments). They still get the option of using them if they want, anyways. function execute(address _to, uint _value, bytes _data) external onlyowner returns (bytes32 _r) { // first, take the opportunity to check that we're under the daily limit. if (underLimit(_value)) { SingleTransact(msg.sender, _value, _to, _data); // yes - just execute the call. _to.call.value(_value)(_data); return 0; } // determine our operation hash. _r = sha3(msg.data, block.number); if (!confirm(_r) && m_txs[_r].to == 0) { m_txs[_r].to = _to; m_txs[_r].value = _value; m_txs[_r].data = _data; ConfirmationNeeded(_r, msg.sender, _value, _to, _data); } } // confirm a transaction through just the hash. we use the previous transactions map, m_txs, in order // to determine the body of the transaction from the hash provided. function confirm(bytes32 _h) onlymanyowners(_h) returns (bool) { if (m_txs[_h].to != 0) { m_txs[_h].to.call.value(m_txs[_h].value)(m_txs[_h].data); MultiTransact(msg.sender, _h, m_txs[_h].value, m_txs[_h].to, m_txs[_h].data); delete m_txs[_h]; return true; } } // INTERNAL METHODS function clearPending() internal { uint length = m_pendingIndex.length; for (uint i = 0; i < length; ++i) delete m_txs[m_pendingIndex[i]]; super.clearPending(); } // FIELDS // pending transactions we have at present. mapping (bytes32 => Transaction) m_txs; } |