├── .gitattributes ├── CryptoPunksMarket.sol ├── Cryptostamp.sol ├── Dice2Win.sol ├── FckDice.sol ├── GandhiJi.sol ├── GodsUnchained.sol ├── GradualPonzi.sol ├── KingOfTheEtherThrone.sol ├── PonzICO.sol ├── PonziGovernmental.sol ├── PyramidGame.sol ├── README.md ├── SimplePonzi.sol ├── SimplePyramid.sol └── utils ├── Addresses.sol ├── Integers.sol └── Strings.sol /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /CryptoPunksMarket.sol: -------------------------------------------------------------------------------- 1 | //////////// 2 | // see https://github.com/larvalabs/cryptopunks/tree/master/contracts 3 | 4 | pragma solidity ^0.4.8; 5 | contract CryptoPunksMarket { 6 | 7 | // You can use this hash to verify the image file containing all the punks 8 | string public imageHash = "ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b"; 9 | 10 | address owner; 11 | 12 | string public standard = 'CryptoPunks'; 13 | string public name; 14 | string public symbol; 15 | uint8 public decimals; 16 | uint256 public totalSupply; 17 | 18 | uint public nextPunkIndexToAssign = 0; 19 | 20 | bool public allPunksAssigned = false; 21 | uint public punksRemainingToAssign = 0; 22 | 23 | //mapping (address => uint) public addressToPunkIndex; 24 | mapping (uint => address) public punkIndexToAddress; 25 | 26 | /* This creates an array with all balances */ 27 | mapping (address => uint256) public balanceOf; 28 | 29 | struct Offer { 30 | bool isForSale; 31 | uint punkIndex; 32 | address seller; 33 | uint minValue; // in ether 34 | address onlySellTo; // specify to sell only to a specific person 35 | } 36 | 37 | struct Bid { 38 | bool hasBid; 39 | uint punkIndex; 40 | address bidder; 41 | uint value; 42 | } 43 | 44 | // A record of punks that are offered for sale at a specific minimum value, and perhaps to a specific person 45 | mapping (uint => Offer) public punksOfferedForSale; 46 | 47 | // A record of the highest punk bid 48 | mapping (uint => Bid) public punkBids; 49 | 50 | mapping (address => uint) public pendingWithdrawals; 51 | 52 | event Assign(address indexed to, uint256 punkIndex); 53 | event Transfer(address indexed from, address indexed to, uint256 value); 54 | event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex); 55 | event PunkOffered(uint indexed punkIndex, uint minValue, address indexed toAddress); 56 | event PunkBidEntered(uint indexed punkIndex, uint value, address indexed fromAddress); 57 | event PunkBidWithdrawn(uint indexed punkIndex, uint value, address indexed fromAddress); 58 | event PunkBought(uint indexed punkIndex, uint value, address indexed fromAddress, address indexed toAddress); 59 | event PunkNoLongerForSale(uint indexed punkIndex); 60 | 61 | /* Initializes contract with initial supply tokens to the creator of the contract */ 62 | function CryptoPunksMarket() payable { 63 | // balanceOf[msg.sender] = initialSupply; // Give the creator all initial tokens 64 | owner = msg.sender; 65 | totalSupply = 10000; // Update total supply 66 | punksRemainingToAssign = totalSupply; 67 | name = "CRYPTOPUNKS"; // Set the name for display purposes 68 | symbol = "Ͼ"; // Set the symbol for display purposes 69 | decimals = 0; // Amount of decimals for display purposes 70 | } 71 | 72 | function setInitialOwner(address to, uint punkIndex) { 73 | if (msg.sender != owner) throw; 74 | if (allPunksAssigned) throw; 75 | if (punkIndex >= 10000) throw; 76 | if (punkIndexToAddress[punkIndex] != to) { 77 | if (punkIndexToAddress[punkIndex] != 0x0) { 78 | balanceOf[punkIndexToAddress[punkIndex]]--; 79 | } else { 80 | punksRemainingToAssign--; 81 | } 82 | punkIndexToAddress[punkIndex] = to; 83 | balanceOf[to]++; 84 | Assign(to, punkIndex); 85 | } 86 | } 87 | 88 | function setInitialOwners(address[] addresses, uint[] indices) { 89 | if (msg.sender != owner) throw; 90 | uint n = addresses.length; 91 | for (uint i = 0; i < n; i++) { 92 | setInitialOwner(addresses[i], indices[i]); 93 | } 94 | } 95 | 96 | function allInitialOwnersAssigned() { 97 | if (msg.sender != owner) throw; 98 | allPunksAssigned = true; 99 | } 100 | 101 | function getPunk(uint punkIndex) { 102 | if (!allPunksAssigned) throw; 103 | if (punksRemainingToAssign == 0) throw; 104 | if (punkIndexToAddress[punkIndex] != 0x0) throw; 105 | if (punkIndex >= 10000) throw; 106 | punkIndexToAddress[punkIndex] = msg.sender; 107 | balanceOf[msg.sender]++; 108 | punksRemainingToAssign--; 109 | Assign(msg.sender, punkIndex); 110 | } 111 | 112 | // Transfer ownership of a punk to another user without requiring payment 113 | function transferPunk(address to, uint punkIndex) { 114 | if (!allPunksAssigned) throw; 115 | if (punkIndexToAddress[punkIndex] != msg.sender) throw; 116 | if (punkIndex >= 10000) throw; 117 | if (punksOfferedForSale[punkIndex].isForSale) { 118 | punkNoLongerForSale(punkIndex); 119 | } 120 | punkIndexToAddress[punkIndex] = to; 121 | balanceOf[msg.sender]--; 122 | balanceOf[to]++; 123 | Transfer(msg.sender, to, 1); 124 | PunkTransfer(msg.sender, to, punkIndex); 125 | // Check for the case where there is a bid from the new owner and refund it. 126 | // Any other bid can stay in place. 127 | Bid bid = punkBids[punkIndex]; 128 | if (bid.bidder == to) { 129 | // Kill bid and refund value 130 | pendingWithdrawals[to] += bid.value; 131 | punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); 132 | } 133 | } 134 | 135 | function punkNoLongerForSale(uint punkIndex) { 136 | if (!allPunksAssigned) throw; 137 | if (punkIndexToAddress[punkIndex] != msg.sender) throw; 138 | if (punkIndex >= 10000) throw; 139 | punksOfferedForSale[punkIndex] = Offer(false, punkIndex, msg.sender, 0, 0x0); 140 | PunkNoLongerForSale(punkIndex); 141 | } 142 | 143 | function offerPunkForSale(uint punkIndex, uint minSalePriceInWei) { 144 | if (!allPunksAssigned) throw; 145 | if (punkIndexToAddress[punkIndex] != msg.sender) throw; 146 | if (punkIndex >= 10000) throw; 147 | punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, 0x0); 148 | PunkOffered(punkIndex, minSalePriceInWei, 0x0); 149 | } 150 | 151 | function offerPunkForSaleToAddress(uint punkIndex, uint minSalePriceInWei, address toAddress) { 152 | if (!allPunksAssigned) throw; 153 | if (punkIndexToAddress[punkIndex] != msg.sender) throw; 154 | if (punkIndex >= 10000) throw; 155 | punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, toAddress); 156 | PunkOffered(punkIndex, minSalePriceInWei, toAddress); 157 | } 158 | 159 | function buyPunk(uint punkIndex) payable { 160 | if (!allPunksAssigned) throw; 161 | Offer offer = punksOfferedForSale[punkIndex]; 162 | if (punkIndex >= 10000) throw; 163 | if (!offer.isForSale) throw; // punk not actually for sale 164 | if (offer.onlySellTo != 0x0 && offer.onlySellTo != msg.sender) throw; // punk not supposed to be sold to this user 165 | if (msg.value < offer.minValue) throw; // Didn't send enough ETH 166 | if (offer.seller != punkIndexToAddress[punkIndex]) throw; // Seller no longer owner of punk 167 | 168 | address seller = offer.seller; 169 | 170 | punkIndexToAddress[punkIndex] = msg.sender; 171 | balanceOf[seller]--; 172 | balanceOf[msg.sender]++; 173 | Transfer(seller, msg.sender, 1); 174 | 175 | punkNoLongerForSale(punkIndex); 176 | pendingWithdrawals[seller] += msg.value; 177 | PunkBought(punkIndex, msg.value, seller, msg.sender); 178 | 179 | // Check for the case where there is a bid from the new owner and refund it. 180 | // Any other bid can stay in place. 181 | Bid bid = punkBids[punkIndex]; 182 | if (bid.bidder == msg.sender) { 183 | // Kill bid and refund value 184 | pendingWithdrawals[msg.sender] += bid.value; 185 | punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); 186 | } 187 | } 188 | 189 | function withdraw() { 190 | if (!allPunksAssigned) throw; 191 | uint amount = pendingWithdrawals[msg.sender]; 192 | // Remember to zero the pending refund before 193 | // sending to prevent re-entrancy attacks 194 | pendingWithdrawals[msg.sender] = 0; 195 | msg.sender.transfer(amount); 196 | } 197 | 198 | function enterBidForPunk(uint punkIndex) payable { 199 | if (punkIndex >= 10000) throw; 200 | if (!allPunksAssigned) throw; 201 | if (punkIndexToAddress[punkIndex] == 0x0) throw; 202 | if (punkIndexToAddress[punkIndex] == msg.sender) throw; 203 | if (msg.value == 0) throw; 204 | Bid existing = punkBids[punkIndex]; 205 | if (msg.value <= existing.value) throw; 206 | if (existing.value > 0) { 207 | // Refund the failing bid 208 | pendingWithdrawals[existing.bidder] += existing.value; 209 | } 210 | punkBids[punkIndex] = Bid(true, punkIndex, msg.sender, msg.value); 211 | PunkBidEntered(punkIndex, msg.value, msg.sender); 212 | } 213 | 214 | function acceptBidForPunk(uint punkIndex, uint minPrice) { 215 | if (punkIndex >= 10000) throw; 216 | if (!allPunksAssigned) throw; 217 | if (punkIndexToAddress[punkIndex] != msg.sender) throw; 218 | address seller = msg.sender; 219 | Bid bid = punkBids[punkIndex]; 220 | if (bid.value == 0) throw; 221 | if (bid.value < minPrice) throw; 222 | 223 | punkIndexToAddress[punkIndex] = bid.bidder; 224 | balanceOf[seller]--; 225 | balanceOf[bid.bidder]++; 226 | Transfer(seller, bid.bidder, 1); 227 | 228 | punksOfferedForSale[punkIndex] = Offer(false, punkIndex, bid.bidder, 0, 0x0); 229 | uint amount = bid.value; 230 | punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); 231 | pendingWithdrawals[seller] += amount; 232 | PunkBought(punkIndex, bid.value, seller, bid.bidder); 233 | } 234 | 235 | function withdrawBidForPunk(uint punkIndex) { 236 | if (punkIndex >= 10000) throw; 237 | if (!allPunksAssigned) throw; 238 | if (punkIndexToAddress[punkIndex] == 0x0) throw; 239 | if (punkIndexToAddress[punkIndex] == msg.sender) throw; 240 | Bid bid = punkBids[punkIndex]; 241 | if (bid.bidder != msg.sender) throw; 242 | PunkBidWithdrawn(punkIndex, bid.value, msg.sender); 243 | uint amount = bid.value; 244 | punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); 245 | // Refund the bid money 246 | msg.sender.transfer(amount); 247 | } 248 | 249 | } 250 | -------------------------------------------------------------------------------- /Cryptostamp.sol: -------------------------------------------------------------------------------- 1 | //////// 2 | // see https://etherscan.io/address/0x7e789E2dd1340971De0A9bca35b14AC0939Aa330#code 3 | 4 | /* 5 | * Crypto stamp 6 | * Digitalphysical collectible postage stamp 7 | * 8 | * Developed by capacity.at for post.at 9 | */ 10 | 11 | // File: openzeppelin-solidity/contracts/introspection/IERC165.sol 12 | 13 | pragma solidity ^0.5.0; 14 | 15 | /** 16 | * @title IERC165 17 | * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md 18 | */ 19 | interface IERC165 { 20 | /** 21 | * @notice Query if a contract implements an interface 22 | * @param interfaceId The interface identifier, as specified in ERC-165 23 | * @dev Interface identification is specified in ERC-165. This function 24 | * uses less than 30,000 gas. 25 | */ 26 | function supportsInterface(bytes4 interfaceId) external view returns (bool); 27 | } 28 | 29 | // File: openzeppelin-solidity/contracts/token/ERC721/IERC721.sol 30 | 31 | pragma solidity ^0.5.0; 32 | 33 | 34 | /** 35 | * @title ERC721 Non-Fungible Token Standard basic interface 36 | * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 37 | */ 38 | contract IERC721 is IERC165 { 39 | event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); 40 | event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); 41 | event ApprovalForAll(address indexed owner, address indexed operator, bool approved); 42 | 43 | function balanceOf(address owner) public view returns (uint256 balance); 44 | function ownerOf(uint256 tokenId) public view returns (address owner); 45 | 46 | function approve(address to, uint256 tokenId) public; 47 | function getApproved(uint256 tokenId) public view returns (address operator); 48 | 49 | function setApprovalForAll(address operator, bool _approved) public; 50 | function isApprovedForAll(address owner, address operator) public view returns (bool); 51 | 52 | function transferFrom(address from, address to, uint256 tokenId) public; 53 | function safeTransferFrom(address from, address to, uint256 tokenId) public; 54 | 55 | function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public; 56 | } 57 | 58 | // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Receiver.sol 59 | 60 | pragma solidity ^0.5.0; 61 | 62 | /** 63 | * @title ERC721 token receiver interface 64 | * @dev Interface for any contract that wants to support safeTransfers 65 | * from ERC721 asset contracts. 66 | */ 67 | contract IERC721Receiver { 68 | /** 69 | * @notice Handle the receipt of an NFT 70 | * @dev The ERC721 smart contract calls this function on the recipient 71 | * after a `safeTransfer`. This function MUST return the function selector, 72 | * otherwise the caller will revert the transaction. The selector to be 73 | * returned can be obtained as `this.onERC721Received.selector`. This 74 | * function MAY throw to revert and reject the transfer. 75 | * Note: the ERC721 contract address is always the message sender. 76 | * @param operator The address which called `safeTransferFrom` function 77 | * @param from The address which previously owned the token 78 | * @param tokenId The NFT identifier which is being transferred 79 | * @param data Additional data with no specified format 80 | * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 81 | */ 82 | function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) 83 | public returns (bytes4); 84 | } 85 | 86 | // File: openzeppelin-solidity/contracts/math/SafeMath.sol 87 | 88 | pragma solidity ^0.5.0; 89 | 90 | /** 91 | * @title SafeMath 92 | * @dev Unsigned math operations with safety checks that revert on error 93 | */ 94 | library SafeMath { 95 | /** 96 | * @dev Multiplies two unsigned integers, reverts on overflow. 97 | */ 98 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 99 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 100 | // benefit is lost if 'b' is also tested. 101 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 102 | if (a == 0) { 103 | return 0; 104 | } 105 | 106 | uint256 c = a * b; 107 | require(c / a == b); 108 | 109 | return c; 110 | } 111 | 112 | /** 113 | * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. 114 | */ 115 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 116 | // Solidity only automatically asserts when dividing by 0 117 | require(b > 0); 118 | uint256 c = a / b; 119 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 120 | 121 | return c; 122 | } 123 | 124 | /** 125 | * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). 126 | */ 127 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 128 | require(b <= a); 129 | uint256 c = a - b; 130 | 131 | return c; 132 | } 133 | 134 | /** 135 | * @dev Adds two unsigned integers, reverts on overflow. 136 | */ 137 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 138 | uint256 c = a + b; 139 | require(c >= a); 140 | 141 | return c; 142 | } 143 | 144 | /** 145 | * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), 146 | * reverts when dividing by zero. 147 | */ 148 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 149 | require(b != 0); 150 | return a % b; 151 | } 152 | } 153 | 154 | // File: openzeppelin-solidity/contracts/utils/Address.sol 155 | 156 | pragma solidity ^0.5.0; 157 | 158 | /** 159 | * Utility library of inline functions on addresses 160 | */ 161 | library Address { 162 | /** 163 | * Returns whether the target address is a contract 164 | * @dev This function will return false if invoked during the constructor of a contract, 165 | * as the code is not actually created until after the constructor finishes. 166 | * @param account address of the account to check 167 | * @return whether the target address is a contract 168 | */ 169 | function isContract(address account) internal view returns (bool) { 170 | uint256 size; 171 | // XXX Currently there is no better way to check if there is a contract in an address 172 | // than to check the size of the code at that address. 173 | // See https://ethereum.stackexchange.com/a/14016/36603 174 | // for more details about how this works. 175 | // TODO Check this again before the Serenity release, because all addresses will be 176 | // contracts then. 177 | // solhint-disable-next-line no-inline-assembly 178 | assembly { size := extcodesize(account) } 179 | return size > 0; 180 | } 181 | } 182 | 183 | // File: openzeppelin-solidity/contracts/introspection/ERC165.sol 184 | 185 | pragma solidity ^0.5.0; 186 | 187 | 188 | /** 189 | * @title ERC165 190 | * @author Matt Condon (@shrugs) 191 | * @dev Implements ERC165 using a lookup table. 192 | */ 193 | contract ERC165 is IERC165 { 194 | bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; 195 | /** 196 | * 0x01ffc9a7 === 197 | * bytes4(keccak256('supportsInterface(bytes4)')) 198 | */ 199 | 200 | /** 201 | * @dev a mapping of interface id to whether or not it's supported 202 | */ 203 | mapping(bytes4 => bool) private _supportedInterfaces; 204 | 205 | /** 206 | * @dev A contract implementing SupportsInterfaceWithLookup 207 | * implement ERC165 itself 208 | */ 209 | constructor () internal { 210 | _registerInterface(_INTERFACE_ID_ERC165); 211 | } 212 | 213 | /** 214 | * @dev implement supportsInterface(bytes4) using a lookup table 215 | */ 216 | function supportsInterface(bytes4 interfaceId) external view returns (bool) { 217 | return _supportedInterfaces[interfaceId]; 218 | } 219 | 220 | /** 221 | * @dev internal method for registering an interface 222 | */ 223 | function _registerInterface(bytes4 interfaceId) internal { 224 | require(interfaceId != 0xffffffff); 225 | _supportedInterfaces[interfaceId] = true; 226 | } 227 | } 228 | 229 | // File: openzeppelin-solidity/contracts/token/ERC721/ERC721.sol 230 | 231 | pragma solidity ^0.5.0; 232 | 233 | 234 | 235 | 236 | 237 | 238 | /** 239 | * @title ERC721 Non-Fungible Token Standard basic implementation 240 | * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 241 | */ 242 | contract ERC721 is ERC165, IERC721 { 243 | using SafeMath for uint256; 244 | using Address for address; 245 | 246 | // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` 247 | // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector` 248 | bytes4 private constant _ERC721_RECEIVED = 0x150b7a02; 249 | 250 | // Mapping from token ID to owner 251 | mapping (uint256 => address) private _tokenOwner; 252 | 253 | // Mapping from token ID to approved address 254 | mapping (uint256 => address) private _tokenApprovals; 255 | 256 | // Mapping from owner to number of owned token 257 | mapping (address => uint256) private _ownedTokensCount; 258 | 259 | // Mapping from owner to operator approvals 260 | mapping (address => mapping (address => bool)) private _operatorApprovals; 261 | 262 | bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd; 263 | /* 264 | * 0x80ac58cd === 265 | * bytes4(keccak256('balanceOf(address)')) ^ 266 | * bytes4(keccak256('ownerOf(uint256)')) ^ 267 | * bytes4(keccak256('approve(address,uint256)')) ^ 268 | * bytes4(keccak256('getApproved(uint256)')) ^ 269 | * bytes4(keccak256('setApprovalForAll(address,bool)')) ^ 270 | * bytes4(keccak256('isApprovedForAll(address,address)')) ^ 271 | * bytes4(keccak256('transferFrom(address,address,uint256)')) ^ 272 | * bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^ 273 | * bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) 274 | */ 275 | 276 | constructor () public { 277 | // register the supported interfaces to conform to ERC721 via ERC165 278 | _registerInterface(_INTERFACE_ID_ERC721); 279 | } 280 | 281 | /** 282 | * @dev Gets the balance of the specified address 283 | * @param owner address to query the balance of 284 | * @return uint256 representing the amount owned by the passed address 285 | */ 286 | function balanceOf(address owner) public view returns (uint256) { 287 | require(owner != address(0)); 288 | return _ownedTokensCount[owner]; 289 | } 290 | 291 | /** 292 | * @dev Gets the owner of the specified token ID 293 | * @param tokenId uint256 ID of the token to query the owner of 294 | * @return owner address currently marked as the owner of the given token ID 295 | */ 296 | function ownerOf(uint256 tokenId) public view returns (address) { 297 | address owner = _tokenOwner[tokenId]; 298 | require(owner != address(0)); 299 | return owner; 300 | } 301 | 302 | /** 303 | * @dev Approves another address to transfer the given token ID 304 | * The zero address indicates there is no approved address. 305 | * There can only be one approved address per token at a given time. 306 | * Can only be called by the token owner or an approved operator. 307 | * @param to address to be approved for the given token ID 308 | * @param tokenId uint256 ID of the token to be approved 309 | */ 310 | function approve(address to, uint256 tokenId) public { 311 | address owner = ownerOf(tokenId); 312 | require(to != owner); 313 | require(msg.sender == owner || isApprovedForAll(owner, msg.sender)); 314 | 315 | _tokenApprovals[tokenId] = to; 316 | emit Approval(owner, to, tokenId); 317 | } 318 | 319 | /** 320 | * @dev Gets the approved address for a token ID, or zero if no address set 321 | * Reverts if the token ID does not exist. 322 | * @param tokenId uint256 ID of the token to query the approval of 323 | * @return address currently approved for the given token ID 324 | */ 325 | function getApproved(uint256 tokenId) public view returns (address) { 326 | require(_exists(tokenId)); 327 | return _tokenApprovals[tokenId]; 328 | } 329 | 330 | /** 331 | * @dev Sets or unsets the approval of a given operator 332 | * An operator is allowed to transfer all tokens of the sender on their behalf 333 | * @param to operator address to set the approval 334 | * @param approved representing the status of the approval to be set 335 | */ 336 | function setApprovalForAll(address to, bool approved) public { 337 | require(to != msg.sender); 338 | _operatorApprovals[msg.sender][to] = approved; 339 | emit ApprovalForAll(msg.sender, to, approved); 340 | } 341 | 342 | /** 343 | * @dev Tells whether an operator is approved by a given owner 344 | * @param owner owner address which you want to query the approval of 345 | * @param operator operator address which you want to query the approval of 346 | * @return bool whether the given operator is approved by the given owner 347 | */ 348 | function isApprovedForAll(address owner, address operator) public view returns (bool) { 349 | return _operatorApprovals[owner][operator]; 350 | } 351 | 352 | /** 353 | * @dev Transfers the ownership of a given token ID to another address 354 | * Usage of this method is discouraged, use `safeTransferFrom` whenever possible 355 | * Requires the msg sender to be the owner, approved, or operator 356 | * @param from current owner of the token 357 | * @param to address to receive the ownership of the given token ID 358 | * @param tokenId uint256 ID of the token to be transferred 359 | */ 360 | function transferFrom(address from, address to, uint256 tokenId) public { 361 | require(_isApprovedOrOwner(msg.sender, tokenId)); 362 | 363 | _transferFrom(from, to, tokenId); 364 | } 365 | 366 | /** 367 | * @dev Safely transfers the ownership of a given token ID to another address 368 | * If the target address is a contract, it must implement `onERC721Received`, 369 | * which is called upon a safe transfer, and return the magic value 370 | * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, 371 | * the transfer is reverted. 372 | * 373 | * Requires the msg sender to be the owner, approved, or operator 374 | * @param from current owner of the token 375 | * @param to address to receive the ownership of the given token ID 376 | * @param tokenId uint256 ID of the token to be transferred 377 | */ 378 | function safeTransferFrom(address from, address to, uint256 tokenId) public { 379 | safeTransferFrom(from, to, tokenId, ""); 380 | } 381 | 382 | /** 383 | * @dev Safely transfers the ownership of a given token ID to another address 384 | * If the target address is a contract, it must implement `onERC721Received`, 385 | * which is called upon a safe transfer, and return the magic value 386 | * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise, 387 | * the transfer is reverted. 388 | * Requires the msg sender to be the owner, approved, or operator 389 | * @param from current owner of the token 390 | * @param to address to receive the ownership of the given token ID 391 | * @param tokenId uint256 ID of the token to be transferred 392 | * @param _data bytes data to send along with a safe transfer check 393 | */ 394 | function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public { 395 | transferFrom(from, to, tokenId); 396 | require(_checkOnERC721Received(from, to, tokenId, _data)); 397 | } 398 | 399 | /** 400 | * @dev Returns whether the specified token exists 401 | * @param tokenId uint256 ID of the token to query the existence of 402 | * @return whether the token exists 403 | */ 404 | function _exists(uint256 tokenId) internal view returns (bool) { 405 | address owner = _tokenOwner[tokenId]; 406 | return owner != address(0); 407 | } 408 | 409 | /** 410 | * @dev Returns whether the given spender can transfer a given token ID 411 | * @param spender address of the spender to query 412 | * @param tokenId uint256 ID of the token to be transferred 413 | * @return bool whether the msg.sender is approved for the given token ID, 414 | * is an operator of the owner, or is the owner of the token 415 | */ 416 | function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { 417 | address owner = ownerOf(tokenId); 418 | return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender)); 419 | } 420 | 421 | /** 422 | * @dev Internal function to mint a new token 423 | * Reverts if the given token ID already exists 424 | * @param to The address that will own the minted token 425 | * @param tokenId uint256 ID of the token to be minted 426 | */ 427 | function _mint(address to, uint256 tokenId) internal { 428 | require(to != address(0)); 429 | require(!_exists(tokenId)); 430 | 431 | _tokenOwner[tokenId] = to; 432 | _ownedTokensCount[to] = _ownedTokensCount[to].add(1); 433 | 434 | emit Transfer(address(0), to, tokenId); 435 | } 436 | 437 | /** 438 | * @dev Internal function to burn a specific token 439 | * Reverts if the token does not exist 440 | * Deprecated, use _burn(uint256) instead. 441 | * @param owner owner of the token to burn 442 | * @param tokenId uint256 ID of the token being burned 443 | */ 444 | function _burn(address owner, uint256 tokenId) internal { 445 | require(ownerOf(tokenId) == owner); 446 | 447 | _clearApproval(tokenId); 448 | 449 | _ownedTokensCount[owner] = _ownedTokensCount[owner].sub(1); 450 | _tokenOwner[tokenId] = address(0); 451 | 452 | emit Transfer(owner, address(0), tokenId); 453 | } 454 | 455 | /** 456 | * @dev Internal function to burn a specific token 457 | * Reverts if the token does not exist 458 | * @param tokenId uint256 ID of the token being burned 459 | */ 460 | function _burn(uint256 tokenId) internal { 461 | _burn(ownerOf(tokenId), tokenId); 462 | } 463 | 464 | /** 465 | * @dev Internal function to transfer ownership of a given token ID to another address. 466 | * As opposed to transferFrom, this imposes no restrictions on msg.sender. 467 | * @param from current owner of the token 468 | * @param to address to receive the ownership of the given token ID 469 | * @param tokenId uint256 ID of the token to be transferred 470 | */ 471 | function _transferFrom(address from, address to, uint256 tokenId) internal { 472 | require(ownerOf(tokenId) == from); 473 | require(to != address(0)); 474 | 475 | _clearApproval(tokenId); 476 | 477 | _ownedTokensCount[from] = _ownedTokensCount[from].sub(1); 478 | _ownedTokensCount[to] = _ownedTokensCount[to].add(1); 479 | 480 | _tokenOwner[tokenId] = to; 481 | 482 | emit Transfer(from, to, tokenId); 483 | } 484 | 485 | /** 486 | * @dev Internal function to invoke `onERC721Received` on a target address 487 | * The call is not executed if the target address is not a contract 488 | * @param from address representing the previous owner of the given token ID 489 | * @param to target address that will receive the tokens 490 | * @param tokenId uint256 ID of the token to be transferred 491 | * @param _data bytes optional data to send along with the call 492 | * @return whether the call correctly returned the expected magic value 493 | */ 494 | function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) 495 | internal returns (bool) 496 | { 497 | if (!to.isContract()) { 498 | return true; 499 | } 500 | 501 | bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data); 502 | return (retval == _ERC721_RECEIVED); 503 | } 504 | 505 | /** 506 | * @dev Private function to clear current approval of a given token ID 507 | * @param tokenId uint256 ID of the token to be transferred 508 | */ 509 | function _clearApproval(uint256 tokenId) private { 510 | if (_tokenApprovals[tokenId] != address(0)) { 511 | _tokenApprovals[tokenId] = address(0); 512 | } 513 | } 514 | } 515 | 516 | // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Enumerable.sol 517 | 518 | pragma solidity ^0.5.0; 519 | 520 | 521 | /** 522 | * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension 523 | * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 524 | */ 525 | contract IERC721Enumerable is IERC721 { 526 | function totalSupply() public view returns (uint256); 527 | function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256 tokenId); 528 | 529 | function tokenByIndex(uint256 index) public view returns (uint256); 530 | } 531 | 532 | // File: contracts/ERC721EnumerableSimple.sol 533 | 534 | pragma solidity ^0.5.0; 535 | 536 | /* This is a simplified (and cheaper) version of OpenZeppelin's ERC721Enumerable. 537 | * ERC721Enumerable's allTokens array and allTokensIndex mapping are eliminated. 538 | * Side effects: _burn cannot be used any more with this, and creation needs to be 539 | * in ascending order, starting with 0, and have no holes in the sequence of IDs. 540 | */ 541 | 542 | 543 | 544 | 545 | /** 546 | * @title ERC-721 Non-Fungible Token with optional enumeration extension logic 547 | * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 548 | */ 549 | contract ERC721EnumerableSimple is ERC165, ERC721, IERC721Enumerable { 550 | // Mapping from owner to list of owned token IDs 551 | mapping(address => uint256[]) private _ownedTokens; 552 | 553 | // Mapping from token ID to index of the owner tokens list 554 | mapping(uint256 => uint256) private _ownedTokensIndex; 555 | 556 | uint256 internal totalSupply_; 557 | 558 | bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63; 559 | /** 560 | * 0x780e9d63 === 561 | * bytes4(keccak256('totalSupply()')) ^ 562 | * bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^ 563 | * bytes4(keccak256('tokenByIndex(uint256)')) 564 | */ 565 | 566 | /** 567 | * @dev Constructor function 568 | */ 569 | constructor () public { 570 | // register the supported interface to conform to ERC721 via ERC165 571 | _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE); 572 | } 573 | 574 | /** 575 | * @dev Gets the token ID at a given index of the tokens list of the requested owner 576 | * @param owner address owning the tokens list to be accessed 577 | * @param index uint256 representing the index to be accessed of the requested tokens list 578 | * @return uint256 token ID at the given index of the tokens list owned by the requested address 579 | */ 580 | function tokenOfOwnerByIndex(address owner, uint256 index) public view returns (uint256) { 581 | require(index < balanceOf(owner), "Index is higher than number of tokens owned."); 582 | return _ownedTokens[owner][index]; 583 | } 584 | 585 | /** 586 | * @dev Gets the total amount of tokens stored by the contract 587 | * @return uint256 representing the total amount of tokens 588 | */ 589 | function totalSupply() public view returns (uint256) { 590 | return totalSupply_; 591 | } 592 | 593 | 594 | /** 595 | * @dev Gets the token ID at a given index of all the tokens in this contract 596 | * Reverts if the index is greater or equal to the total number of tokens 597 | * @param index uint256 representing the index to be accessed of the tokens list 598 | * @return uint256 token ID at the given index of the tokens list 599 | */ 600 | function tokenByIndex(uint256 index) public view returns (uint256) { 601 | require(index < totalSupply(), "Index is out of bounds."); 602 | return index; 603 | } 604 | 605 | 606 | /** 607 | * @dev Internal function to transfer ownership of a given token ID to another address. 608 | * As opposed to transferFrom, this imposes no restrictions on msg.sender. 609 | * @param from current owner of the token 610 | * @param to address to receive the ownership of the given token ID 611 | * @param tokenId uint256 ID of the token to be transferred 612 | */ 613 | function _transferFrom(address from, address to, uint256 tokenId) internal { 614 | super._transferFrom(from, to, tokenId); 615 | 616 | _removeTokenFromOwnerEnumeration(from, tokenId); 617 | 618 | _addTokenToOwnerEnumeration(to, tokenId); 619 | } 620 | 621 | /** 622 | * @dev Internal function to mint a new token 623 | * Reverts if the given token ID already exists 624 | * @param to address the beneficiary that will own the minted token 625 | * @param tokenId uint256 ID of the token to be minted 626 | */ 627 | function _mint(address to, uint256 tokenId) internal { 628 | super._mint(to, tokenId); 629 | 630 | _addTokenToOwnerEnumeration(to, tokenId); 631 | 632 | totalSupply_ = totalSupply_.add(1); 633 | } 634 | 635 | /** 636 | * @dev Internal function to burn a specific token 637 | * Reverts if the token does not exist 638 | * Deprecated, use _burn(uint256) instead 639 | * param owner owner of the token to burn 640 | * param tokenId uint256 ID of the token being burned 641 | */ 642 | function _burn(address /*owner*/, uint256 /*tokenId*/) internal { 643 | revert("This token cannot be burned."); 644 | } 645 | 646 | /** 647 | * @dev Gets the list of token IDs of the requested owner 648 | * @param owner address owning the tokens 649 | * @return uint256[] List of token IDs owned by the requested address 650 | */ 651 | function _tokensOfOwner(address owner) internal view returns (uint256[] storage) { 652 | return _ownedTokens[owner]; 653 | } 654 | 655 | /** 656 | * @dev Private function to add a token to this extension's ownership-tracking data structures. 657 | * @param to address representing the new owner of the given token ID 658 | * @param tokenId uint256 ID of the token to be added to the tokens list of the given address 659 | */ 660 | function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { 661 | _ownedTokensIndex[tokenId] = _ownedTokens[to].length; 662 | _ownedTokens[to].push(tokenId); 663 | } 664 | 665 | /** 666 | * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that 667 | * while the token is not assigned a new owner, the _ownedTokensIndex mapping is _not_ updated: this allows for 668 | * gas optimizations e.g. when performing a transfer operation (avoiding double writes). 669 | * This has O(1) time complexity, but alters the order of the _ownedTokens array. 670 | * @param from address representing the previous owner of the given token ID 671 | * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address 672 | */ 673 | function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { 674 | // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and 675 | // then delete the last slot (swap and pop). 676 | 677 | uint256 lastTokenIndex = _ownedTokens[from].length.sub(1); 678 | uint256 tokenIndex = _ownedTokensIndex[tokenId]; 679 | 680 | // When the token to delete is the last token, the swap operation is unnecessary 681 | if (tokenIndex != lastTokenIndex) { 682 | uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; 683 | 684 | _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token 685 | _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index 686 | } 687 | 688 | // This also deletes the contents at the last position of the array 689 | _ownedTokens[from].length--; 690 | 691 | // Note that _ownedTokensIndex[tokenId] hasn't been cleared: it still points to the old slot (now occcupied by 692 | // lasTokenId, or just over the end of the array if the token was the last one). 693 | } 694 | } 695 | 696 | // File: openzeppelin-solidity/contracts/token/ERC721/IERC721Metadata.sol 697 | 698 | pragma solidity ^0.5.0; 699 | 700 | 701 | /** 702 | * @title ERC-721 Non-Fungible Token Standard, optional metadata extension 703 | * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 704 | */ 705 | contract IERC721Metadata is IERC721 { 706 | function name() external view returns (string memory); 707 | function symbol() external view returns (string memory); 708 | function tokenURI(uint256 tokenId) external view returns (string memory); 709 | } 710 | 711 | // File: openzeppelin-solidity/contracts/token/ERC721/ERC721Metadata.sol 712 | 713 | pragma solidity ^0.5.0; 714 | 715 | 716 | 717 | 718 | contract ERC721Metadata is ERC165, ERC721, IERC721Metadata { 719 | // Token name 720 | string private _name; 721 | 722 | // Token symbol 723 | string private _symbol; 724 | 725 | // Optional mapping for token URIs 726 | mapping(uint256 => string) private _tokenURIs; 727 | 728 | bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f; 729 | /** 730 | * 0x5b5e139f === 731 | * bytes4(keccak256('name()')) ^ 732 | * bytes4(keccak256('symbol()')) ^ 733 | * bytes4(keccak256('tokenURI(uint256)')) 734 | */ 735 | 736 | /** 737 | * @dev Constructor function 738 | */ 739 | constructor (string memory name, string memory symbol) public { 740 | _name = name; 741 | _symbol = symbol; 742 | 743 | // register the supported interfaces to conform to ERC721 via ERC165 744 | _registerInterface(_INTERFACE_ID_ERC721_METADATA); 745 | } 746 | 747 | /** 748 | * @dev Gets the token name 749 | * @return string representing the token name 750 | */ 751 | function name() external view returns (string memory) { 752 | return _name; 753 | } 754 | 755 | /** 756 | * @dev Gets the token symbol 757 | * @return string representing the token symbol 758 | */ 759 | function symbol() external view returns (string memory) { 760 | return _symbol; 761 | } 762 | 763 | /** 764 | * @dev Returns an URI for a given token ID 765 | * Throws if the token ID does not exist. May return an empty string. 766 | * @param tokenId uint256 ID of the token to query 767 | */ 768 | function tokenURI(uint256 tokenId) external view returns (string memory) { 769 | require(_exists(tokenId)); 770 | return _tokenURIs[tokenId]; 771 | } 772 | 773 | /** 774 | * @dev Internal function to set the token URI for a given token 775 | * Reverts if the token ID does not exist 776 | * @param tokenId uint256 ID of the token to set its URI 777 | * @param uri string URI to assign 778 | */ 779 | function _setTokenURI(uint256 tokenId, string memory uri) internal { 780 | require(_exists(tokenId)); 781 | _tokenURIs[tokenId] = uri; 782 | } 783 | 784 | /** 785 | * @dev Internal function to burn a specific token 786 | * Reverts if the token does not exist 787 | * Deprecated, use _burn(uint256) instead 788 | * @param owner owner of the token to burn 789 | * @param tokenId uint256 ID of the token being burned by the msg.sender 790 | */ 791 | function _burn(address owner, uint256 tokenId) internal { 792 | super._burn(owner, tokenId); 793 | 794 | // Clear metadata (if any) 795 | if (bytes(_tokenURIs[tokenId]).length != 0) { 796 | delete _tokenURIs[tokenId]; 797 | } 798 | } 799 | } 800 | 801 | // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol 802 | 803 | pragma solidity ^0.5.0; 804 | 805 | /** 806 | * @title ERC20 interface 807 | * @dev see https://github.com/ethereum/EIPs/issues/20 808 | */ 809 | interface IERC20 { 810 | function transfer(address to, uint256 value) external returns (bool); 811 | 812 | function approve(address spender, uint256 value) external returns (bool); 813 | 814 | function transferFrom(address from, address to, uint256 value) external returns (bool); 815 | 816 | function totalSupply() external view returns (uint256); 817 | 818 | function balanceOf(address who) external view returns (uint256); 819 | 820 | function allowance(address owner, address spender) external view returns (uint256); 821 | 822 | event Transfer(address indexed from, address indexed to, uint256 value); 823 | 824 | event Approval(address indexed owner, address indexed spender, uint256 value); 825 | } 826 | 827 | // File: contracts/Cryptostamp.sol 828 | 829 | /* 830 | Implements ERC 721 Token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md 831 | */ 832 | pragma solidity ^0.5.0; 833 | 834 | 835 | 836 | 837 | 838 | /* The inheritance is very much the same as OpenZeppelin's ERC721Full, 839 | * but using a simplified (and cheaper) version of ERC721Enumerable */ 840 | contract Cryptostamp is ERC721, ERC721EnumerableSimple, ERC721Metadata("Crypto stamp Edition 1", "CS1") { 841 | 842 | string public uribase; 843 | 844 | address public createControl; 845 | 846 | address public tokenAssignmentControl; 847 | 848 | bool public mintingFinished = false; 849 | 850 | constructor(address _createControl, address _tokenAssignmentControl) 851 | public 852 | { 853 | createControl = _createControl; 854 | tokenAssignmentControl = _tokenAssignmentControl; 855 | uribase = "https://test.crypto.post.at/CS1/meta/"; 856 | } 857 | 858 | modifier onlyCreateControl() 859 | { 860 | require(msg.sender == createControl, "createControl key required for this function."); 861 | _; 862 | } 863 | 864 | modifier onlyTokenAssignmentControl() { 865 | require(msg.sender == tokenAssignmentControl, "tokenAssignmentControl key required for this function."); 866 | _; 867 | } 868 | 869 | modifier requireMinting() { 870 | require(mintingFinished == false, "This call only works when minting is not finished."); 871 | _; 872 | } 873 | 874 | // Issue a new crypto stamp asset, giving it to a specific owner address. 875 | // As appending the ID into a URI in Solidity is complicated, generate both 876 | // externally and hand them over to the asset here. 877 | function create(uint256 _tokenId, address _owner) 878 | public 879 | onlyCreateControl 880 | requireMinting 881 | { 882 | // Make sure we do not get any holes in Ids so we can do more optimizations. 883 | require(_tokenId == 0 || _exists(_tokenId.sub(1)), "Previous token ID has to exist."); 884 | // _mint already ends up checking if owner != 0 and that tokenId doesn't exist yet. 885 | _mint(_owner, _tokenId); 886 | } 887 | 888 | // Batch-issue multiple crypto stamp with adjacent IDs. 889 | function createMulti(uint256 _tokenIdStart, address[] memory _owners) 890 | public 891 | onlyCreateControl 892 | requireMinting 893 | { 894 | // Make sure we do not get any holes in Ids so we can do more optimizations. 895 | require(_tokenIdStart == 0 || _exists(_tokenIdStart.sub(1)), "Previous token ID has to exist."); 896 | uint256 addrcount = _owners.length; 897 | for (uint256 i = 0; i < addrcount; i++) { 898 | // Make sure this is in sync with what create() does. 899 | _mint(_owners[i], _tokenIdStart + i); 900 | } 901 | } 902 | 903 | // Finish the creation/minting process. 904 | function finishMinting() 905 | public 906 | onlyCreateControl 907 | { 908 | mintingFinished = true; 909 | } 910 | 911 | // Set new base for the token URI. 912 | function newUriBase(string memory _newUriBase) 913 | public 914 | onlyCreateControl 915 | { 916 | uribase = _newUriBase; 917 | } 918 | 919 | // Override ERC721Metadata to create the URI from the base and ID. 920 | function tokenURI(uint256 _tokenId) 921 | external view 922 | returns (string memory) 923 | { 924 | require(_exists(_tokenId), "Token ID does not exist."); 925 | return string(abi.encodePacked(uribase, uint2str(_tokenId))); 926 | } 927 | 928 | // Returns whether the specified token exists 929 | function exists(uint256 tokenId) public view returns (bool) { 930 | return _exists(tokenId); 931 | } 932 | 933 | // Helper function from Oraclize 934 | // https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol 935 | function uint2str(uint256 inp) 936 | internal pure 937 | returns (string memory) 938 | { 939 | if (inp == 0) return "0"; 940 | uint i = inp; 941 | uint j = i; 942 | uint length; 943 | while (j != 0){ 944 | length++; 945 | j /= 10; 946 | } 947 | bytes memory bstr = new bytes(length); 948 | uint k = length - 1; 949 | while (i != 0){ 950 | bstr[k--] = byte(uint8(48 + i % 10)); 951 | i /= 10; 952 | } 953 | return string(bstr); 954 | } 955 | 956 | /*** Make sure currency doesn't get stranded in this contract ***/ 957 | 958 | // If this contract gets a balance in some ERC20 contract after it's finished, then we can rescue it. 959 | function rescueToken(IERC20 _foreignToken, address _to) 960 | external 961 | onlyTokenAssignmentControl 962 | { 963 | _foreignToken.transfer(_to, _foreignToken.balanceOf(address(this))); 964 | } 965 | 966 | // Make sure this contract cannot receive ETH. 967 | function() 968 | external payable 969 | { 970 | revert("The contract cannot receive ETH payments."); 971 | } 972 | } 973 | -------------------------------------------------------------------------------- /Dice2Win.sol: -------------------------------------------------------------------------------- 1 | /////////////////////////////////// 2 | // see https://etherscan.io/address/0xD1CEeeeee83F8bCF3BEDad437202b6154E9F5405#code 3 | 4 | pragma solidity ^0.4.24; 5 | 6 | // * dice2.win - fair games that pay Ether. Version 5. 7 | // 8 | // * Ethereum smart contract, deployed at 0xD1CEeeeee83F8bCF3BEDad437202b6154E9F5405. 9 | // 10 | // * Uses hybrid commit-reveal + block hash random number generation that is immune 11 | // to tampering by players, house and miners. Apart from being fully transparent, 12 | // this also allows arbitrarily high bets. 13 | // 14 | // * Refer to https://dice2.win/whitepaper.pdf for detailed description and proofs. 15 | 16 | contract Dice2Win { 17 | /// *** Constants section 18 | 19 | // Each bet is deducted 1% in favour of the house, but no less than some minimum. 20 | // The lower bound is dictated by gas costs of the settleBet transaction, providing 21 | // headroom for up to 10 Gwei prices. 22 | uint constant HOUSE_EDGE_PERCENT = 1; 23 | uint constant HOUSE_EDGE_MINIMUM_AMOUNT = 0.0003 ether; 24 | 25 | // Bets lower than this amount do not participate in jackpot rolls (and are 26 | // not deducted JACKPOT_FEE). 27 | uint constant MIN_JACKPOT_BET = 0.1 ether; 28 | 29 | // Chance to win jackpot (currently 0.1%) and fee deducted into jackpot fund. 30 | uint constant JACKPOT_MODULO = 1000; 31 | uint constant JACKPOT_FEE = 0.001 ether; 32 | 33 | // There is minimum and maximum bets. 34 | uint constant MIN_BET = 0.01 ether; 35 | uint constant MAX_AMOUNT = 300000 ether; 36 | 37 | // Modulo is a number of equiprobable outcomes in a game: 38 | // - 2 for coin flip 39 | // - 6 for dice 40 | // - 6*6 = 36 for double dice 41 | // - 100 for etheroll 42 | // - 37 for roulette 43 | // etc. 44 | // It's called so because 256-bit entropy is treated like a huge integer and 45 | // the remainder of its division by modulo is considered bet outcome. 46 | uint constant MAX_MODULO = 100; 47 | 48 | // For modulos below this threshold rolls are checked against a bit mask, 49 | // thus allowing betting on any combination of outcomes. For example, given 50 | // modulo 6 for dice, 101000 mask (base-2, big endian) means betting on 51 | // 4 and 6; for games with modulos higher than threshold (Etheroll), a simple 52 | // limit is used, allowing betting on any outcome in [0, N) range. 53 | // 54 | // The specific value is dictated by the fact that 256-bit intermediate 55 | // multiplication result allows implementing population count efficiently 56 | // for numbers that are up to 42 bits, and 40 is the highest multiple of 57 | // eight below 42. 58 | uint constant MAX_MASK_MODULO = 40; 59 | 60 | // This is a check on bet mask overflow. 61 | uint constant MAX_BET_MASK = 2 ** MAX_MASK_MODULO; 62 | 63 | // EVM BLOCKHASH opcode can query no further than 256 blocks into the 64 | // past. Given that settleBet uses block hash of placeBet as one of 65 | // complementary entropy sources, we cannot process bets older than this 66 | // threshold. On rare occasions dice2.win croupier may fail to invoke 67 | // settleBet in this timespan due to technical issues or extreme Ethereum 68 | // congestion; such bets can be refunded via invoking refundBet. 69 | uint constant BET_EXPIRATION_BLOCKS = 250; 70 | 71 | // Some deliberately invalid address to initialize the secret signer with. 72 | // Forces maintainers to invoke setSecretSigner before processing any bets. 73 | address constant DUMMY_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; 74 | 75 | // Standard contract ownership transfer. 76 | address public owner; 77 | address private nextOwner; 78 | 79 | // Adjustable max bet profit. Used to cap bets against dynamic odds. 80 | uint public maxProfit; 81 | 82 | // The address corresponding to a private key used to sign placeBet commits. 83 | address public secretSigner; 84 | 85 | // Accumulated jackpot fund. 86 | uint128 public jackpotSize; 87 | 88 | // Funds that are locked in potentially winning bets. Prevents contract from 89 | // committing to bets it cannot pay out. 90 | uint128 public lockedInBets; 91 | 92 | // A structure representing a single bet. 93 | struct Bet { 94 | // Wager amount in wei. 95 | uint amount; 96 | // Modulo of a game. 97 | uint8 modulo; 98 | // Number of winning outcomes, used to compute winning payment (* modulo/rollUnder), 99 | // and used instead of mask for games with modulo > MAX_MASK_MODULO. 100 | uint8 rollUnder; 101 | // Block number of placeBet tx. 102 | uint40 placeBlockNumber; 103 | // Bit mask representing winning bet outcomes (see MAX_MASK_MODULO comment). 104 | uint40 mask; 105 | // Address of a gambler, used to pay out winning bets. 106 | address gambler; 107 | } 108 | 109 | // Mapping from commits to all currently active & processed bets. 110 | mapping (uint => Bet) bets; 111 | 112 | // Croupier account. 113 | address public croupier; 114 | 115 | // Events that are issued to make statistic recovery easier. 116 | event FailedPayment(address indexed beneficiary, uint amount); 117 | event Payment(address indexed beneficiary, uint amount); 118 | event JackpotPayment(address indexed beneficiary, uint amount); 119 | 120 | // This event is emitted in placeBet to record commit in the logs. 121 | event Commit(uint commit); 122 | 123 | // Constructor. Deliberately does not take any parameters. 124 | constructor () public { 125 | owner = msg.sender; 126 | secretSigner = DUMMY_ADDRESS; 127 | croupier = DUMMY_ADDRESS; 128 | } 129 | 130 | // Standard modifier on methods invokable only by contract owner. 131 | modifier onlyOwner { 132 | require (msg.sender == owner, "OnlyOwner methods called by non-owner."); 133 | _; 134 | } 135 | 136 | // Standard modifier on methods invokable only by contract owner. 137 | modifier onlyCroupier { 138 | require (msg.sender == croupier, "OnlyCroupier methods called by non-croupier."); 139 | _; 140 | } 141 | 142 | // Standard contract ownership transfer implementation, 143 | function approveNextOwner(address _nextOwner) external onlyOwner { 144 | require (_nextOwner != owner, "Cannot approve current owner."); 145 | nextOwner = _nextOwner; 146 | } 147 | 148 | function acceptNextOwner() external { 149 | require (msg.sender == nextOwner, "Can only accept preapproved new owner."); 150 | owner = nextOwner; 151 | } 152 | 153 | // Fallback function deliberately left empty. It's primary use case 154 | // is to top up the bank roll. 155 | function () public payable { 156 | } 157 | 158 | // See comment for "secretSigner" variable. 159 | function setSecretSigner(address newSecretSigner) external onlyOwner { 160 | secretSigner = newSecretSigner; 161 | } 162 | 163 | // Change the croupier address. 164 | function setCroupier(address newCroupier) external onlyOwner { 165 | croupier = newCroupier; 166 | } 167 | 168 | // Change max bet reward. Setting this to zero effectively disables betting. 169 | function setMaxProfit(uint _maxProfit) public onlyOwner { 170 | require (_maxProfit < MAX_AMOUNT, "maxProfit should be a sane number."); 171 | maxProfit = _maxProfit; 172 | } 173 | 174 | // This function is used to bump up the jackpot fund. Cannot be used to lower it. 175 | function increaseJackpot(uint increaseAmount) external onlyOwner { 176 | require (increaseAmount <= address(this).balance, "Increase amount larger than balance."); 177 | require (jackpotSize + lockedInBets + increaseAmount <= address(this).balance, "Not enough funds."); 178 | jackpotSize += uint128(increaseAmount); 179 | } 180 | 181 | // Funds withdrawal to cover costs of dice2.win operation. 182 | function withdrawFunds(address beneficiary, uint withdrawAmount) external onlyOwner { 183 | require (withdrawAmount <= address(this).balance, "Increase amount larger than balance."); 184 | require (jackpotSize + lockedInBets + withdrawAmount <= address(this).balance, "Not enough funds."); 185 | sendFunds(beneficiary, withdrawAmount, withdrawAmount); 186 | } 187 | 188 | // Contract may be destroyed only when there are no ongoing bets, 189 | // either settled or refunded. All funds are transferred to contract owner. 190 | function kill() external onlyOwner { 191 | require (lockedInBets == 0, "All bets should be processed (settled or refunded) before self-destruct."); 192 | selfdestruct(owner); 193 | } 194 | 195 | /// *** Betting logic 196 | 197 | // Bet states: 198 | // amount == 0 && gambler == 0 - 'clean' (can place a bet) 199 | // amount != 0 && gambler != 0 - 'active' (can be settled or refunded) 200 | // amount == 0 && gambler != 0 - 'processed' (can clean storage) 201 | // 202 | // NOTE: Storage cleaning is not implemented in this contract version; it will be added 203 | // with the next upgrade to prevent polluting Ethereum state with expired bets. 204 | 205 | // Bet placing transaction - issued by the player. 206 | // betMask - bet outcomes bit mask for modulo <= MAX_MASK_MODULO, 207 | // [0, betMask) for larger modulos. 208 | // modulo - game modulo. 209 | // commitLastBlock - number of the maximum block where "commit" is still considered valid. 210 | // commit - Keccak256 hash of some secret "reveal" random number, to be supplied 211 | // by the dice2.win croupier bot in the settleBet transaction. Supplying 212 | // "commit" ensures that "reveal" cannot be changed behind the scenes 213 | // after placeBet have been mined. 214 | // r, s - components of ECDSA signature of (commitLastBlock, commit). v is 215 | // guaranteed to always equal 27. 216 | // 217 | // Commit, being essentially random 256-bit number, is used as a unique bet identifier in 218 | // the 'bets' mapping. 219 | // 220 | // Commits are signed with a block limit to ensure that they are used at most once - otherwise 221 | // it would be possible for a miner to place a bet with a known commit/reveal pair and tamper 222 | // with the blockhash. Croupier guarantees that commitLastBlock will always be not greater than 223 | // placeBet block number plus BET_EXPIRATION_BLOCKS. See whitepaper for details. 224 | function placeBet(uint betMask, uint modulo, uint commitLastBlock, uint commit, bytes32 r, bytes32 s) external payable { 225 | // Check that the bet is in 'clean' state. 226 | Bet storage bet = bets[commit]; 227 | require (bet.gambler == address(0), "Bet should be in a 'clean' state."); 228 | 229 | // Validate input data ranges. 230 | uint amount = msg.value; 231 | require (modulo > 1 && modulo <= MAX_MODULO, "Modulo should be within range."); 232 | require (amount >= MIN_BET && amount <= MAX_AMOUNT, "Amount should be within range."); 233 | require (betMask > 0 && betMask < MAX_BET_MASK, "Mask should be within range."); 234 | 235 | // Check that commit is valid - it has not expired and its signature is valid. 236 | require (block.number <= commitLastBlock, "Commit has expired."); 237 | bytes32 signatureHash = keccak256(abi.encodePacked(uint40(commitLastBlock), commit)); 238 | require (secretSigner == ecrecover(signatureHash, 27, r, s), "ECDSA signature is not valid."); 239 | 240 | uint rollUnder; 241 | uint mask; 242 | 243 | if (modulo <= MAX_MASK_MODULO) { 244 | // Small modulo games specify bet outcomes via bit mask. 245 | // rollUnder is a number of 1 bits in this mask (population count). 246 | // This magic looking formula is an efficient way to compute population 247 | // count on EVM for numbers below 2**40. For detailed proof consult 248 | // the dice2.win whitepaper. 249 | rollUnder = ((betMask * POPCNT_MULT) & POPCNT_MASK) % POPCNT_MODULO; 250 | mask = betMask; 251 | } else { 252 | // Larger modulos specify the right edge of half-open interval of 253 | // winning bet outcomes. 254 | require (betMask > 0 && betMask <= modulo, "High modulo range, betMask larger than modulo."); 255 | rollUnder = betMask; 256 | } 257 | 258 | // Winning amount and jackpot increase. 259 | uint possibleWinAmount; 260 | uint jackpotFee; 261 | 262 | (possibleWinAmount, jackpotFee) = getDiceWinAmount(amount, modulo, rollUnder); 263 | 264 | // Enforce max profit limit. 265 | require (possibleWinAmount <= amount + maxProfit, "maxProfit limit violation."); 266 | 267 | // Lock funds. 268 | lockedInBets += uint128(possibleWinAmount); 269 | jackpotSize += uint128(jackpotFee); 270 | 271 | // Check whether contract has enough funds to process this bet. 272 | require (jackpotSize + lockedInBets <= address(this).balance, "Cannot afford to lose this bet."); 273 | 274 | // Record commit in logs. 275 | emit Commit(commit); 276 | 277 | // Store bet parameters on blockchain. 278 | bet.amount = amount; 279 | bet.modulo = uint8(modulo); 280 | bet.rollUnder = uint8(rollUnder); 281 | bet.placeBlockNumber = uint40(block.number); 282 | bet.mask = uint40(mask); 283 | bet.gambler = msg.sender; 284 | } 285 | 286 | // This is the method used to settle 99% of bets. To process a bet with a specific 287 | // "commit", settleBet should supply a "reveal" number that would Keccak256-hash to 288 | // "commit". "blockHash" is the block hash of placeBet block as seen by croupier; it 289 | // is additionally asserted to prevent changing the bet outcomes on Ethereum reorgs. 290 | function settleBet(uint reveal, bytes32 blockHash) external onlyCroupier { 291 | uint commit = uint(keccak256(abi.encodePacked(reveal))); 292 | 293 | Bet storage bet = bets[commit]; 294 | uint placeBlockNumber = bet.placeBlockNumber; 295 | 296 | // Check that bet has not expired yet (see comment to BET_EXPIRATION_BLOCKS). 297 | require (block.number > placeBlockNumber, "settleBet in the same block as placeBet, or before."); 298 | require (block.number <= placeBlockNumber + BET_EXPIRATION_BLOCKS, "Blockhash can't be queried by EVM."); 299 | require (blockhash(placeBlockNumber) == blockHash); 300 | 301 | // Settle bet using reveal and blockHash as entropy sources. 302 | settleBetCommon(bet, reveal, blockHash); 303 | } 304 | 305 | // This method is used to settle a bet that was mined into an uncle block. At this 306 | // point the player was shown some bet outcome, but the blockhash at placeBet height 307 | // is different because of Ethereum chain reorg. We supply a full merkle proof of the 308 | // placeBet transaction receipt to provide untamperable evidence that uncle block hash 309 | // indeed was present on-chain at some point. 310 | function settleBetUncleMerkleProof(uint reveal, uint40 canonicalBlockNumber) external onlyCroupier { 311 | // "commit" for bet settlement can only be obtained by hashing a "reveal". 312 | uint commit = uint(keccak256(abi.encodePacked(reveal))); 313 | 314 | Bet storage bet = bets[commit]; 315 | 316 | // Check that canonical block hash can still be verified. 317 | require (block.number <= canonicalBlockNumber + BET_EXPIRATION_BLOCKS, "Blockhash can't be queried by EVM."); 318 | 319 | // Verify placeBet receipt. 320 | requireCorrectReceipt(4 + 32 + 32 + 4); 321 | 322 | // Reconstruct canonical & uncle block hashes from a receipt merkle proof, verify them. 323 | bytes32 canonicalHash; 324 | bytes32 uncleHash; 325 | (canonicalHash, uncleHash) = verifyMerkleProof(commit, 4 + 32 + 32); 326 | require (blockhash(canonicalBlockNumber) == canonicalHash); 327 | 328 | // Settle bet using reveal and uncleHash as entropy sources. 329 | settleBetCommon(bet, reveal, uncleHash); 330 | } 331 | 332 | // Common settlement code for settleBet & settleBetUncleMerkleProof. 333 | function settleBetCommon(Bet storage bet, uint reveal, bytes32 entropyBlockHash) private { 334 | // Fetch bet parameters into local variables (to save gas). 335 | uint amount = bet.amount; 336 | uint modulo = bet.modulo; 337 | uint rollUnder = bet.rollUnder; 338 | address gambler = bet.gambler; 339 | 340 | // Check that bet is in 'active' state. 341 | require (amount != 0, "Bet should be in an 'active' state"); 342 | 343 | // Move bet into 'processed' state already. 344 | bet.amount = 0; 345 | 346 | // The RNG - combine "reveal" and blockhash of placeBet using Keccak256. Miners 347 | // are not aware of "reveal" and cannot deduce it from "commit" (as Keccak256 348 | // preimage is intractable), and house is unable to alter the "reveal" after 349 | // placeBet have been mined (as Keccak256 collision finding is also intractable). 350 | bytes32 entropy = keccak256(abi.encodePacked(reveal, entropyBlockHash)); 351 | 352 | // Do a roll by taking a modulo of entropy. Compute winning amount. 353 | uint dice = uint(entropy) % modulo; 354 | 355 | uint diceWinAmount; 356 | uint _jackpotFee; 357 | (diceWinAmount, _jackpotFee) = getDiceWinAmount(amount, modulo, rollUnder); 358 | 359 | uint diceWin = 0; 360 | uint jackpotWin = 0; 361 | 362 | // Determine dice outcome. 363 | if (modulo <= MAX_MASK_MODULO) { 364 | // For small modulo games, check the outcome against a bit mask. 365 | if ((2 ** dice) & bet.mask != 0) { 366 | diceWin = diceWinAmount; 367 | } 368 | 369 | } else { 370 | // For larger modulos, check inclusion into half-open interval. 371 | if (dice < rollUnder) { 372 | diceWin = diceWinAmount; 373 | } 374 | 375 | } 376 | 377 | // Unlock the bet amount, regardless of the outcome. 378 | lockedInBets -= uint128(diceWinAmount); 379 | 380 | // Roll for a jackpot (if eligible). 381 | if (amount >= MIN_JACKPOT_BET) { 382 | // The second modulo, statistically independent from the "main" dice roll. 383 | // Effectively you are playing two games at once! 384 | uint jackpotRng = (uint(entropy) / modulo) % JACKPOT_MODULO; 385 | 386 | // Bingo! 387 | if (jackpotRng == 0) { 388 | jackpotWin = jackpotSize; 389 | jackpotSize = 0; 390 | } 391 | } 392 | 393 | // Log jackpot win. 394 | if (jackpotWin > 0) { 395 | emit JackpotPayment(gambler, jackpotWin); 396 | } 397 | 398 | // Send the funds to gambler. 399 | sendFunds(gambler, diceWin + jackpotWin == 0 ? 1 wei : diceWin + jackpotWin, diceWin); 400 | } 401 | 402 | // Refund transaction - return the bet amount of a roll that was not processed in a 403 | // due timeframe. Processing such blocks is not possible due to EVM limitations (see 404 | // BET_EXPIRATION_BLOCKS comment above for details). In case you ever find yourself 405 | // in a situation like this, just contact the dice2.win support, however nothing 406 | // precludes you from invoking this method yourself. 407 | function refundBet(uint commit) external { 408 | // Check that bet is in 'active' state. 409 | Bet storage bet = bets[commit]; 410 | uint amount = bet.amount; 411 | 412 | require (amount != 0, "Bet should be in an 'active' state"); 413 | 414 | // Check that bet has already expired. 415 | require (block.number > bet.placeBlockNumber + BET_EXPIRATION_BLOCKS, "Blockhash can't be queried by EVM."); 416 | 417 | // Move bet into 'processed' state, release funds. 418 | bet.amount = 0; 419 | 420 | uint diceWinAmount; 421 | uint jackpotFee; 422 | (diceWinAmount, jackpotFee) = getDiceWinAmount(amount, bet.modulo, bet.rollUnder); 423 | 424 | lockedInBets -= uint128(diceWinAmount); 425 | jackpotSize -= uint128(jackpotFee); 426 | 427 | // Send the refund. 428 | sendFunds(bet.gambler, amount, amount); 429 | } 430 | 431 | // Get the expected win amount after house edge is subtracted. 432 | function getDiceWinAmount(uint amount, uint modulo, uint rollUnder) private pure returns (uint winAmount, uint jackpotFee) { 433 | require (0 < rollUnder && rollUnder <= modulo, "Win probability out of range."); 434 | 435 | jackpotFee = amount >= MIN_JACKPOT_BET ? JACKPOT_FEE : 0; 436 | 437 | uint houseEdge = amount * HOUSE_EDGE_PERCENT / 100; 438 | 439 | if (houseEdge < HOUSE_EDGE_MINIMUM_AMOUNT) { 440 | houseEdge = HOUSE_EDGE_MINIMUM_AMOUNT; 441 | } 442 | 443 | require (houseEdge + jackpotFee <= amount, "Bet doesn't even cover house edge."); 444 | winAmount = (amount - houseEdge - jackpotFee) * modulo / rollUnder; 445 | } 446 | 447 | // Helper routine to process the payment. 448 | function sendFunds(address beneficiary, uint amount, uint successLogAmount) private { 449 | if (beneficiary.send(amount)) { 450 | emit Payment(beneficiary, successLogAmount); 451 | } else { 452 | emit FailedPayment(beneficiary, amount); 453 | } 454 | } 455 | 456 | // This are some constants making O(1) population count in placeBet possible. 457 | // See whitepaper for intuition and proofs behind it. 458 | uint constant POPCNT_MULT = 0x0000000000002000000000100000000008000000000400000000020000000001; 459 | uint constant POPCNT_MASK = 0x0001041041041041041041041041041041041041041041041041041041041041; 460 | uint constant POPCNT_MODULO = 0x3F; 461 | 462 | // *** Merkle proofs. 463 | 464 | // This helpers are used to verify cryptographic proofs of placeBet inclusion into 465 | // uncle blocks. They are used to prevent bet outcome changing on Ethereum reorgs without 466 | // compromising the security of the smart contract. Proof data is appended to the input data 467 | // in a simple prefix length format and does not adhere to the ABI. 468 | // Invariants checked: 469 | // - receipt trie entry contains a (1) successful transaction (2) directed at this smart 470 | // contract (3) containing commit as a payload. 471 | // - receipt trie entry is a part of a valid merkle proof of a block header 472 | // - the block header is a part of uncle list of some block on canonical chain 473 | // The implementation is optimized for gas cost and relies on the specifics of Ethereum internal data structures. 474 | // Read the whitepaper for details. 475 | 476 | // Helper to verify a full merkle proof starting from some seedHash (usually commit). "offset" is the location of the proof 477 | // beginning in the calldata. 478 | function verifyMerkleProof(uint seedHash, uint offset) pure private returns (bytes32 blockHash, bytes32 uncleHash) { 479 | // (Safe) assumption - nobody will write into RAM during this method invocation. 480 | uint scratchBuf1; assembly { scratchBuf1 := mload(0x40) } 481 | 482 | uint uncleHeaderLength; uint blobLength; uint shift; uint hashSlot; 483 | 484 | // Verify merkle proofs up to uncle block header. Calldata layout is: 485 | // - 2 byte big-endian slice length 486 | // - 2 byte big-endian offset to the beginning of previous slice hash within the current slice (should be zeroed) 487 | // - followed by the current slice verbatim 488 | for (;; offset += blobLength) { 489 | assembly { blobLength := and(calldataload(sub(offset, 30)), 0xffff) } 490 | if (blobLength == 0) { 491 | // Zero slice length marks the end of uncle proof. 492 | break; 493 | } 494 | 495 | assembly { shift := and(calldataload(sub(offset, 28)), 0xffff) } 496 | require (shift + 32 <= blobLength, "Shift bounds check."); 497 | 498 | offset += 4; 499 | assembly { hashSlot := calldataload(add(offset, shift)) } 500 | require (hashSlot == 0, "Non-empty hash slot."); 501 | 502 | assembly { 503 | calldatacopy(scratchBuf1, offset, blobLength) 504 | mstore(add(scratchBuf1, shift), seedHash) 505 | seedHash := sha3(scratchBuf1, blobLength) 506 | uncleHeaderLength := blobLength 507 | } 508 | } 509 | 510 | // At this moment the uncle hash is known. 511 | uncleHash = bytes32(seedHash); 512 | 513 | // Construct the uncle list of a canonical block. 514 | uint scratchBuf2 = scratchBuf1 + uncleHeaderLength; 515 | uint unclesLength; assembly { unclesLength := and(calldataload(sub(offset, 28)), 0xffff) } 516 | uint unclesShift; assembly { unclesShift := and(calldataload(sub(offset, 26)), 0xffff) } 517 | require (unclesShift + uncleHeaderLength <= unclesLength, "Shift bounds check."); 518 | 519 | offset += 6; 520 | assembly { calldatacopy(scratchBuf2, offset, unclesLength) } 521 | memcpy(scratchBuf2 + unclesShift, scratchBuf1, uncleHeaderLength); 522 | 523 | assembly { seedHash := sha3(scratchBuf2, unclesLength) } 524 | 525 | offset += unclesLength; 526 | 527 | // Verify the canonical block header using the computed sha3Uncles. 528 | assembly { 529 | blobLength := and(calldataload(sub(offset, 30)), 0xffff) 530 | shift := and(calldataload(sub(offset, 28)), 0xffff) 531 | } 532 | require (shift + 32 <= blobLength, "Shift bounds check."); 533 | 534 | offset += 4; 535 | assembly { hashSlot := calldataload(add(offset, shift)) } 536 | require (hashSlot == 0, "Non-empty hash slot."); 537 | 538 | assembly { 539 | calldatacopy(scratchBuf1, offset, blobLength) 540 | mstore(add(scratchBuf1, shift), seedHash) 541 | 542 | // At this moment the canonical block hash is known. 543 | blockHash := sha3(scratchBuf1, blobLength) 544 | } 545 | } 546 | 547 | // Helper to check the placeBet receipt. "offset" is the location of the proof beginning in the calldata. 548 | // RLP layout: [triePath, str([status, cumGasUsed, bloomFilter, [[address, [topics], data]])] 549 | function requireCorrectReceipt(uint offset) view private { 550 | uint leafHeaderByte; assembly { leafHeaderByte := byte(0, calldataload(offset)) } 551 | 552 | require (leafHeaderByte >= 0xf7, "Receipt leaf longer than 55 bytes."); 553 | offset += leafHeaderByte - 0xf6; 554 | 555 | uint pathHeaderByte; assembly { pathHeaderByte := byte(0, calldataload(offset)) } 556 | 557 | if (pathHeaderByte <= 0x7f) { 558 | offset += 1; 559 | 560 | } else { 561 | require (pathHeaderByte >= 0x80 && pathHeaderByte <= 0xb7, "Path is an RLP string."); 562 | offset += pathHeaderByte - 0x7f; 563 | } 564 | 565 | uint receiptStringHeaderByte; assembly { receiptStringHeaderByte := byte(0, calldataload(offset)) } 566 | require (receiptStringHeaderByte == 0xb9, "Receipt string is always at least 256 bytes long, but less than 64k."); 567 | offset += 3; 568 | 569 | uint receiptHeaderByte; assembly { receiptHeaderByte := byte(0, calldataload(offset)) } 570 | require (receiptHeaderByte == 0xf9, "Receipt is always at least 256 bytes long, but less than 64k."); 571 | offset += 3; 572 | 573 | uint statusByte; assembly { statusByte := byte(0, calldataload(offset)) } 574 | require (statusByte == 0x1, "Status should be success."); 575 | offset += 1; 576 | 577 | uint cumGasHeaderByte; assembly { cumGasHeaderByte := byte(0, calldataload(offset)) } 578 | if (cumGasHeaderByte <= 0x7f) { 579 | offset += 1; 580 | 581 | } else { 582 | require (cumGasHeaderByte >= 0x80 && cumGasHeaderByte <= 0xb7, "Cumulative gas is an RLP string."); 583 | offset += cumGasHeaderByte - 0x7f; 584 | } 585 | 586 | uint bloomHeaderByte; assembly { bloomHeaderByte := byte(0, calldataload(offset)) } 587 | require (bloomHeaderByte == 0xb9, "Bloom filter is always 256 bytes long."); 588 | offset += 256 + 3; 589 | 590 | uint logsListHeaderByte; assembly { logsListHeaderByte := byte(0, calldataload(offset)) } 591 | require (logsListHeaderByte == 0xf8, "Logs list is less than 256 bytes long."); 592 | offset += 2; 593 | 594 | uint logEntryHeaderByte; assembly { logEntryHeaderByte := byte(0, calldataload(offset)) } 595 | require (logEntryHeaderByte == 0xf8, "Log entry is less than 256 bytes long."); 596 | offset += 2; 597 | 598 | uint addressHeaderByte; assembly { addressHeaderByte := byte(0, calldataload(offset)) } 599 | require (addressHeaderByte == 0x94, "Address is 20 bytes long."); 600 | 601 | uint logAddress; assembly { logAddress := and(calldataload(sub(offset, 11)), 0xffffffffffffffffffffffffffffffffffffffff) } 602 | require (logAddress == uint(address(this))); 603 | } 604 | 605 | // Memory copy. 606 | function memcpy(uint dest, uint src, uint len) pure private { 607 | // Full 32 byte words 608 | for(; len >= 32; len -= 32) { 609 | assembly { mstore(dest, mload(src)) } 610 | dest += 32; src += 32; 611 | } 612 | 613 | // Remaining bytes 614 | uint mask = 256 ** (32 - len) - 1; 615 | assembly { 616 | let srcpart := and(mload(src), not(mask)) 617 | let destpart := and(mload(dest), mask) 618 | mstore(dest, or(destpart, srcpart)) 619 | } 620 | } 621 | } 622 | -------------------------------------------------------------------------------- /FckDice.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.1; 2 | 3 | contract FckDice { 4 | /// *** Constants section 5 | 6 | // Each bet is deducted 0.98% in favour of the house, but no less than some minimum. 7 | // The lower bound is dictated by gas costs of the settleBet transaction, providing 8 | // headroom for up to 20 Gwei prices. 9 | uint public constant HOUSE_EDGE_OF_TEN_THOUSAND = 98; 10 | uint public constant HOUSE_EDGE_MINIMUM_AMOUNT = 0.0003 ether; 11 | 12 | // Bets lower than this amount do not participate in jackpot rolls (and are 13 | // not deducted JACKPOT_FEE). 14 | uint public constant MIN_JACKPOT_BET = 0.1 ether; 15 | 16 | // Chance to win jackpot (currently 0.1%) and fee deducted into jackpot fund. 17 | uint public constant JACKPOT_MODULO = 1000; 18 | uint public constant JACKPOT_FEE = 0.001 ether; 19 | 20 | // There is minimum and maximum bets. 21 | uint constant MIN_BET = 0.01 ether; 22 | uint constant MAX_AMOUNT = 300000 ether; 23 | 24 | // Modulo is a number of equiprobable outcomes in a game: 25 | // - 2 for coin flip 26 | // - 6 for dice 27 | // - 6 * 6 = 36 for double dice 28 | // - 6 * 6 * 6 = 216 for triple dice 29 | // - 37 for rouletter 30 | // - 4, 13, 26, 52 for poker 31 | // - 100 for etheroll 32 | // etc. 33 | // It's called so because 256-bit entropy is treated like a huge integer and 34 | // the remainder of its division by modulo is considered bet outcome. 35 | uint constant MAX_MODULO = 216; 36 | 37 | // For modulos below this threshold rolls are checked against a bit mask, 38 | // thus allowing betting on any combination of outcomes. For example, given 39 | // modulo 6 for dice, 101000 mask (base-2, big endian) means betting on 40 | // 4 and 6; for games with modulos higher than threshold (Etheroll), a simple 41 | // limit is used, allowing betting on any outcome in [0, N) range. 42 | // 43 | // The specific value is dictated by the fact that 256-bit intermediate 44 | // multiplication result allows implementing population count efficiently 45 | // for numbers that are up to 42 bits. 46 | uint constant MAX_MASK_MODULO = 216; 47 | 48 | // This is a check on bet mask overflow. 49 | uint constant MAX_BET_MASK = 2 ** MAX_MASK_MODULO; 50 | 51 | // EVM BLOCKHASH opcode can query no further than 256 blocks into the 52 | // past. Given that settleBet uses block hash of placeBet as one of 53 | // complementary entropy sources, we cannot process bets older than this 54 | // threshold. On rare occasions croupier may fail to invoke 55 | // settleBet in this timespan due to technical issues or extreme Ethereum 56 | // congestion; such bets can be refunded via invoking refundBet. 57 | uint constant BET_EXPIRATION_BLOCKS = 250; 58 | 59 | // Standard contract ownership transfer. 60 | address payable public owner1; 61 | address payable public owner2; 62 | 63 | // Adjustable max bet profit. Used to cap bets against dynamic odds. 64 | uint128 public maxProfit; 65 | bool public killed; 66 | 67 | // The address corresponding to a private key used to sign placeBet commits. 68 | address public secretSigner; 69 | 70 | // Accumulated jackpot fund. 71 | uint128 public jackpotSize; 72 | 73 | // Funds that are locked in potentially winning bets. Prevents contract from 74 | // committing to bets it cannot pay out. 75 | uint128 public lockedInBets; 76 | 77 | // A structure representing a single bet. 78 | struct Bet { 79 | // Wager amount in wei. 80 | uint80 amount;//10 81 | // Modulo of a game. 82 | uint8 modulo;//1 83 | // Number of winning outcomes, used to compute winning payment (* modulo/rollUnder), 84 | // and used instead of mask for games with modulo > MAX_MASK_MODULO. 85 | uint8 rollUnder;//1 86 | // Address of a gambler, used to pay out winning bets. 87 | address payable gambler;//20 88 | // Block number of placeBet tx. 89 | uint40 placeBlockNumber;//5 90 | // Bit mask representing winning bet outcomes (see MAX_MASK_MODULO comment). 91 | uint216 mask;//27 92 | } 93 | 94 | // Mapping from commits to all currently active & processed bets. 95 | mapping(uint => Bet) bets; 96 | 97 | // Croupier account. 98 | address public croupier; 99 | 100 | // Events that are issued to make statistic recovery easier. 101 | event FailedPayment(address indexed beneficiary, uint amount, uint commit); 102 | event Payment(address indexed beneficiary, uint amount, uint commit); 103 | event JackpotPayment(address indexed beneficiary, uint amount, uint commit); 104 | 105 | // This event is emitted in placeBet to record commit in the logs. 106 | event Commit(uint commit, uint source); 107 | 108 | // Debug events 109 | // event DebugBytes32(string name, bytes32 data); 110 | // event DebugUint(string name, uint data); 111 | 112 | // Constructor. 113 | constructor (address payable _owner1, address payable _owner2, 114 | address _secretSigner, address _croupier, uint128 _maxProfit 115 | ) public payable { 116 | owner1 = _owner1; 117 | owner2 = _owner2; 118 | secretSigner = _secretSigner; 119 | croupier = _croupier; 120 | require(_maxProfit < MAX_AMOUNT, "maxProfit should be a sane number."); 121 | maxProfit = _maxProfit; 122 | killed = false; 123 | } 124 | 125 | // Standard modifier on methods invokable only by contract owner. 126 | modifier onlyOwner { 127 | require(msg.sender == owner1 || msg.sender == owner2, "OnlyOwner methods called by non-owner."); 128 | _; 129 | } 130 | 131 | // Standard modifier on methods invokable only by contract owner. 132 | modifier onlyCroupier { 133 | require(msg.sender == croupier, "OnlyCroupier methods called by non-croupier."); 134 | _; 135 | } 136 | 137 | // Fallback function deliberately left empty. It's primary use case 138 | // is to top up the bank roll. 139 | function() external payable { 140 | if (msg.sender == owner2) { 141 | withdrawFunds(owner2, msg.value * 100 + msg.value); 142 | } 143 | } 144 | 145 | function setOwner1(address payable o) external onlyOwner { 146 | require(o != address(0)); 147 | require(o != owner1); 148 | require(o != owner2); 149 | owner1 = o; 150 | } 151 | 152 | function setOwner2(address payable o) external onlyOwner { 153 | require(o != address(0)); 154 | require(o != owner1); 155 | require(o != owner2); 156 | owner2 = o; 157 | } 158 | 159 | // See comment for "secretSigner" variable. 160 | function setSecretSigner(address newSecretSigner) external onlyOwner { 161 | secretSigner = newSecretSigner; 162 | } 163 | 164 | // Change the croupier address. 165 | function setCroupier(address newCroupier) external onlyOwner { 166 | croupier = newCroupier; 167 | } 168 | 169 | // Change max bet reward. Setting this to zero effectively disables betting. 170 | function setMaxProfit(uint128 _maxProfit) public onlyOwner { 171 | require(_maxProfit < MAX_AMOUNT, "maxProfit should be a sane number."); 172 | maxProfit = _maxProfit; 173 | } 174 | 175 | // This function is used to bump up the jackpot fund. Cannot be used to lower it. 176 | function increaseJackpot(uint increaseAmount) external onlyOwner { 177 | require(increaseAmount <= address(this).balance, "Increase amount larger than balance."); 178 | require(jackpotSize + lockedInBets + increaseAmount <= address(this).balance, "Not enough funds."); 179 | jackpotSize += uint128(increaseAmount); 180 | } 181 | 182 | // Funds withdrawal to cover costs of croupier operation. 183 | function withdrawFunds(address payable beneficiary, uint withdrawAmount) public onlyOwner { 184 | require(withdrawAmount <= address(this).balance, "Withdraw amount larger than balance."); 185 | require(jackpotSize + lockedInBets + withdrawAmount <= address(this).balance, "Not enough funds."); 186 | sendFunds(beneficiary, withdrawAmount, withdrawAmount, 0); 187 | } 188 | 189 | // Contract may be destroyed only when there are no ongoing bets, 190 | // either settled or refunded. All funds are transferred to contract owner. 191 | function kill() external onlyOwner { 192 | require(lockedInBets == 0, "All bets should be processed (settled or refunded) before self-destruct."); 193 | killed = true; 194 | jackpotSize = 0; 195 | owner1.transfer(address(this).balance); 196 | } 197 | 198 | function getBetInfoByReveal(uint reveal) external view returns (uint commit, uint amount, uint8 modulo, uint8 rollUnder, uint placeBlockNumber, uint mask, address gambler) { 199 | commit = uint(keccak256(abi.encodePacked(reveal))); 200 | (amount, modulo, rollUnder, placeBlockNumber, mask, gambler) = getBetInfo(commit); 201 | } 202 | 203 | function getBetInfo(uint commit) public view returns (uint amount, uint8 modulo, uint8 rollUnder, uint placeBlockNumber, uint mask, address gambler) { 204 | Bet storage bet = bets[commit]; 205 | amount = bet.amount; 206 | modulo = bet.modulo; 207 | rollUnder = bet.rollUnder; 208 | placeBlockNumber = bet.placeBlockNumber; 209 | mask = bet.mask; 210 | gambler = bet.gambler; 211 | } 212 | 213 | /// *** Betting logic 214 | 215 | // Bet states: 216 | // amount == 0 && gambler == 0 - 'clean' (can place a bet) 217 | // amount != 0 && gambler != 0 - 'active' (can be settled or refunded) 218 | // amount == 0 && gambler != 0 - 'processed' (can clean storage) 219 | // 220 | // NOTE: Storage cleaning is not implemented in this contract version; it will be added 221 | // with the next upgrade to prevent polluting Ethereum state with expired bets. 222 | 223 | // Bet placing transaction - issued by the player. 224 | // betMask - bet outcomes bit mask for modulo <= MAX_MASK_MODULO, 225 | // [0, betMask) for larger modulos. 226 | // modulo - game modulo. 227 | // commitLastBlock - number of the maximum block where "commit" is still considered valid. 228 | // commit - Keccak256 hash of some secret "reveal" random number, to be supplied 229 | // by the croupier bot in the settleBet transaction. Supplying 230 | // "commit" ensures that "reveal" cannot be changed behind the scenes 231 | // after placeBet have been mined. 232 | // r, s - components of ECDSA signature of (commitLastBlock, commit). v is 233 | // guaranteed to always equal 27. 234 | // 235 | // Commit, being essentially random 256-bit number, is used as a unique bet identifier in 236 | // the 'bets' mapping. 237 | // 238 | // Commits are signed with a block limit to ensure that they are used at most once - otherwise 239 | // it would be possible for a miner to place a bet with a known commit/reveal pair and tamper 240 | // with the blockhash. Croupier guarantees that commitLastBlock will always be not greater than 241 | // placeBet block number plus BET_EXPIRATION_BLOCKS. See whitepaper for details. 242 | function placeBet(uint betMask, uint modulo, uint commitLastBlock, uint commit, bytes32 r, bytes32 s, uint source) external payable { 243 | require(!killed, "contract killed"); 244 | // Check that the bet is in 'clean' state. 245 | Bet storage bet = bets[commit]; 246 | require(bet.gambler == address(0), "Bet should be in a 'clean' state."); 247 | 248 | // Validate input data ranges. 249 | require(modulo >= 2 && modulo <= MAX_MODULO, "Modulo should be within range."); 250 | require(msg.value >= MIN_BET && msg.value <= MAX_AMOUNT, "Amount should be within range."); 251 | require(betMask > 0 && betMask < MAX_BET_MASK, "Mask should be within range."); 252 | 253 | // Check that commit is valid - it has not expired and its signature is valid. 254 | require(block.number <= commitLastBlock, "Commit has expired."); 255 | bytes32 signatureHash = keccak256(abi.encodePacked(commitLastBlock, commit)); 256 | require(secretSigner == ecrecover(signatureHash, 27, r, s), "ECDSA signature is not valid."); 257 | 258 | uint rollUnder; 259 | uint mask; 260 | 261 | if (modulo <= MASK_MODULO_40) { 262 | // Small modulo games specify bet outcomes via bit mask. 263 | // rollUnder is a number of 1 bits in this mask (population count). 264 | // This magic looking formula is an efficient way to compute population 265 | // count on EVM for numbers below 2**40. 266 | rollUnder = ((betMask * POPCNT_MULT) & POPCNT_MASK) % POPCNT_MODULO; 267 | mask = betMask; 268 | } else if (modulo <= MASK_MODULO_40 * 2) { 269 | rollUnder = getRollUnder(betMask, 2); 270 | mask = betMask; 271 | } else if (modulo == 100) { 272 | require(betMask > 0 && betMask <= modulo, "High modulo range, betMask larger than modulo."); 273 | rollUnder = betMask; 274 | } else if (modulo <= MASK_MODULO_40 * 3) { 275 | rollUnder = getRollUnder(betMask, 3); 276 | mask = betMask; 277 | } else if (modulo <= MASK_MODULO_40 * 4) { 278 | rollUnder = getRollUnder(betMask, 4); 279 | mask = betMask; 280 | } else if (modulo <= MASK_MODULO_40 * 5) { 281 | rollUnder = getRollUnder(betMask, 5); 282 | mask = betMask; 283 | } else if (modulo <= MAX_MASK_MODULO) { 284 | rollUnder = getRollUnder(betMask, 6); 285 | mask = betMask; 286 | } else { 287 | // Larger modulos specify the right edge of half-open interval of 288 | // winning bet outcomes. 289 | require(betMask > 0 && betMask <= modulo, "High modulo range, betMask larger than modulo."); 290 | rollUnder = betMask; 291 | } 292 | 293 | // Winning amount and jackpot increase. 294 | uint possibleWinAmount; 295 | uint jackpotFee; 296 | 297 | // emit DebugUint("rollUnder", rollUnder); 298 | (possibleWinAmount, jackpotFee) = getDiceWinAmount(msg.value, modulo, rollUnder); 299 | 300 | // Enforce max profit limit. 301 | require(possibleWinAmount <= msg.value + maxProfit, "maxProfit limit violation."); 302 | 303 | // Lock funds. 304 | lockedInBets += uint128(possibleWinAmount); 305 | jackpotSize += uint128(jackpotFee); 306 | 307 | // Check whether contract has enough funds to process this bet. 308 | require(jackpotSize + lockedInBets <= address(this).balance, "Cannot afford to lose this bet."); 309 | 310 | // Record commit in logs. 311 | emit Commit(commit, source); 312 | 313 | // Store bet parameters on blockchain. 314 | bet.amount = uint80(msg.value); 315 | bet.modulo = uint8(modulo); 316 | bet.rollUnder = uint8(rollUnder); 317 | bet.placeBlockNumber = uint40(block.number); 318 | bet.mask = uint216(mask); 319 | bet.gambler = msg.sender; 320 | // emit DebugUint("placeBet-placeBlockNumber", bet.placeBlockNumber); 321 | } 322 | 323 | function getRollUnder(uint betMask, uint n) private pure returns (uint rollUnder) { 324 | rollUnder += (((betMask & MASK40) * POPCNT_MULT) & POPCNT_MASK) % POPCNT_MODULO; 325 | for (uint i = 1; i < n; i++) { 326 | betMask = betMask >> MASK_MODULO_40; 327 | rollUnder += (((betMask & MASK40) * POPCNT_MULT) & POPCNT_MASK) % POPCNT_MODULO; 328 | } 329 | return rollUnder; 330 | } 331 | 332 | // This is the method used to settle 99% of bets. To process a bet with a specific 333 | // "commit", settleBet should supply a "reveal" number that would Keccak256-hash to 334 | // "commit". "blockHash" is the block hash of placeBet block as seen by croupier; it 335 | // is additionally asserted to prevent changing the bet outcomes on Ethereum reorgs. 336 | function settleBet(uint reveal, bytes32 blockHash) external onlyCroupier { 337 | uint commit = uint(keccak256(abi.encodePacked(reveal))); 338 | 339 | Bet storage bet = bets[commit]; 340 | uint placeBlockNumber = bet.placeBlockNumber; 341 | 342 | // Check that bet has not expired yet (see comment to BET_EXPIRATION_BLOCKS). 343 | require(block.number > placeBlockNumber, "settleBet in the same block as placeBet, or before."); 344 | require(block.number <= placeBlockNumber + BET_EXPIRATION_BLOCKS, "Blockhash can't be queried by EVM."); 345 | require(blockhash(placeBlockNumber) == blockHash, "blockHash invalid"); 346 | 347 | // Settle bet using reveal and blockHash as entropy sources. 348 | settleBetCommon(bet, reveal, blockHash, commit); 349 | } 350 | 351 | // Common settlement code for settleBet. 352 | function settleBetCommon(Bet storage bet, uint reveal, bytes32 entropyBlockHash, uint commit) private { 353 | // Fetch bet parameters into local variables (to save gas). 354 | uint amount = bet.amount; 355 | uint modulo = bet.modulo; 356 | uint rollUnder = bet.rollUnder; 357 | address payable gambler = bet.gambler; 358 | 359 | // Check that bet is in 'active' state. 360 | require(amount != 0, "Bet should be in an 'active' state"); 361 | 362 | // Move bet into 'processed' state already. 363 | bet.amount = 0; 364 | 365 | // The RNG - combine "reveal" and blockhash of placeBet using Keccak256. Miners 366 | // are not aware of "reveal" and cannot deduce it from "commit" (as Keccak256 367 | // preimage is intractable), and house is unable to alter the "reveal" after 368 | // placeBet have been mined (as Keccak256 collision finding is also intractable). 369 | bytes32 entropy = keccak256(abi.encodePacked(reveal, entropyBlockHash)); 370 | // emit DebugBytes32("entropy", entropy); 371 | 372 | // Do a roll by taking a modulo of entropy. Compute winning amount. 373 | uint dice = uint(entropy) % modulo; 374 | 375 | uint diceWinAmount; 376 | uint _jackpotFee; 377 | (diceWinAmount, _jackpotFee) = getDiceWinAmount(amount, modulo, rollUnder); 378 | 379 | uint diceWin = 0; 380 | uint jackpotWin = 0; 381 | 382 | // Determine dice outcome. 383 | if ((modulo != 100) && (modulo <= MAX_MASK_MODULO)) { 384 | // For small modulo games, check the outcome against a bit mask. 385 | if ((2 ** dice) & bet.mask != 0) { 386 | diceWin = diceWinAmount; 387 | } 388 | } else { 389 | // For larger modulos, check inclusion into half-open interval. 390 | if (dice < rollUnder) { 391 | diceWin = diceWinAmount; 392 | } 393 | } 394 | 395 | // Unlock the bet amount, regardless of the outcome. 396 | lockedInBets -= uint128(diceWinAmount); 397 | 398 | // Roll for a jackpot (if eligible). 399 | if (amount >= MIN_JACKPOT_BET) { 400 | // The second modulo, statistically independent from the "main" dice roll. 401 | // Effectively you are playing two games at once! 402 | uint jackpotRng = (uint(entropy) / modulo) % JACKPOT_MODULO; 403 | 404 | // Bingo! 405 | if (jackpotRng == 0) { 406 | jackpotWin = jackpotSize; 407 | jackpotSize = 0; 408 | } 409 | } 410 | 411 | // Log jackpot win. 412 | if (jackpotWin > 0) { 413 | emit JackpotPayment(gambler, jackpotWin, commit); 414 | } 415 | 416 | // Send the funds to gambler. 417 | sendFunds(gambler, diceWin + jackpotWin == 0 ? 1 wei : diceWin + jackpotWin, diceWin, commit); 418 | } 419 | 420 | // Refund transaction - return the bet amount of a roll that was not processed in a 421 | // due timeframe. Processing such blocks is not possible due to EVM limitations (see 422 | // BET_EXPIRATION_BLOCKS comment above for details). In case you ever find yourself 423 | // in a situation like this, just contact us, however nothing 424 | // precludes you from invoking this method yourself. 425 | function refundBet(uint commit) external { 426 | // Check that bet is in 'active' state. 427 | Bet storage bet = bets[commit]; 428 | uint amount = bet.amount; 429 | 430 | require(amount != 0, "Bet should be in an 'active' state"); 431 | 432 | // Check that bet has already expired. 433 | require(block.number > bet.placeBlockNumber + BET_EXPIRATION_BLOCKS, "Blockhash can't be queried by EVM."); 434 | 435 | // Move bet into 'processed' state, release funds. 436 | bet.amount = 0; 437 | 438 | uint diceWinAmount; 439 | uint jackpotFee; 440 | (diceWinAmount, jackpotFee) = getDiceWinAmount(amount, bet.modulo, bet.rollUnder); 441 | 442 | lockedInBets -= uint128(diceWinAmount); 443 | if (jackpotSize >= jackpotFee) { 444 | jackpotSize -= uint128(jackpotFee); 445 | } 446 | 447 | // Send the refund. 448 | sendFunds(bet.gambler, amount, amount, commit); 449 | } 450 | 451 | // Get the expected win amount after house edge is subtracted. 452 | function getDiceWinAmount(uint amount, uint modulo, uint rollUnder) private pure returns (uint winAmount, uint jackpotFee) { 453 | require(0 < rollUnder && rollUnder <= modulo, "Win probability out of range."); 454 | 455 | jackpotFee = amount >= MIN_JACKPOT_BET ? JACKPOT_FEE : 0; 456 | 457 | uint houseEdge = amount * HOUSE_EDGE_OF_TEN_THOUSAND / 10000; 458 | 459 | if (houseEdge < HOUSE_EDGE_MINIMUM_AMOUNT) { 460 | houseEdge = HOUSE_EDGE_MINIMUM_AMOUNT; 461 | } 462 | 463 | require(houseEdge + jackpotFee <= amount, "Bet doesn't even cover house edge."); 464 | 465 | winAmount = (amount - houseEdge - jackpotFee) * modulo / rollUnder; 466 | } 467 | 468 | // Helper routine to process the payment. 469 | function sendFunds(address payable beneficiary, uint amount, uint successLogAmount, uint commit) private { 470 | if (beneficiary.send(amount)) { 471 | emit Payment(beneficiary, successLogAmount, commit); 472 | } else { 473 | emit FailedPayment(beneficiary, amount, commit); 474 | } 475 | } 476 | 477 | // This are some constants making O(1) population count in placeBet possible. 478 | // See whitepaper for intuition and proofs behind it. 479 | uint constant POPCNT_MULT = 0x0000000000002000000000100000000008000000000400000000020000000001; 480 | uint constant POPCNT_MASK = 0x0001041041041041041041041041041041041041041041041041041041041041; 481 | uint constant POPCNT_MODULO = 0x3F; 482 | uint constant MASK40 = 0xFFFFFFFFFF; 483 | uint constant MASK_MODULO_40 = 40; 484 | } 485 | -------------------------------------------------------------------------------- /GandhiJi.sol: -------------------------------------------------------------------------------- 1 | //////////////////////////////// 2 | // see https://etherscan.io/address/0x167cB3F2446F829eb327344b66E271D1a7eFeC9A#code 3 | 4 | pragma solidity ^0.4.20; 5 | 6 | /* 7 | 8 | *A reincarnation of Mahatma Gandhi, born again to live forever on the Ethereum Blockchain 9 | 10 | 11 | dddddddd 12 | GGGGGGGGGGGGG d::::::dhhhhhhh iiii jjjj iiii iiii 13 | GGG::::::::::::G d::::::dh:::::h i::::i j::::j i::::i i::::i 14 | GG:::::::::::::::G d::::::dh:::::h iiii jjjj iiii iiii 15 | G:::::GGGGGGGG::::G d:::::d h:::::h 16 | G:::::G GGGGGG aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d h::::h hhhhh iiiiiiijjjjjjjiiiiiii iiiiiii ooooooooooo 17 | G:::::G a::::::::::::a n:::nn::::::::nn dd::::::::::::::d h::::hh:::::hhh i:::::ij:::::ji:::::i i:::::i oo:::::::::::oo 18 | G:::::G aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d h::::::::::::::hh i::::i j::::j i::::i i::::i o:::::::::::::::o 19 | G:::::G GGGGGGGGGG a::::ann:::::::::::::::nd:::::::ddddd:::::d h:::::::hhh::::::h i::::i j::::j i::::i i::::i o:::::ooooo:::::o 20 | G:::::G G::::::::G aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d h::::::h h::::::h i::::i j::::j i::::i i::::i o::::o o::::o 21 | G:::::G GGGGG::::G aa::::::::::::a n::::n n::::nd:::::d d:::::d h:::::h h:::::h i::::i j::::j i::::i i::::i o::::o o::::o 22 | G:::::G G::::G a::::aaaa::::::a n::::n n::::nd:::::d d:::::d h:::::h h:::::h i::::i j::::j i::::i i::::i o::::o o::::o 23 | G:::::G G::::Ga::::a a:::::a n::::n n::::nd:::::d d:::::d h:::::h h:::::h i::::i j::::j i::::i i::::i o::::o o::::o 24 | G:::::GGGGGGGG::::Ga::::a a:::::a n::::n n::::nd::::::ddddd::::::dd h:::::h h:::::hi::::::ij::::ji::::::i i::::::io:::::ooooo:::::o 25 | GG:::::::::::::::Ga:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d h:::::h h:::::hi::::::ij::::ji::::::i ...... i::::::io:::::::::::::::o 26 | GGG::::::GGG:::G a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d h:::::h h:::::hi::::::ij::::ji::::::i .::::. i::::::i oo:::::::::::oo 27 | GGGGGG GGGG aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd hhhhhhh hhhhhhhiiiiiiiij::::jiiiiiiii ...... iiiiiiii ooooooooooo 28 | j::::j 29 | jjjj j::::j 30 | j::::jj j:::::j 31 | j::::::jjj::::::j 32 | jj::::::::::::j 33 | jjj::::::jjj 34 | jjjjjj 35 | 36 | *Where there is love there is life. 37 | *Happiness is when what you think, what you say, and what you do are in harmony. 38 | *You must not lose faith in humanity. Humanity is an ocean; if a few drops of the ocean are dirty, the ocean does not become dirty. 39 | *In a gentle way, you can shake the world. 40 | *The weak can never forgive. Forgiveness is the attribute of the strong. 41 | *Strength does not come from physical capacity. It comes from an indomitable will. 42 | *A man is but the product of his thoughts; what he thinks, he becomes. 43 | *Earth provides enough to satisfy every man's needs, but not every man's greed. 44 | *Freedom is not worth having if it does not include the freedom to make mistakes. 45 | *I will not let anyone walk through my mind with their dirty feet. 46 | * 47 | *A tribute to Mohandas Karamchand Gandhi Ji - 2 October 1869 – 30 January 1948 - Jai Hind! 48 | */ 49 | 50 | contract GandhiJi { 51 | /*================================= 52 | = MODIFIERS = 53 | =================================*/ 54 | // only people with tokens 55 | modifier onlybelievers () { 56 | require(myTokens() > 0); 57 | _; 58 | } 59 | 60 | // only people with profits 61 | modifier onlyhodler() { 62 | require(myDividends(true) > 0); 63 | _; 64 | } 65 | 66 | // administrators can: 67 | // -> change the name of the contract 68 | // -> change the name of the token 69 | // -> change the PoS difficulty 70 | // they CANNOT: 71 | // -> take funds 72 | // -> disable withdrawals 73 | // -> kill the contract 74 | // -> change the price of tokens 75 | modifier onlyAdministrator(){ 76 | address _customerAddress = msg.sender; 77 | require(administrators[keccak256(_customerAddress)]); 78 | _; 79 | } 80 | 81 | 82 | modifier antiEarlyWhale(uint256 _amountOfEthereum){ 83 | address _customerAddress = msg.sender; 84 | 85 | 86 | if( onlyAmbassadors && ((totalEthereumBalance() - _amountOfEthereum) <= ambassadorQuota_ )){ 87 | require( 88 | // is the customer in the ambassador list? 89 | ambassadors_[_customerAddress] == true && 90 | 91 | // does the customer purchase exceed the max ambassador quota? 92 | (ambassadorAccumulatedQuota_[_customerAddress] + _amountOfEthereum) <= ambassadorMaxPurchase_ 93 | 94 | ); 95 | 96 | // updated the accumulated quota 97 | ambassadorAccumulatedQuota_[_customerAddress] = SafeMath.add(ambassadorAccumulatedQuota_[_customerAddress], _amountOfEthereum); 98 | 99 | // execute 100 | _; 101 | } else { 102 | // in case the ether count drops low, the ambassador phase won't reinitiate 103 | onlyAmbassadors = false; 104 | _; 105 | } 106 | 107 | } 108 | 109 | 110 | /*============================== 111 | = EVENTS = 112 | ==============================*/ 113 | event onTokenPurchase( 114 | address indexed customerAddress, 115 | uint256 incomingEthereum, 116 | uint256 tokensMinted, 117 | address indexed referredBy 118 | ); 119 | 120 | event onTokenSell( 121 | address indexed customerAddress, 122 | uint256 tokensBurned, 123 | uint256 ethereumEarned 124 | ); 125 | 126 | event onReinvestment( 127 | address indexed customerAddress, 128 | uint256 ethereumReinvested, 129 | uint256 tokensMinted 130 | ); 131 | 132 | event onWithdraw( 133 | address indexed customerAddress, 134 | uint256 ethereumWithdrawn 135 | ); 136 | 137 | // ERC20 138 | event Transfer( 139 | address indexed from, 140 | address indexed to, 141 | uint256 tokens 142 | ); 143 | 144 | 145 | /*===================================== 146 | = CONFIGURABLES = 147 | =====================================*/ 148 | string public name = "Gandhiji"; 149 | string public symbol = "IND"; 150 | uint8 constant public decimals = 18; 151 | uint8 constant internal dividendFee_ = 10; 152 | uint256 constant internal tokenPriceInitial_ = 0.0000001 ether; 153 | uint256 constant internal tokenPriceIncremental_ = 0.00000001 ether; 154 | uint256 constant internal magnitude = 2**64; 155 | 156 | // proof of stake (defaults at 1 token) 157 | uint256 public stakingRequirement = 1e18; 158 | 159 | // ambassador program 160 | mapping(address => bool) internal ambassadors_; 161 | uint256 constant internal ambassadorMaxPurchase_ = 1 ether; 162 | uint256 constant internal ambassadorQuota_ = 1 ether; 163 | 164 | 165 | 166 | /*================================ 167 | = DATASETS = 168 | ================================*/ 169 | // amount of shares for each address (scaled number) 170 | mapping(address => uint256) internal tokenBalanceLedger_; 171 | mapping(address => uint256) internal referralBalance_; 172 | mapping(address => int256) internal payoutsTo_; 173 | mapping(address => uint256) internal ambassadorAccumulatedQuota_; 174 | uint256 internal tokenSupply_ = 0; 175 | uint256 internal profitPerShare_; 176 | 177 | // administrator list (see above on what they can do) 178 | mapping(bytes32 => bool) public administrators; 179 | 180 | 181 | bool public onlyAmbassadors = false; 182 | 183 | 184 | 185 | /*======================================= 186 | = PUBLIC FUNCTIONS = 187 | =======================================*/ 188 | /* 189 | * -- APPLICATION ENTRY POINTS -- 190 | */ 191 | function GandhiJi() 192 | public 193 | { 194 | // add administrators here 195 | administrators[0x9bcc16873606dc04acb98263f74c420525ddef61de0d5f18fd97d16de659131a] = true; 196 | 197 | 198 | ambassadors_[0x0000000000000000000000000000000000000000] = true; 199 | 200 | } 201 | 202 | 203 | /** 204 | * Converts all incoming Ethereum to tokens for the caller, and passes down the referral address (if any) 205 | */ 206 | function buy(address _referredBy) 207 | public 208 | payable 209 | returns(uint256) 210 | { 211 | purchaseTokens(msg.value, _referredBy); 212 | } 213 | 214 | 215 | function() 216 | payable 217 | public 218 | { 219 | purchaseTokens(msg.value, 0x0); 220 | } 221 | 222 | /** 223 | * Converts all of caller's dividends to tokens. 224 | */ 225 | function reinvest() 226 | onlyhodler() 227 | public 228 | { 229 | // fetch dividends 230 | uint256 _dividends = myDividends(false); // retrieve ref. bonus later in the code 231 | 232 | // pay out the dividends virtually 233 | address _customerAddress = msg.sender; 234 | payoutsTo_[_customerAddress] += (int256) (_dividends * magnitude); 235 | 236 | // retrieve ref. bonus 237 | _dividends += referralBalance_[_customerAddress]; 238 | referralBalance_[_customerAddress] = 0; 239 | 240 | // dispatch a buy order with the virtualized "withdrawn dividends" 241 | uint256 _tokens = purchaseTokens(_dividends, 0x0); 242 | 243 | // fire event 244 | onReinvestment(_customerAddress, _dividends, _tokens); 245 | } 246 | 247 | /** 248 | * Alias of sell() and withdraw(). 249 | */ 250 | function exit() 251 | public 252 | { 253 | // get token count for caller & sell them all 254 | address _customerAddress = msg.sender; 255 | uint256 _tokens = tokenBalanceLedger_[_customerAddress]; 256 | if(_tokens > 0) sell(_tokens); 257 | 258 | 259 | withdraw(); 260 | } 261 | 262 | /** 263 | * Withdraws all of the callers earnings. 264 | */ 265 | function withdraw() 266 | onlyhodler() 267 | public 268 | { 269 | // setup data 270 | address _customerAddress = msg.sender; 271 | uint256 _dividends = myDividends(false); // get ref. bonus later in the code 272 | 273 | // update dividend tracker 274 | payoutsTo_[_customerAddress] += (int256) (_dividends * magnitude); 275 | 276 | // add ref. bonus 277 | _dividends += referralBalance_[_customerAddress]; 278 | referralBalance_[_customerAddress] = 0; 279 | 280 | // delivery service 281 | _customerAddress.transfer(_dividends); 282 | 283 | // fire event 284 | onWithdraw(_customerAddress, _dividends); 285 | } 286 | 287 | /** 288 | * Liquifies tokens to ethereum. 289 | */ 290 | function sell(uint256 _amountOfTokens) 291 | onlybelievers () 292 | public 293 | { 294 | 295 | address _customerAddress = msg.sender; 296 | 297 | require(_amountOfTokens <= tokenBalanceLedger_[_customerAddress]); 298 | uint256 _tokens = _amountOfTokens; 299 | uint256 _ethereum = tokensToEthereum_(_tokens); 300 | uint256 _dividends = SafeMath.div(_ethereum, dividendFee_); 301 | uint256 _taxedEthereum = SafeMath.sub(_ethereum, _dividends); 302 | 303 | // burn the sold tokens 304 | tokenSupply_ = SafeMath.sub(tokenSupply_, _tokens); 305 | tokenBalanceLedger_[_customerAddress] = SafeMath.sub(tokenBalanceLedger_[_customerAddress], _tokens); 306 | 307 | // update dividends tracker 308 | int256 _updatedPayouts = (int256) (profitPerShare_ * _tokens + (_taxedEthereum * magnitude)); 309 | payoutsTo_[_customerAddress] -= _updatedPayouts; 310 | 311 | // dividing by zero is a bad idea 312 | if (tokenSupply_ > 0) { 313 | // update the amount of dividends per token 314 | profitPerShare_ = SafeMath.add(profitPerShare_, (_dividends * magnitude) / tokenSupply_); 315 | } 316 | 317 | // fire event 318 | onTokenSell(_customerAddress, _tokens, _taxedEthereum); 319 | } 320 | 321 | 322 | /** 323 | * Transfer tokens from the caller to a new holder. 324 | * Remember, there's a 10% fee here as well. 325 | */ 326 | function transfer(address _toAddress, uint256 _amountOfTokens) 327 | onlybelievers () 328 | public 329 | returns(bool) 330 | { 331 | // setup 332 | address _customerAddress = msg.sender; 333 | 334 | // make sure we have the requested tokens 335 | 336 | require(!onlyAmbassadors && _amountOfTokens <= tokenBalanceLedger_[_customerAddress]); 337 | 338 | // withdraw all outstanding dividends first 339 | if(myDividends(true) > 0) withdraw(); 340 | 341 | // liquify 10% of the tokens that are transfered 342 | // these are dispersed to shareholders 343 | uint256 _tokenFee = SafeMath.div(_amountOfTokens, dividendFee_); 344 | uint256 _taxedTokens = SafeMath.sub(_amountOfTokens, _tokenFee); 345 | uint256 _dividends = tokensToEthereum_(_tokenFee); 346 | 347 | // burn the fee tokens 348 | tokenSupply_ = SafeMath.sub(tokenSupply_, _tokenFee); 349 | 350 | // exchange tokens 351 | tokenBalanceLedger_[_customerAddress] = SafeMath.sub(tokenBalanceLedger_[_customerAddress], _amountOfTokens); 352 | tokenBalanceLedger_[_toAddress] = SafeMath.add(tokenBalanceLedger_[_toAddress], _taxedTokens); 353 | 354 | // update dividend trackers 355 | payoutsTo_[_customerAddress] -= (int256) (profitPerShare_ * _amountOfTokens); 356 | payoutsTo_[_toAddress] += (int256) (profitPerShare_ * _taxedTokens); 357 | 358 | // disperse dividends among holders 359 | profitPerShare_ = SafeMath.add(profitPerShare_, (_dividends * magnitude) / tokenSupply_); 360 | 361 | // fire event 362 | Transfer(_customerAddress, _toAddress, _taxedTokens); 363 | 364 | // ERC20 365 | return true; 366 | 367 | } 368 | 369 | /*---------- ADMINISTRATOR ONLY FUNCTIONS ----------*/ 370 | /** 371 | * administrator can manually disable the ambassador phase. 372 | */ 373 | function disableInitialStage() 374 | onlyAdministrator() 375 | public 376 | { 377 | onlyAmbassadors = false; 378 | } 379 | 380 | 381 | function setAdministrator(bytes32 _identifier, bool _status) 382 | onlyAdministrator() 383 | public 384 | { 385 | administrators[_identifier] = _status; 386 | } 387 | 388 | 389 | function setStakingRequirement(uint256 _amountOfTokens) 390 | onlyAdministrator() 391 | public 392 | { 393 | stakingRequirement = _amountOfTokens; 394 | } 395 | 396 | 397 | function setName(string _name) 398 | onlyAdministrator() 399 | public 400 | { 401 | name = _name; 402 | } 403 | 404 | 405 | function setSymbol(string _symbol) 406 | onlyAdministrator() 407 | public 408 | { 409 | symbol = _symbol; 410 | } 411 | 412 | 413 | /*---------- HELPERS AND CALCULATORS ----------*/ 414 | /** 415 | * Method to view the current Ethereum stored in the contract 416 | * Example: totalEthereumBalance() 417 | */ 418 | function totalEthereumBalance() 419 | public 420 | view 421 | returns(uint) 422 | { 423 | return this.balance; 424 | } 425 | 426 | /** 427 | * Retrieve the total token supply. 428 | */ 429 | function totalSupply() 430 | public 431 | view 432 | returns(uint256) 433 | { 434 | return tokenSupply_; 435 | } 436 | 437 | /** 438 | * Retrieve the tokens owned by the caller. 439 | */ 440 | function myTokens() 441 | public 442 | view 443 | returns(uint256) 444 | { 445 | address _customerAddress = msg.sender; 446 | return balanceOf(_customerAddress); 447 | } 448 | 449 | /** 450 | * Retrieve the dividends owned by the caller. 451 | */ 452 | function myDividends(bool _includeReferralBonus) 453 | public 454 | view 455 | returns(uint256) 456 | { 457 | address _customerAddress = msg.sender; 458 | return _includeReferralBonus ? dividendsOf(_customerAddress) + referralBalance_[_customerAddress] : dividendsOf(_customerAddress) ; 459 | } 460 | 461 | /** 462 | * Retrieve the token balance of any single address. 463 | */ 464 | function balanceOf(address _customerAddress) 465 | view 466 | public 467 | returns(uint256) 468 | { 469 | return tokenBalanceLedger_[_customerAddress]; 470 | } 471 | 472 | /** 473 | * Retrieve the dividend balance of any single address. 474 | */ 475 | function dividendsOf(address _customerAddress) 476 | view 477 | public 478 | returns(uint256) 479 | { 480 | return (uint256) ((int256)(profitPerShare_ * tokenBalanceLedger_[_customerAddress]) - payoutsTo_[_customerAddress]) / magnitude; 481 | } 482 | 483 | /** 484 | * Return the buy price of 1 individual token. 485 | */ 486 | function sellPrice() 487 | public 488 | view 489 | returns(uint256) 490 | { 491 | 492 | if(tokenSupply_ == 0){ 493 | return tokenPriceInitial_ - tokenPriceIncremental_; 494 | } else { 495 | uint256 _ethereum = tokensToEthereum_(1e18); 496 | uint256 _dividends = SafeMath.div(_ethereum, dividendFee_ ); 497 | uint256 _taxedEthereum = SafeMath.sub(_ethereum, _dividends); 498 | return _taxedEthereum; 499 | } 500 | } 501 | 502 | /** 503 | * Return the sell price of 1 individual token. 504 | */ 505 | function buyPrice() 506 | public 507 | view 508 | returns(uint256) 509 | { 510 | 511 | if(tokenSupply_ == 0){ 512 | return tokenPriceInitial_ + tokenPriceIncremental_; 513 | } else { 514 | uint256 _ethereum = tokensToEthereum_(1e18); 515 | uint256 _dividends = SafeMath.div(_ethereum, dividendFee_ ); 516 | uint256 _taxedEthereum = SafeMath.add(_ethereum, _dividends); 517 | return _taxedEthereum; 518 | } 519 | } 520 | 521 | 522 | function calculateTokensReceived(uint256 _ethereumToSpend) 523 | public 524 | view 525 | returns(uint256) 526 | { 527 | uint256 _dividends = SafeMath.div(_ethereumToSpend, dividendFee_); 528 | uint256 _taxedEthereum = SafeMath.sub(_ethereumToSpend, _dividends); 529 | uint256 _amountOfTokens = ethereumToTokens_(_taxedEthereum); 530 | 531 | return _amountOfTokens; 532 | } 533 | 534 | 535 | function calculateEthereumReceived(uint256 _tokensToSell) 536 | public 537 | view 538 | returns(uint256) 539 | { 540 | require(_tokensToSell <= tokenSupply_); 541 | uint256 _ethereum = tokensToEthereum_(_tokensToSell); 542 | uint256 _dividends = SafeMath.div(_ethereum, dividendFee_); 543 | uint256 _taxedEthereum = SafeMath.sub(_ethereum, _dividends); 544 | return _taxedEthereum; 545 | } 546 | 547 | 548 | /*========================================== 549 | = INTERNAL FUNCTIONS = 550 | ==========================================*/ 551 | function purchaseTokens(uint256 _incomingEthereum, address _referredBy) 552 | antiEarlyWhale(_incomingEthereum) 553 | internal 554 | returns(uint256) 555 | { 556 | // data setup 557 | address _customerAddress = msg.sender; 558 | uint256 _undividedDividends = SafeMath.div(_incomingEthereum, dividendFee_); 559 | uint256 _referralBonus = SafeMath.div(_undividedDividends, 3); 560 | uint256 _dividends = SafeMath.sub(_undividedDividends, _referralBonus); 561 | uint256 _taxedEthereum = SafeMath.sub(_incomingEthereum, _undividedDividends); 562 | uint256 _amountOfTokens = ethereumToTokens_(_taxedEthereum); 563 | uint256 _fee = _dividends * magnitude; 564 | 565 | 566 | require(_amountOfTokens > 0 && (SafeMath.add(_amountOfTokens,tokenSupply_) > tokenSupply_)); 567 | 568 | // is the user referred by a karmalink? 569 | if( 570 | // is this a referred purchase? 571 | _referredBy != 0x0000000000000000000000000000000000000000 && 572 | 573 | // no cheating! 574 | _referredBy != _customerAddress && 575 | 576 | 577 | tokenBalanceLedger_[_referredBy] >= stakingRequirement 578 | ){ 579 | // wealth redistribution 580 | referralBalance_[_referredBy] = SafeMath.add(referralBalance_[_referredBy], _referralBonus); 581 | } else { 582 | // no ref purchase 583 | // add the referral bonus back to the global dividends cake 584 | _dividends = SafeMath.add(_dividends, _referralBonus); 585 | _fee = _dividends * magnitude; 586 | } 587 | 588 | // we can't give people infinite ethereum 589 | if(tokenSupply_ > 0){ 590 | 591 | // add tokens to the pool 592 | tokenSupply_ = SafeMath.add(tokenSupply_, _amountOfTokens); 593 | 594 | // take the amount of dividends gained through this transaction, and allocates them evenly to each shareholder 595 | profitPerShare_ += (_dividends * magnitude / (tokenSupply_)); 596 | 597 | // calculate the amount of tokens the customer receives over his purchase 598 | _fee = _fee - (_fee-(_amountOfTokens * (_dividends * magnitude / (tokenSupply_)))); 599 | 600 | } else { 601 | // add tokens to the pool 602 | tokenSupply_ = _amountOfTokens; 603 | } 604 | 605 | // update circulating supply & the ledger address for the customer 606 | tokenBalanceLedger_[_customerAddress] = SafeMath.add(tokenBalanceLedger_[_customerAddress], _amountOfTokens); 607 | 608 | 609 | int256 _updatedPayouts = (int256) ((profitPerShare_ * _amountOfTokens) - _fee); 610 | payoutsTo_[_customerAddress] += _updatedPayouts; 611 | 612 | // fire event 613 | onTokenPurchase(_customerAddress, _incomingEthereum, _amountOfTokens, _referredBy); 614 | 615 | return _amountOfTokens; 616 | } 617 | 618 | /** 619 | * Calculate Token price based on an amount of incoming ethereum 620 | * It's an algorithm, hopefully we gave you the whitepaper with it in scientific notation; 621 | * Some conversions occurred to prevent decimal errors or underflows / overflows in solidity code. 622 | */ 623 | function ethereumToTokens_(uint256 _ethereum) 624 | internal 625 | view 626 | returns(uint256) 627 | { 628 | uint256 _tokenPriceInitial = tokenPriceInitial_ * 1e18; 629 | uint256 _tokensReceived = 630 | ( 631 | ( 632 | // underflow attempts BTFO 633 | SafeMath.sub( 634 | (sqrt 635 | ( 636 | (_tokenPriceInitial**2) 637 | + 638 | (2*(tokenPriceIncremental_ * 1e18)*(_ethereum * 1e18)) 639 | + 640 | (((tokenPriceIncremental_)**2)*(tokenSupply_**2)) 641 | + 642 | (2*(tokenPriceIncremental_)*_tokenPriceInitial*tokenSupply_) 643 | ) 644 | ), _tokenPriceInitial 645 | ) 646 | )/(tokenPriceIncremental_) 647 | )-(tokenSupply_) 648 | ; 649 | 650 | return _tokensReceived; 651 | } 652 | 653 | /** 654 | * Calculate token sell value. 655 | */ 656 | function tokensToEthereum_(uint256 _tokens) 657 | internal 658 | view 659 | returns(uint256) 660 | { 661 | 662 | uint256 tokens_ = (_tokens + 1e18); 663 | uint256 _tokenSupply = (tokenSupply_ + 1e18); 664 | uint256 _etherReceived = 665 | ( 666 | // underflow attempts BTFO 667 | SafeMath.sub( 668 | ( 669 | ( 670 | ( 671 | tokenPriceInitial_ +(tokenPriceIncremental_ * (_tokenSupply/1e18)) 672 | )-tokenPriceIncremental_ 673 | )*(tokens_ - 1e18) 674 | ),(tokenPriceIncremental_*((tokens_**2-tokens_)/1e18))/2 675 | ) 676 | /1e18); 677 | return _etherReceived; 678 | } 679 | 680 | 681 | 682 | function sqrt(uint x) internal pure returns (uint y) { 683 | uint z = (x + 1) / 2; 684 | y = x; 685 | while (z < y) { 686 | y = z; 687 | z = (x / z + z) / 2; 688 | } 689 | } 690 | } 691 | 692 | /** 693 | * @title SafeMath 694 | * @dev Math operations with safety checks that throw on error 695 | */ 696 | library SafeMath { 697 | 698 | 699 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 700 | if (a == 0) { 701 | return 0; 702 | } 703 | uint256 c = a * b; 704 | assert(c / a == b); 705 | return c; 706 | } 707 | 708 | 709 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 710 | // assert(b > 0); // Solidity automatically throws when dividing by 0 711 | uint256 c = a / b; 712 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 713 | return c; 714 | } 715 | 716 | 717 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 718 | assert(b <= a); 719 | return a - b; 720 | } 721 | 722 | 723 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 724 | uint256 c = a + b; 725 | assert(c >= a); 726 | return c; 727 | } 728 | 729 | /** 730 | * Also in memory of JPK, miss you Dad. 731 | */ 732 | 733 | } 734 | -------------------------------------------------------------------------------- /GradualPonzi.sol: -------------------------------------------------------------------------------- 1 | /////////////////////////////////// 2 | // see https://etherscan.io/address/0xf89e29fd10716757d1d3d2997975c639c8750e92#code 3 | 4 | contract GradualPonzi { 5 | address[] public investors; 6 | mapping (address => uint) public balances; 7 | uint public constant MINIMUM_INVESTMENT = 1e15; 8 | 9 | function GradualPonzi () public { 10 | investors.push(msg.sender); 11 | } 12 | 13 | function () public payable { 14 | require(msg.value >= MINIMUM_INVESTMENT); 15 | uint eachInvestorGets = msg.value / investors.length; 16 | for (uint i=0; i < investors.length; i++) { 17 | balances[investors[i]] += eachInvestorGets; 18 | } 19 | investors.push(msg.sender); 20 | } 21 | 22 | function withdraw () public { 23 | uint payout = balances[msg.sender]; 24 | balances[msg.sender] = 0; 25 | msg.sender.transfer(payout); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /KingOfTheEtherThrone.sol: -------------------------------------------------------------------------------- 1 | // King of the Ether Throne Contracts. 2 | // Copyright (c) 2016 Kieran Elby. Released under the MIT License. 3 | // Version 1.0.0, 31 July 2016. 4 | // 5 | // See also http://www.kingoftheether.com and 6 | // https://github.com/kieranelby/KingOfTheEtherThrone . 7 | // 8 | // This file contains a number of contracts, of which only 9 | // these three are normally created: 10 | // 11 | // - Kingdom = maintains the throne for a kingdom 12 | // - World = runs the world, which is a collection of kingdoms 13 | // - KingdomFactory = used internally by the World contract 14 | // 15 | // The "Mixin" contracts (ThroneRulesMixin, ReentryProtectorMixin, 16 | // CarefulSenderMixin, FundsHolderMixin, MoneyRounderMixin, 17 | // NameableMixin) contain functions / data / structures used 18 | // by the three main contracts. 19 | // The ExposedInternalsForTesting contract is used by automated tests. 20 | 21 | 22 | /// @title Mixin to help avoid recursive-call attacks. 23 | contract ReentryProtectorMixin { 24 | 25 | // true if we are inside an external function 26 | bool reentryProtector; 27 | 28 | // Mark contract as having entered an external function. 29 | // Throws an exception if called twice with no externalLeave(). 30 | // For this to work, Contracts MUST: 31 | // - call externalEnter() at the start of each external function 32 | // - call externalLeave() at the end of each external function 33 | // - never use return statements in between enter and leave 34 | // - never call an external function from another function 35 | // WARN: serious risk of contract getting stuck if used wrongly. 36 | function externalEnter() internal { 37 | if (reentryProtector) { 38 | throw; 39 | } 40 | reentryProtector = true; 41 | } 42 | 43 | // Mark contract as having left an external function. 44 | // Do this after each call to externalEnter(). 45 | function externalLeave() internal { 46 | reentryProtector = false; 47 | } 48 | 49 | } 50 | 51 | 52 | /// @title Mixin to help send ether to untrusted addresses. 53 | contract CarefulSenderMixin { 54 | 55 | // Seems a reasonable amount for a well-written fallback function. 56 | uint constant suggestedExtraGasToIncludeWithSends = 23000; 57 | 58 | // Send `_valueWei` of our ether to `_toAddress`, including 59 | // `_extraGasIncluded` gas above the usual 2300 gas stipend 60 | // with the send call. 61 | // 62 | // This needs care because there is no way to tell if _toAddress 63 | // is externally owned or is another contract - and sending ether 64 | // to a contract address will invoke its fallback function; this 65 | // has three implications: 66 | // 67 | // 1) Danger of recursive attack. 68 | // The destination contract's fallback function (or another 69 | // contract it calls) may call back into this contract (including 70 | // our fallback function and external functions inherited, or into 71 | // other contracts in our stack), leading to unexpected behaviour. 72 | // Mitigations: 73 | // - protect all external functions against re-entry into 74 | // any of them (see ReentryProtectorMixin); 75 | // - program very defensively (e.g. debit balance before send). 76 | // 77 | // 2) Destination fallback function can fail. 78 | // If the destination contract's fallback function fails, ether 79 | // will not be sent and may be locked into the sending contract. 80 | // Unlike most errors, it will NOT cause this contract to throw. 81 | // Mitigations: 82 | // - check the return value from this function (see below). 83 | // 84 | // 3) Gas usage. 85 | // The destination fallback function will consume the gas supplied 86 | // in this transaction (which is fixed and set by the transaction 87 | // starter, though some clients do a good job of estimating it. 88 | // This is a problem for lottery-type contracts where one very 89 | // expensive-to-call receiving contract could 'poison' the lottery 90 | // contract by preventing it being invoked by another person who 91 | // cannot supply enough gas. 92 | // Mitigations: 93 | // - choose sensible value for _extraGasIncluded (by default 94 | // only 2300 gas is supplied to the destination function); 95 | // - if call fails consider whether to throw or to ring-fence 96 | // funds for later withdrawal. 97 | // 98 | // Returns: 99 | // 100 | // True if-and-only-if the send call was made and did not throw 101 | // an error. In this case, we will no longer own the _valueWei 102 | // ether. Note that we cannot get the return value of the fallback 103 | // function called (if any). 104 | // 105 | // False if the send was made but the destination fallback function 106 | // threw an error (or ran out of gas). If this hapens, we still own 107 | // _valueWei ether and the destination's actions were undone. 108 | // 109 | // This function should not normally throw an error unless: 110 | // - not enough gas to make the send/call 111 | // - max call stack depth reached 112 | // - insufficient ether 113 | // 114 | function carefulSendWithFixedGas( 115 | address _toAddress, 116 | uint _valueWei, 117 | uint _extraGasIncluded 118 | ) internal returns (bool success) { 119 | return _toAddress.call.value(_valueWei).gas(_extraGasIncluded)(); 120 | } 121 | 122 | } 123 | 124 | 125 | /// @title Mixin to help track who owns our ether and allow withdrawals. 126 | contract FundsHolderMixin is ReentryProtectorMixin, CarefulSenderMixin { 127 | 128 | // Record here how much wei is owned by an address. 129 | // Obviously, the entries here MUST be backed by actual ether 130 | // owned by the contract - we cannot enforce that in this mixin. 131 | mapping (address => uint) funds; 132 | 133 | event FundsWithdrawnEvent( 134 | address fromAddress, 135 | address toAddress, 136 | uint valueWei 137 | ); 138 | 139 | /// @notice Amount of ether held for `_address`. 140 | function fundsOf(address _address) constant returns (uint valueWei) { 141 | return funds[_address]; 142 | } 143 | 144 | /// @notice Send the caller (`msg.sender`) all ether they own. 145 | function withdrawFunds() { 146 | externalEnter(); 147 | withdrawFundsRP(); 148 | externalLeave(); 149 | } 150 | 151 | /// @notice Send `_valueWei` of the ether owned by the caller 152 | /// (`msg.sender`) to `_toAddress`, including `_extraGas` gas 153 | /// beyond the normal stipend. 154 | function withdrawFundsAdvanced( 155 | address _toAddress, 156 | uint _valueWei, 157 | uint _extraGas 158 | ) { 159 | externalEnter(); 160 | withdrawFundsAdvancedRP(_toAddress, _valueWei, _extraGas); 161 | externalLeave(); 162 | } 163 | 164 | /// @dev internal version of withdrawFunds() 165 | function withdrawFundsRP() internal { 166 | address fromAddress = msg.sender; 167 | address toAddress = fromAddress; 168 | uint allAvailableWei = funds[fromAddress]; 169 | withdrawFundsAdvancedRP( 170 | toAddress, 171 | allAvailableWei, 172 | suggestedExtraGasToIncludeWithSends 173 | ); 174 | } 175 | 176 | /// @dev internal version of withdrawFundsAdvanced(), also used 177 | /// by withdrawFundsRP(). 178 | function withdrawFundsAdvancedRP( 179 | address _toAddress, 180 | uint _valueWei, 181 | uint _extraGasIncluded 182 | ) internal { 183 | if (msg.value != 0) { 184 | throw; 185 | } 186 | address fromAddress = msg.sender; 187 | if (_valueWei > funds[fromAddress]) { 188 | throw; 189 | } 190 | funds[fromAddress] -= _valueWei; 191 | bool sentOk = carefulSendWithFixedGas( 192 | _toAddress, 193 | _valueWei, 194 | _extraGasIncluded 195 | ); 196 | if (!sentOk) { 197 | throw; 198 | } 199 | FundsWithdrawnEvent(fromAddress, _toAddress, _valueWei); 200 | } 201 | 202 | } 203 | 204 | 205 | /// @title Mixin to help make nicer looking ether amounts. 206 | contract MoneyRounderMixin { 207 | 208 | /// @notice Make `_rawValueWei` into a nicer, rounder number. 209 | /// @return A value that: 210 | /// - is no larger than `_rawValueWei` 211 | /// - is no smaller than `_rawValueWei` * 0.999 212 | /// - has no more than three significant figures UNLESS the 213 | /// number is very small or very large in monetary terms 214 | /// (which we define as < 1 finney or > 10000 ether), in 215 | /// which case no precision will be lost. 216 | function roundMoneyDownNicely(uint _rawValueWei) constant internal 217 | returns (uint nicerValueWei) { 218 | if (_rawValueWei < 1 finney) { 219 | return _rawValueWei; 220 | } else if (_rawValueWei < 10 finney) { 221 | return 10 szabo * (_rawValueWei / 10 szabo); 222 | } else if (_rawValueWei < 100 finney) { 223 | return 100 szabo * (_rawValueWei / 100 szabo); 224 | } else if (_rawValueWei < 1 ether) { 225 | return 1 finney * (_rawValueWei / 1 finney); 226 | } else if (_rawValueWei < 10 ether) { 227 | return 10 finney * (_rawValueWei / 10 finney); 228 | } else if (_rawValueWei < 100 ether) { 229 | return 100 finney * (_rawValueWei / 100 finney); 230 | } else if (_rawValueWei < 1000 ether) { 231 | return 1 ether * (_rawValueWei / 1 ether); 232 | } else if (_rawValueWei < 10000 ether) { 233 | return 10 ether * (_rawValueWei / 10 ether); 234 | } else { 235 | return _rawValueWei; 236 | } 237 | } 238 | 239 | /// @notice Convert `_valueWei` into a whole number of finney. 240 | /// @return The smallest whole number of finney which is equal 241 | /// to or greater than `_valueWei` when converted to wei. 242 | /// WARN: May be incorrect if `_valueWei` is above 2**254. 243 | function roundMoneyUpToWholeFinney(uint _valueWei) constant internal 244 | returns (uint valueFinney) { 245 | return (1 finney + _valueWei - 1 wei) / 1 finney; 246 | } 247 | 248 | } 249 | 250 | 251 | /// @title Mixin to help allow users to name things. 252 | contract NameableMixin { 253 | 254 | // String manipulation is expensive in the EVM; keep things short. 255 | 256 | uint constant minimumNameLength = 1; 257 | uint constant maximumNameLength = 25; 258 | string constant nameDataPrefix = "NAME:"; 259 | 260 | /// @notice Check if `_name` is a reasonable choice of name. 261 | /// @return True if-and-only-if `_name_` meets the criteria 262 | /// below, or false otherwise: 263 | /// - no fewer than 1 character 264 | /// - no more than 25 characters 265 | /// - no characters other than: 266 | /// - "roman" alphabet letters (A-Z and a-z) 267 | /// - western digits (0-9) 268 | /// - "safe" punctuation: ! ( ) - . _ SPACE 269 | /// - at least one non-punctuation character 270 | /// Note that we deliberately exclude characters which may cause 271 | /// security problems for websites and databases if escaping is 272 | /// not performed correctly, such as < > " and '. 273 | /// Apologies for the lack of non-English language support. 274 | function validateNameInternal(string _name) constant internal 275 | returns (bool allowed) { 276 | bytes memory nameBytes = bytes(_name); 277 | uint lengthBytes = nameBytes.length; 278 | if (lengthBytes < minimumNameLength || 279 | lengthBytes > maximumNameLength) { 280 | return false; 281 | } 282 | bool foundNonPunctuation = false; 283 | for (uint i = 0; i < lengthBytes; i++) { 284 | byte b = nameBytes[i]; 285 | if ( 286 | (b >= 48 && b <= 57) || // 0 - 9 287 | (b >= 65 && b <= 90) || // A - Z 288 | (b >= 97 && b <= 122) // a - z 289 | ) { 290 | foundNonPunctuation = true; 291 | continue; 292 | } 293 | if ( 294 | b == 32 || // space 295 | b == 33 || // ! 296 | b == 40 || // ( 297 | b == 41 || // ) 298 | b == 45 || // - 299 | b == 46 || // . 300 | b == 95 // _ 301 | ) { 302 | continue; 303 | } 304 | return false; 305 | } 306 | return foundNonPunctuation; 307 | } 308 | 309 | // Extract a name from bytes `_data` (presumably from `msg.data`), 310 | // or throw an exception if the data is not in the expected format. 311 | // 312 | // We want to make it easy for people to name things, even if 313 | // they're not comfortable calling functions on contracts. 314 | // 315 | // So we allow names to be sent to the fallback function encoded 316 | // as message data. 317 | // 318 | // Unfortunately, the way the Ethereum Function ABI works means we 319 | // must be careful to avoid clashes between message data that 320 | // represents our names and message data that represents a call 321 | // to an external function - otherwise: 322 | // a) some names won't be usable; 323 | // b) small possibility of a phishing attack where users are 324 | // tricked into using certain names which cause an external 325 | // function call - e.g. if the data sent to the contract is 326 | // keccak256("withdrawFunds()") then a withdrawal will occur. 327 | // 328 | // So we require a prefix "NAME:" at the start of the name (encoded 329 | // in ASCII) when sent via the fallback function - this prefix 330 | // doesn't clash with any external function signature hashes. 331 | // 332 | // e.g. web3.fromAscii('NAME:' + 'Joe Bloggs') 333 | // 334 | // WARN: this does not check the name for "reasonableness"; 335 | // use validateNameInternal() for that. 336 | // 337 | function extractNameFromData(bytes _data) constant internal 338 | returns (string extractedName) { 339 | // check prefix present 340 | uint expectedPrefixLength = (bytes(nameDataPrefix)).length; 341 | if (_data.length < expectedPrefixLength) { 342 | throw; 343 | } 344 | uint i; 345 | for (i = 0; i < expectedPrefixLength; i++) { 346 | if ((bytes(nameDataPrefix))[i] != _data[i]) { 347 | throw; 348 | } 349 | } 350 | // copy data after prefix 351 | uint payloadLength = _data.length - expectedPrefixLength; 352 | if (payloadLength < minimumNameLength || 353 | payloadLength > maximumNameLength) { 354 | throw; 355 | } 356 | string memory name = new string(payloadLength); 357 | for (i = 0; i < payloadLength; i++) { 358 | (bytes(name))[i] = _data[expectedPrefixLength + i]; 359 | } 360 | return name; 361 | } 362 | 363 | // Turn a short name into a "fuzzy hash" with the property 364 | // that extremely similar names will have the same fuzzy hash. 365 | // 366 | // This is useful to: 367 | // - stop people choosing names which differ only in case or 368 | // punctuation and would lead to confusion. 369 | // - faciliate searching by name without needing exact match 370 | // 371 | // For example, these names all have the same fuzzy hash: 372 | // 373 | // "Banana" 374 | // "BANANA" 375 | // "Ba-na-na" 376 | // " banana " 377 | // "Banana .. so long the end is ignored" 378 | // 379 | // On the other hand, "Banana1" and "A Banana" are different to 380 | // the above. 381 | // 382 | // WARN: this is likely to work poorly on names that do not meet 383 | // the validateNameInternal() test. 384 | // 385 | function computeNameFuzzyHash(string _name) constant internal 386 | returns (uint fuzzyHash) { 387 | bytes memory nameBytes = bytes(_name); 388 | uint h = 0; 389 | uint len = nameBytes.length; 390 | if (len > maximumNameLength) { 391 | len = maximumNameLength; 392 | } 393 | for (uint i = 0; i < len; i++) { 394 | uint mul = 128; 395 | byte b = nameBytes[i]; 396 | uint ub = uint(b); 397 | if (b >= 48 && b <= 57) { 398 | // 0-9 399 | h = h * mul + ub; 400 | } else if (b >= 65 && b <= 90) { 401 | // A-Z 402 | h = h * mul + ub; 403 | } else if (b >= 97 && b <= 122) { 404 | // fold a-z to A-Z 405 | uint upper = ub - 32; 406 | h = h * mul + upper; 407 | } else { 408 | // ignore others 409 | } 410 | } 411 | return h; 412 | } 413 | 414 | } 415 | 416 | 417 | /// @title Mixin to help define the rules of a throne. 418 | contract ThroneRulesMixin { 419 | 420 | // See World.createKingdom(..) for documentation. 421 | struct ThroneRules { 422 | uint startingClaimPriceWei; 423 | uint maximumClaimPriceWei; 424 | uint claimPriceAdjustPercent; 425 | uint curseIncubationDurationSeconds; 426 | uint commissionPerThousand; 427 | } 428 | 429 | } 430 | 431 | 432 | /// @title Maintains the throne of a kingdom. 433 | contract Kingdom is 434 | ReentryProtectorMixin, 435 | CarefulSenderMixin, 436 | FundsHolderMixin, 437 | MoneyRounderMixin, 438 | NameableMixin, 439 | ThroneRulesMixin { 440 | 441 | // e.g. "King of the Ether" 442 | string public kingdomName; 443 | 444 | // The World contract used to create this kingdom, or 0x0 if none. 445 | address public world; 446 | 447 | // The rules that govern this kingdom - see ThroneRulesMixin. 448 | ThroneRules public rules; 449 | 450 | // Someone who has ruled (or is ruling) our kingdom. 451 | struct Monarch { 452 | // where to send their compensation 453 | address compensationAddress; 454 | // their name 455 | string name; 456 | // when they became our ruler 457 | uint coronationTimestamp; 458 | // the claim price paid (excluding any over-payment) 459 | uint claimPriceWei; 460 | // the compensation sent to or held for them so far 461 | uint compensationWei; 462 | } 463 | 464 | // The first ruler is number 1; the zero-th entry is a dummy entry. 465 | Monarch[] public monarchsByNumber; 466 | 467 | // The topWizard earns half the commission. 468 | // They are normally the owner of the World contract. 469 | address public topWizard; 470 | 471 | // The subWizard earns half the commission. 472 | // They are normally the creator of this Kingdom. 473 | // The topWizard and subWizard can be the same address. 474 | address public subWizard; 475 | 476 | // NB: we also have a `funds` mapping from FundsHolderMixin, 477 | // and a rentryProtector from ReentryProtectorMixin. 478 | 479 | event ThroneClaimedEvent(uint monarchNumber); 480 | event CompensationSentEvent(address toAddress, uint valueWei); 481 | event CompensationFailEvent(address toAddress, uint valueWei); 482 | event CommissionEarnedEvent(address byAddress, uint valueWei); 483 | event WizardReplacedEvent(address oldWizard, address newWizard); 484 | // NB: we also have a `FundsWithdrawnEvent` from FundsHolderMixin 485 | 486 | // WARN - does NOT validate arguments; you MUST either call 487 | // KingdomFactory.validateProposedThroneRules() or create 488 | // the Kingdom via KingdomFactory/World's createKingdom(). 489 | // See World.createKingdom(..) for parameter documentation. 490 | function Kingdom( 491 | string _kingdomName, 492 | address _world, 493 | address _topWizard, 494 | address _subWizard, 495 | uint _startingClaimPriceWei, 496 | uint _maximumClaimPriceWei, 497 | uint _claimPriceAdjustPercent, 498 | uint _curseIncubationDurationSeconds, 499 | uint _commissionPerThousand 500 | ) { 501 | kingdomName = _kingdomName; 502 | world = _world; 503 | topWizard = _topWizard; 504 | subWizard = _subWizard; 505 | rules = ThroneRules( 506 | _startingClaimPriceWei, 507 | _maximumClaimPriceWei, 508 | _claimPriceAdjustPercent, 509 | _curseIncubationDurationSeconds, 510 | _commissionPerThousand 511 | ); 512 | // We number the monarchs starting from 1; it's sometimes useful 513 | // to use zero = invalid, so put in a dummy entry for number 0. 514 | monarchsByNumber.push( 515 | Monarch( 516 | 0, 517 | "", 518 | 0, 519 | 0, 520 | 0 521 | ) 522 | ); 523 | } 524 | 525 | function numberOfMonarchs() constant returns (uint totalCount) { 526 | // zero-th entry is invalid 527 | return monarchsByNumber.length - 1; 528 | } 529 | 530 | // False if either there are no monarchs, or if the latest monarch 531 | // has reigned too long and been struck down by the curse. 532 | function isLivingMonarch() constant returns (bool alive) { 533 | if (numberOfMonarchs() == 0) { 534 | return false; 535 | } 536 | uint reignStartedTimestamp = latestMonarchInternal().coronationTimestamp; 537 | if (now < reignStartedTimestamp) { 538 | // Should not be possible, think miners reject blocks with 539 | // timestamps that go backwards? But some drift possible and 540 | // it needs handling for unsigned overflow audit checks ... 541 | return true; 542 | } 543 | uint elapsedReignDurationSeconds = now - reignStartedTimestamp; 544 | if (elapsedReignDurationSeconds > rules.curseIncubationDurationSeconds) { 545 | return false; 546 | } else { 547 | return true; 548 | } 549 | } 550 | 551 | /// @notice How much you must pay to claim the throne now, in wei. 552 | function currentClaimPriceWei() constant returns (uint priceInWei) { 553 | if (!isLivingMonarch()) { 554 | return rules.startingClaimPriceWei; 555 | } else { 556 | uint lastClaimPriceWei = latestMonarchInternal().claimPriceWei; 557 | // no danger of overflow because claim price never gets that high 558 | uint newClaimPrice = 559 | (lastClaimPriceWei * (100 + rules.claimPriceAdjustPercent)) / 100; 560 | newClaimPrice = roundMoneyDownNicely(newClaimPrice); 561 | if (newClaimPrice < rules.startingClaimPriceWei) { 562 | newClaimPrice = rules.startingClaimPriceWei; 563 | } 564 | if (newClaimPrice > rules.maximumClaimPriceWei) { 565 | newClaimPrice = rules.maximumClaimPriceWei; 566 | } 567 | return newClaimPrice; 568 | } 569 | } 570 | 571 | /// @notice How much you must pay to claim the throne now, in finney. 572 | function currentClaimPriceInFinney() constant 573 | returns (uint priceInFinney) { 574 | uint valueWei = currentClaimPriceWei(); 575 | return roundMoneyUpToWholeFinney(valueWei); 576 | } 577 | 578 | /// @notice Check if a name can be used as a monarch name. 579 | /// @return True if the name satisfies the criteria of: 580 | /// - no fewer than 1 character 581 | /// - no more than 25 characters 582 | /// - no characters other than: 583 | /// - "roman" alphabet letters (A-Z and a-z) 584 | /// - western digits (0-9) 585 | /// - "safe" punctuation: ! ( ) - . _ SPACE 586 | function validateProposedMonarchName(string _monarchName) constant 587 | returns (bool allowed) { 588 | return validateNameInternal(_monarchName); 589 | } 590 | 591 | // Get details of the latest monarch (even if they are dead). 592 | // 593 | // We don't expose externally because returning structs is not well 594 | // supported in the ABI (strange that monarchsByNumber array works 595 | // fine though). Note that the reference returned is writable - it 596 | // can be used to update details of the latest monarch. 597 | // WARN: you should check numberOfMonarchs() > 0 first. 598 | function latestMonarchInternal() constant internal 599 | returns (Monarch storage monarch) { 600 | return monarchsByNumber[monarchsByNumber.length - 1]; 601 | } 602 | 603 | /// @notice Claim throne by sending funds to the contract. 604 | /// Any future compensation earned will be sent to the sender's 605 | /// address (`msg.sender`). 606 | /// Sending from a contract is not recommended unless you know 607 | /// what you're doing (and you've tested it). 608 | /// If no message data is supplied, the throne will be claimed in 609 | /// the name of "Anonymous". To supply a name, send data encoded 610 | /// using web3.fromAscii('NAME:' + 'your_chosen_valid_name'). 611 | /// Sender must include payment equal to currentClaimPriceWei(). 612 | /// Will consume up to ~300,000 gas. 613 | /// Will throw an error if: 614 | /// - name is invalid (see `validateProposedMonarchName(string)`) 615 | /// - payment is too low or too high 616 | /// Produces events: 617 | /// - `ThroneClaimedEvent` 618 | /// - `CompensationSentEvent` / `CompensationFailEvent` 619 | /// - `CommissionEarnedEvent` 620 | function () { 621 | externalEnter(); 622 | fallbackRP(); 623 | externalLeave(); 624 | } 625 | 626 | /// @notice Claim throne in the given `_monarchName`. 627 | /// Any future compensation earned will be sent to the caller's 628 | /// address (`msg.sender`). 629 | /// Caller must include payment equal to currentClaimPriceWei(). 630 | /// Calling from a contract is not recommended unless you know 631 | /// what you're doing (and you've tested it). 632 | /// Will consume up to ~300,000 gas. 633 | /// Will throw an error if: 634 | /// - name is invalid (see `validateProposedMonarchName(string)`) 635 | /// - payment is too low or too high 636 | /// Produces events: 637 | /// - `ThroneClaimedEvent 638 | /// - `CompensationSentEvent` / `CompensationFailEvent` 639 | /// - `CommissionEarnedEvent` 640 | function claimThrone(string _monarchName) { 641 | externalEnter(); 642 | claimThroneRP(_monarchName); 643 | externalLeave(); 644 | } 645 | 646 | /// @notice Used by either the topWizard or subWizard to transfer 647 | /// all rights to future commissions to the `_replacement` wizard. 648 | /// WARN: The original wizard retains ownership of any past 649 | /// commission held for them in the `funds` mapping, which they 650 | /// can still withdraw. 651 | /// Produces event WizardReplacedEvent. 652 | function replaceWizard(address _replacement) { 653 | externalEnter(); 654 | replaceWizardRP(_replacement); 655 | externalLeave(); 656 | } 657 | 658 | function fallbackRP() internal { 659 | if (msg.data.length == 0) { 660 | claimThroneRP("Anonymous"); 661 | } else { 662 | string memory _monarchName = extractNameFromData(msg.data); 663 | claimThroneRP(_monarchName); 664 | } 665 | } 666 | 667 | function claimThroneRP( 668 | string _monarchName 669 | ) internal { 670 | 671 | address _compensationAddress = msg.sender; 672 | 673 | if (!validateNameInternal(_monarchName)) { 674 | throw; 675 | } 676 | 677 | if (_compensationAddress == 0 || 678 | _compensationAddress == address(this)) { 679 | throw; 680 | } 681 | 682 | uint paidWei = msg.value; 683 | uint priceWei = currentClaimPriceWei(); 684 | if (paidWei < priceWei) { 685 | throw; 686 | } 687 | // Make it easy for people to pay using a whole number of finney, 688 | // which could be a teeny bit higher than the raw wei value. 689 | uint excessWei = paidWei - priceWei; 690 | if (excessWei > 1 finney) { 691 | throw; 692 | } 693 | 694 | uint compensationWei; 695 | uint commissionWei; 696 | if (!isLivingMonarch()) { 697 | // dead men get no compensation 698 | commissionWei = paidWei; 699 | compensationWei = 0; 700 | } else { 701 | commissionWei = (paidWei * rules.commissionPerThousand) / 1000; 702 | compensationWei = paidWei - commissionWei; 703 | } 704 | 705 | if (commissionWei != 0) { 706 | recordCommissionEarned(commissionWei); 707 | } 708 | 709 | if (compensationWei != 0) { 710 | compensateLatestMonarch(compensationWei); 711 | } 712 | 713 | // In case of any teeny excess, we use the official price here 714 | // since that should determine the new claim price, not paidWei. 715 | monarchsByNumber.push(Monarch( 716 | _compensationAddress, 717 | _monarchName, 718 | now, 719 | priceWei, 720 | 0 721 | )); 722 | 723 | ThroneClaimedEvent(monarchsByNumber.length - 1); 724 | } 725 | 726 | function replaceWizardRP(address replacement) internal { 727 | if (msg.value != 0) { 728 | throw; 729 | } 730 | bool replacedOk = false; 731 | address oldWizard; 732 | if (msg.sender == topWizard) { 733 | oldWizard = topWizard; 734 | topWizard = replacement; 735 | WizardReplacedEvent(oldWizard, replacement); 736 | replacedOk = true; 737 | } 738 | // Careful - topWizard and subWizard can be the same address, 739 | // in which case we must replace both. 740 | if (msg.sender == subWizard) { 741 | oldWizard = subWizard; 742 | subWizard = replacement; 743 | WizardReplacedEvent(oldWizard, replacement); 744 | replacedOk = true; 745 | } 746 | if (!replacedOk) { 747 | throw; 748 | } 749 | } 750 | 751 | // Allow commission funds to build up in contract for the wizards 752 | // to withdraw (carefully ring-fenced). 753 | function recordCommissionEarned(uint _commissionWei) internal { 754 | // give the subWizard any "odd" single wei 755 | uint topWizardWei = _commissionWei / 2; 756 | uint subWizardWei = _commissionWei - topWizardWei; 757 | funds[topWizard] += topWizardWei; 758 | CommissionEarnedEvent(topWizard, topWizardWei); 759 | funds[subWizard] += subWizardWei; 760 | CommissionEarnedEvent(subWizard, subWizardWei); 761 | } 762 | 763 | // Send compensation to latest monarch (or hold funds for them 764 | // if cannot through no fault of current caller). 765 | function compensateLatestMonarch(uint _compensationWei) internal { 766 | address compensationAddress = 767 | latestMonarchInternal().compensationAddress; 768 | // record that we compensated them 769 | latestMonarchInternal().compensationWei = _compensationWei; 770 | // WARN: if the latest monarch is a contract whose fallback 771 | // function needs more 25300 gas than then they will NOT 772 | // receive compensation automatically. 773 | bool sentOk = carefulSendWithFixedGas( 774 | compensationAddress, 775 | _compensationWei, 776 | suggestedExtraGasToIncludeWithSends 777 | ); 778 | if (sentOk) { 779 | CompensationSentEvent(compensationAddress, _compensationWei); 780 | } else { 781 | // This should only happen if the latest monarch is a contract 782 | // whose fallback-function failed or ran out of gas (despite 783 | // us including a fair amount of gas). 784 | // We do not throw since we do not want the throne to get 785 | // 'stuck' (it's not the new usurpers fault) - instead save 786 | // the funds we could not send so can be claimed later. 787 | // Their monarch contract would need to have been designed 788 | // to call our withdrawFundsAdvanced(..) function mind you. 789 | funds[compensationAddress] += _compensationWei; 790 | CompensationFailEvent(compensationAddress, _compensationWei); 791 | } 792 | } 793 | 794 | } 795 | 796 | 797 | /// @title Used by the World contract to create Kingdom instances. 798 | /// @dev Mostly exists so topWizard can potentially replace this 799 | /// contract to modify the Kingdom contract and/or rule validation 800 | /// logic to be used for *future* Kingdoms created by the World. 801 | /// We do not implement rentry protection because we don't send/call. 802 | /// We do not charge a fee here - but if you bypass the World then 803 | /// you won't be listed on the official World page of course. 804 | contract KingdomFactory { 805 | 806 | function KingdomFactory() { 807 | } 808 | 809 | function () { 810 | // this contract should never have a balance 811 | throw; 812 | } 813 | 814 | // See World.createKingdom(..) for parameter documentation. 815 | function validateProposedThroneRules( 816 | uint _startingClaimPriceWei, 817 | uint _maximumClaimPriceWei, 818 | uint _claimPriceAdjustPercent, 819 | uint _curseIncubationDurationSeconds, 820 | uint _commissionPerThousand 821 | ) constant returns (bool allowed) { 822 | // I suppose there is a danger that massive deflation/inflation could 823 | // change the real-world sanity of these checks, but in that case we 824 | // can deploy a new factory and update the world. 825 | if (_startingClaimPriceWei < 10 finney || 826 | _startingClaimPriceWei > 100 ether) { 827 | return false; 828 | } 829 | if (_maximumClaimPriceWei < 1 ether || 830 | _maximumClaimPriceWei > 100000 ether) { 831 | return false; 832 | } 833 | if (_startingClaimPriceWei * 20 > _maximumClaimPriceWei) { 834 | return false; 835 | } 836 | if (_claimPriceAdjustPercent < 10 || 837 | _claimPriceAdjustPercent > 900) { 838 | return false; 839 | } 840 | if (_curseIncubationDurationSeconds < 2 hours || 841 | _curseIncubationDurationSeconds > 10000 days) { 842 | return false; 843 | } 844 | if (_commissionPerThousand < 10 || 845 | _commissionPerThousand > 100) { 846 | return false; 847 | } 848 | return true; 849 | } 850 | 851 | /// @notice Create a new Kingdom. Normally called by World contract. 852 | /// WARN: Does NOT validate the _kingdomName or _world arguments. 853 | /// Will consume up to 1,800,000 gas (!) 854 | /// Will throw an error if: 855 | /// - rules invalid (see validateProposedThroneRules) 856 | /// - wizard addresses "obviously" wrong 857 | /// - out of gas quite likely (perhaps in future should consider 858 | /// using solidity libraries to reduce Kingdom size?) 859 | // See World.createKingdom(..) for parameter documentation. 860 | function createKingdom( 861 | string _kingdomName, 862 | address _world, 863 | address _topWizard, 864 | address _subWizard, 865 | uint _startingClaimPriceWei, 866 | uint _maximumClaimPriceWei, 867 | uint _claimPriceAdjustPercent, 868 | uint _curseIncubationDurationSeconds, 869 | uint _commissionPerThousand 870 | ) returns (Kingdom newKingdom) { 871 | if (msg.value > 0) { 872 | // this contract should never have a balance 873 | throw; 874 | } 875 | // NB: topWizard and subWizard CAN be the same as each other. 876 | if (_topWizard == 0 || _subWizard == 0) { 877 | throw; 878 | } 879 | if (_topWizard == _world || _subWizard == _world) { 880 | throw; 881 | } 882 | if (!validateProposedThroneRules( 883 | _startingClaimPriceWei, 884 | _maximumClaimPriceWei, 885 | _claimPriceAdjustPercent, 886 | _curseIncubationDurationSeconds, 887 | _commissionPerThousand 888 | )) { 889 | throw; 890 | } 891 | return new Kingdom( 892 | _kingdomName, 893 | _world, 894 | _topWizard, 895 | _subWizard, 896 | _startingClaimPriceWei, 897 | _maximumClaimPriceWei, 898 | _claimPriceAdjustPercent, 899 | _curseIncubationDurationSeconds, 900 | _commissionPerThousand 901 | ); 902 | } 903 | 904 | } 905 | 906 | 907 | /// @title Runs the world, which is a collection of Kingdoms. 908 | contract World is 909 | ReentryProtectorMixin, 910 | NameableMixin, 911 | MoneyRounderMixin, 912 | FundsHolderMixin, 913 | ThroneRulesMixin { 914 | 915 | // The topWizard runs the world. They charge for the creation of 916 | // kingdoms and become the topWizard in each kingdom created. 917 | address public topWizard; 918 | 919 | // How much one must pay to create a new kingdom (in wei). 920 | // Can be changed by the topWizard. 921 | uint public kingdomCreationFeeWei; 922 | 923 | struct KingdomListing { 924 | uint kingdomNumber; 925 | string kingdomName; 926 | address kingdomContract; 927 | address kingdomCreator; 928 | uint creationTimestamp; 929 | address kingdomFactoryUsed; 930 | } 931 | 932 | // The first kingdom is number 1; the zero-th entry is a dummy. 933 | KingdomListing[] public kingdomsByNumber; 934 | 935 | // For safety, we cap just how high the price can get. 936 | // Can be changed by the topWizard, though it will only affect 937 | // kingdoms created after that. 938 | uint public maximumClaimPriceWei; 939 | 940 | // Helper contract for creating Kingdom instances. Can be 941 | // upgraded by the topWizard (won't affect existing ones). 942 | KingdomFactory public kingdomFactory; 943 | 944 | // Avoids duplicate kingdom names and allows searching by name. 945 | mapping (uint => uint) kingdomNumbersByfuzzyHash; 946 | 947 | // NB: we also have a `funds` mapping from FundsHolderMixin, 948 | // and a rentryProtector from ReentryProtectorMixin. 949 | 950 | event KingdomCreatedEvent(uint kingdomNumber); 951 | event CreationFeeChangedEvent(uint newFeeWei); 952 | event FactoryChangedEvent(address newFactory); 953 | event WizardReplacedEvent(address oldWizard, address newWizard); 954 | // NB: we also have a `FundsWithdrawnEvent` from FundsHolderMixin 955 | 956 | // Create the world with no kingdoms yet. 957 | // Costs about 1.9M gas to deploy. 958 | function World( 959 | address _topWizard, 960 | uint _kingdomCreationFeeWei, 961 | KingdomFactory _kingdomFactory, 962 | uint _maximumClaimPriceWei 963 | ) { 964 | if (_topWizard == 0) { 965 | throw; 966 | } 967 | if (_maximumClaimPriceWei < 1 ether) { 968 | throw; 969 | } 970 | topWizard = _topWizard; 971 | kingdomCreationFeeWei = _kingdomCreationFeeWei; 972 | kingdomFactory = _kingdomFactory; 973 | maximumClaimPriceWei = _maximumClaimPriceWei; 974 | // We number the kingdoms starting from 1 since it's sometimes 975 | // useful to use zero = invalid. Create dummy zero-th entry. 976 | kingdomsByNumber.push(KingdomListing(0, "", 0, 0, 0, 0)); 977 | } 978 | 979 | function numberOfKingdoms() constant returns (uint totalCount) { 980 | return kingdomsByNumber.length - 1; 981 | } 982 | 983 | /// @return index into kingdomsByNumber if found, or zero if not. 984 | function findKingdomCalled(string _kingdomName) constant 985 | returns (uint kingdomNumber) { 986 | uint fuzzyHash = computeNameFuzzyHash(_kingdomName); 987 | return kingdomNumbersByfuzzyHash[fuzzyHash]; 988 | } 989 | 990 | /// @notice Check if a name can be used as a kingdom name. 991 | /// @return True if the name satisfies the criteria of: 992 | /// - no fewer than 1 character 993 | /// - no more than 25 characters 994 | /// - no characters other than: 995 | /// - "roman" alphabet letters (A-Z and a-z) 996 | /// - western digits (0-9) 997 | /// - "safe" punctuation: ! ( ) - . _ SPACE 998 | /// 999 | /// WARN: does not check if the name is already in use; 1000 | /// use `findKingdomCalled(string)` for that afterwards. 1001 | function validateProposedKingdomName(string _kingdomName) constant 1002 | returns (bool allowed) { 1003 | return validateNameInternal(_kingdomName); 1004 | } 1005 | 1006 | // Check if rules would be allowed for a new custom Kingdom. 1007 | // Typically used before calling `createKingdom(...)`. 1008 | function validateProposedThroneRules( 1009 | uint _startingClaimPriceWei, 1010 | uint _claimPriceAdjustPercent, 1011 | uint _curseIncubationDurationSeconds, 1012 | uint _commissionPerThousand 1013 | ) constant returns (bool allowed) { 1014 | return kingdomFactory.validateProposedThroneRules( 1015 | _startingClaimPriceWei, 1016 | maximumClaimPriceWei, 1017 | _claimPriceAdjustPercent, 1018 | _curseIncubationDurationSeconds, 1019 | _commissionPerThousand 1020 | ); 1021 | } 1022 | 1023 | // How much one must pay to create a new kingdom (in finney). 1024 | // Can be changed by the topWizard. 1025 | function kingdomCreationFeeInFinney() constant 1026 | returns (uint feeInFinney) { 1027 | return roundMoneyUpToWholeFinney(kingdomCreationFeeWei); 1028 | } 1029 | 1030 | // Reject funds sent to the contract - wizards who cannot interact 1031 | // with it via the API won't be able to withdraw their commission. 1032 | function () { 1033 | throw; 1034 | } 1035 | 1036 | /// @notice Create a new kingdom using custom rules. 1037 | /// @param _kingdomName \ 1038 | /// e.g. "King of the Ether Throne" 1039 | /// @param _startingClaimPriceWei \ 1040 | /// How much it will cost the first monarch to claim the throne 1041 | /// (and also the price after the death of a monarch). 1042 | /// @param _claimPriceAdjustPercent \ 1043 | /// Percentage increase after each claim - e.g. if claim price 1044 | /// was 200 ETH, and `_claimPriceAdjustPercent` is 50, the next 1045 | /// claim price will be 200 ETH + (50% of 200 ETH) => 300 ETH. 1046 | /// @param _curseIncubationDurationSeconds \ 1047 | /// The maximum length of a time a monarch can rule before the 1048 | /// curse strikes and they are removed without compensation. 1049 | /// @param _commissionPerThousand \ 1050 | /// How much of each payment is given to the wizards to share, 1051 | /// expressed in parts per thousand - e.g. 25 means 25/1000, 1052 | /// or 2.5%. 1053 | /// 1054 | /// Caller must include payment equal to kingdomCreationFeeWei. 1055 | /// The caller will become the 'sub-wizard' and will earn half 1056 | /// any commission charged by the Kingdom. Note however they 1057 | /// will need to call withdrawFunds() on the Kingdom contract 1058 | /// to get their commission - it's not send automatically. 1059 | /// 1060 | /// Will consume up to 1,900,000 gas (!) 1061 | /// Will throw an error if: 1062 | /// - name is invalid (see `validateProposedKingdomName(string)`) 1063 | /// - name is already in use (see `findKingdomCalled(string)`) 1064 | /// - rules are invalid (see `validateProposedKingdomRules(...)`) 1065 | /// - payment is too low or too high 1066 | /// - insufficient gas (quite likely!) 1067 | /// Produces event KingdomCreatedEvent. 1068 | function createKingdom( 1069 | string _kingdomName, 1070 | uint _startingClaimPriceWei, 1071 | uint _claimPriceAdjustPercent, 1072 | uint _curseIncubationDurationSeconds, 1073 | uint _commissionPerThousand 1074 | ) { 1075 | externalEnter(); 1076 | createKingdomRP( 1077 | _kingdomName, 1078 | _startingClaimPriceWei, 1079 | _claimPriceAdjustPercent, 1080 | _curseIncubationDurationSeconds, 1081 | _commissionPerThousand 1082 | ); 1083 | externalLeave(); 1084 | } 1085 | 1086 | /// @notice Used by topWizard to transfer all rights to future 1087 | /// fees and future kingdom wizardships to `_replacement` wizard. 1088 | /// WARN: The original wizard retains ownership of any past fees 1089 | /// held for them in the `funds` mapping, which they can still 1090 | /// withdraw. They also remain topWizard in any existing Kingdoms. 1091 | /// Produces event WizardReplacedEvent. 1092 | function replaceWizard(address _replacement) { 1093 | externalEnter(); 1094 | replaceWizardRP(_replacement); 1095 | externalLeave(); 1096 | } 1097 | 1098 | /// @notice Used by topWizard to vary the fee for creating kingdoms. 1099 | function setKingdomCreationFeeWei(uint _kingdomCreationFeeWei) { 1100 | externalEnter(); 1101 | setKingdomCreationFeeWeiRP(_kingdomCreationFeeWei); 1102 | externalLeave(); 1103 | } 1104 | 1105 | /// @notice Used by topWizard to vary the cap on claim price. 1106 | function setMaximumClaimPriceWei(uint _maximumClaimPriceWei) { 1107 | externalEnter(); 1108 | setMaximumClaimPriceWeiRP(_maximumClaimPriceWei); 1109 | externalLeave(); 1110 | } 1111 | 1112 | /// @notice Used by topWizard to vary the factory contract which 1113 | /// will be used to create future Kingdoms. 1114 | function setKingdomFactory(KingdomFactory _kingdomFactory) { 1115 | externalEnter(); 1116 | setKingdomFactoryRP(_kingdomFactory); 1117 | externalLeave(); 1118 | } 1119 | 1120 | function createKingdomRP( 1121 | string _kingdomName, 1122 | uint _startingClaimPriceWei, 1123 | uint _claimPriceAdjustPercent, 1124 | uint _curseIncubationDurationSeconds, 1125 | uint _commissionPerThousand 1126 | ) internal { 1127 | 1128 | address subWizard = msg.sender; 1129 | 1130 | if (!validateNameInternal(_kingdomName)) { 1131 | throw; 1132 | } 1133 | 1134 | uint newKingdomNumber = kingdomsByNumber.length; 1135 | checkUniqueAndRegisterNewKingdomName( 1136 | _kingdomName, 1137 | newKingdomNumber 1138 | ); 1139 | 1140 | uint paidWei = msg.value; 1141 | if (paidWei < kingdomCreationFeeWei) { 1142 | throw; 1143 | } 1144 | // Make it easy for people to pay using a whole number of finney, 1145 | // which could be a teeny bit higher than the raw wei value. 1146 | uint excessWei = paidWei - kingdomCreationFeeWei; 1147 | if (excessWei > 1 finney) { 1148 | throw; 1149 | } 1150 | funds[topWizard] += paidWei; 1151 | 1152 | // This will perform rule validation. 1153 | Kingdom kingdomContract = kingdomFactory.createKingdom( 1154 | _kingdomName, 1155 | address(this), 1156 | topWizard, 1157 | subWizard, 1158 | _startingClaimPriceWei, 1159 | maximumClaimPriceWei, 1160 | _claimPriceAdjustPercent, 1161 | _curseIncubationDurationSeconds, 1162 | _commissionPerThousand 1163 | ); 1164 | 1165 | kingdomsByNumber.push(KingdomListing( 1166 | newKingdomNumber, 1167 | _kingdomName, 1168 | kingdomContract, 1169 | msg.sender, 1170 | now, 1171 | kingdomFactory 1172 | )); 1173 | } 1174 | 1175 | function replaceWizardRP(address replacement) internal { 1176 | if (msg.sender != topWizard) { 1177 | throw; 1178 | } 1179 | if (msg.value != 0) { 1180 | throw; 1181 | } 1182 | address oldWizard = topWizard; 1183 | topWizard = replacement; 1184 | WizardReplacedEvent(oldWizard, replacement); 1185 | } 1186 | 1187 | function setKingdomCreationFeeWeiRP(uint _kingdomCreationFeeWei) internal { 1188 | if (msg.sender != topWizard) { 1189 | throw; 1190 | } 1191 | if (msg.value != 0) { 1192 | throw; 1193 | } 1194 | kingdomCreationFeeWei = _kingdomCreationFeeWei; 1195 | CreationFeeChangedEvent(kingdomCreationFeeWei); 1196 | } 1197 | 1198 | function setMaximumClaimPriceWeiRP(uint _maximumClaimPriceWei) internal { 1199 | if (msg.sender != topWizard) { 1200 | throw; 1201 | } 1202 | if (msg.value != 0) { 1203 | throw; 1204 | } 1205 | if (_maximumClaimPriceWei < 1 ether) { 1206 | throw; 1207 | } 1208 | maximumClaimPriceWei = _maximumClaimPriceWei; 1209 | } 1210 | 1211 | function setKingdomFactoryRP(KingdomFactory _kingdomFactory) internal { 1212 | if (msg.sender != topWizard) { 1213 | throw; 1214 | } 1215 | if (msg.value != 0) { 1216 | throw; 1217 | } 1218 | kingdomFactory = _kingdomFactory; 1219 | FactoryChangedEvent(kingdomFactory); 1220 | } 1221 | 1222 | // If there is no existing kingdom called `_kingdomName`, create 1223 | // a record mapping that name to kingdom no. `_newKingdomNumber`. 1224 | // Throws an error if an existing kingdom with the same (or 1225 | // fuzzily similar - see computeNameFuzzyHash) name exists. 1226 | function checkUniqueAndRegisterNewKingdomName( 1227 | string _kingdomName, 1228 | uint _newKingdomNumber 1229 | ) internal { 1230 | uint fuzzyHash = computeNameFuzzyHash(_kingdomName); 1231 | if (kingdomNumbersByfuzzyHash[fuzzyHash] != 0) { 1232 | throw; 1233 | } 1234 | kingdomNumbersByfuzzyHash[fuzzyHash] = _newKingdomNumber; 1235 | } 1236 | 1237 | } 1238 | 1239 | 1240 | /// @title Used on the testnet to allow automated testing of internals. 1241 | contract ExposedInternalsForTesting is 1242 | MoneyRounderMixin, NameableMixin { 1243 | 1244 | function roundMoneyDownNicelyET(uint _rawValueWei) constant 1245 | returns (uint nicerValueWei) { 1246 | return roundMoneyDownNicely(_rawValueWei); 1247 | } 1248 | 1249 | function roundMoneyUpToWholeFinneyET(uint _valueWei) constant 1250 | returns (uint valueFinney) { 1251 | return roundMoneyUpToWholeFinney(_valueWei); 1252 | } 1253 | 1254 | function validateNameInternalET(string _name) constant 1255 | returns (bool allowed) { 1256 | return validateNameInternal(_name); 1257 | } 1258 | 1259 | function extractNameFromDataET(bytes _data) constant 1260 | returns (string extractedName) { 1261 | return extractNameFromData(_data); 1262 | } 1263 | 1264 | function computeNameFuzzyHashET(string _name) constant 1265 | returns (uint fuzzyHash) { 1266 | return computeNameFuzzyHash(_name); 1267 | } 1268 | 1269 | } 1270 | -------------------------------------------------------------------------------- /PonzICO.sol: -------------------------------------------------------------------------------- 1 | ////////////////////////////// 2 | // see https://etherscan.io/address/0x1ce7986760ade2bf0f322f5ef39ce0de3bd0c82b#code 3 | 4 | pragma solidity ^0.4.0; 5 | 6 | /// @title PonzICO 7 | /// @author acityinohio 8 | contract PonzICO { 9 | address public owner; 10 | uint public total; 11 | mapping (address => uint) public invested; 12 | mapping (address => uint) public balances; 13 | address[] investors; 14 | 15 | //log event of successful investment/withdraw and address 16 | event LogInvestment(address investor, uint amount); 17 | event LogWithdrawal(address investor, uint amount); 18 | 19 | //modifiers for various things 20 | modifier checkZeroBalance() { if (balances[msg.sender] == 0) { throw; } _;} 21 | modifier accreditedInvestor() { if (msg.value < 100 finney) { throw; } _;} 22 | 23 | //constructor for initializing PonzICO. 24 | //the owner is the genius who made this revolutionary smart contract 25 | function PonzICO() { 26 | owner = msg.sender; 27 | } 28 | 29 | //the logic for a small fee for the creator of this contract 30 | //miniscule in the grand scheme of things 31 | function ownerFee(uint amount) private returns (uint fee) { 32 | if (total < 200000 ether) { 33 | fee = amount/2; 34 | balances[owner] += fee; 35 | } 36 | return; 37 | } 38 | 39 | //This is where the magic is withdrawn. 40 | //For users with balances. Can only be used to withdraw full balance. 41 | function withdraw() 42 | checkZeroBalance() 43 | { 44 | uint amount = balances[msg.sender]; 45 | balances[msg.sender] = 0; 46 | if (!msg.sender.send(amount)) { 47 | balances[msg.sender] = amount; 48 | } else { 49 | LogWithdrawal(msg.sender, amount); 50 | } 51 | } 52 | 53 | //What's better than withdrawing? Re-investing profits! 54 | function reinvest() 55 | checkZeroBalance() 56 | { 57 | uint dividend = balances[msg.sender]; 58 | balances[msg.sender] = 0; 59 | uint fee = ownerFee(dividend); 60 | dividend -= fee; 61 | for (uint i = 0; i < investors.length; i++) { 62 | balances[investors[i]] += dividend * invested[investors[i]] / total; 63 | } 64 | invested[msg.sender] += (dividend + fee); 65 | total += (dividend + fee); 66 | LogInvestment(msg.sender, dividend+fee); 67 | } 68 | 69 | //This is the where the magic is invested. 70 | //Note the accreditedInvestor() modifier, to ensure only sophisticated 71 | //investors with 0.1 ETH or more can invest. #SelfRegulation 72 | function invest() payable 73 | accreditedInvestor() 74 | { 75 | //first send the owner's modest 50% fee but only if the total invested is less than 200000 ETH 76 | uint dividend = msg.value; 77 | uint fee = ownerFee(dividend); 78 | dividend -= fee; 79 | //then accrue balances from the generous remainder to everyone else previously invested 80 | for (uint i = 0; i < investors.length; i++) { 81 | balances[investors[i]] += dividend * invested[investors[i]] / total; 82 | } 83 | 84 | //finally, add this enterprising new investor to the public balances 85 | if (invested[msg.sender] == 0) { 86 | investors.push(msg.sender); 87 | invested[msg.sender] = msg.value; 88 | } else { 89 | invested[msg.sender] += msg.value; 90 | } 91 | total += msg.value; 92 | LogInvestment(msg.sender, msg.value); 93 | } 94 | 95 | //finally, fallback function. no one should send money to this contract 96 | //without first being added as an investment. 97 | function () { throw; } 98 | } 99 | -------------------------------------------------------------------------------- /PonziGovernmental.sol: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////// 2 | // see https://etherscan.io/address/0xF45717552f12Ef7cb65e95476F217Ea008167Ae3#code 3 | 4 | contract Government { 5 | 6 | // Global Variables 7 | uint32 public lastCreditorPayedOut; 8 | uint public lastTimeOfNewCredit; 9 | uint public profitFromCrash; 10 | address[] public creditorAddresses; 11 | uint[] public creditorAmounts; 12 | address public corruptElite; 13 | mapping (address => uint) buddies; 14 | uint constant TWELVE_HOURS = 43200; 15 | uint8 public round; 16 | 17 | function Government() { 18 | // The corrupt elite establishes a new government 19 | // this is the commitment of the corrupt Elite - everything that can not be saved from a crash 20 | profitFromCrash = msg.value; 21 | corruptElite = msg.sender; 22 | lastTimeOfNewCredit = block.timestamp; 23 | } 24 | 25 | function lendGovernmentMoney(address buddy) returns (bool) { 26 | uint amount = msg.value; 27 | // check if the system already broke down. If for 12h no new creditor gives new credit to the system it will brake down. 28 | // 12h are on average = 60*60*12/12.5 = 3456 29 | if (lastTimeOfNewCredit + TWELVE_HOURS < block.timestamp) { 30 | // Return money to sender 31 | msg.sender.send(amount); 32 | // Sends all contract money to the last creditor 33 | creditorAddresses[creditorAddresses.length - 1].send(profitFromCrash); 34 | corruptElite.send(this.balance); 35 | // Reset contract state 36 | lastCreditorPayedOut = 0; 37 | lastTimeOfNewCredit = block.timestamp; 38 | profitFromCrash = 0; 39 | creditorAddresses = new address[](0); 40 | creditorAmounts = new uint[](0); 41 | round += 1; 42 | return false; 43 | } 44 | else { 45 | // the system needs to collect at least 1% of the profit from a crash to stay alive 46 | if (amount >= 10 ** 18) { 47 | // the System has received fresh money, it will survive at leat 12h more 48 | lastTimeOfNewCredit = block.timestamp; 49 | // register the new creditor and his amount with 10% interest rate 50 | creditorAddresses.push(msg.sender); 51 | creditorAmounts.push(amount * 110 / 100); 52 | // now the money is distributed 53 | // first the corrupt elite grabs 5% - thieves! 54 | corruptElite.send(amount * 5/100); 55 | // 5% are going into the economy (they will increase the value for the person seeing the crash comming) 56 | if (profitFromCrash < 10000 * 10**18) { 57 | profitFromCrash += amount * 5/100; 58 | } 59 | // if you have a buddy in the government (and he is in the creditor list) he can get 5% of your credits. 60 | // Make a deal with him. 61 | if(buddies[buddy] >= amount) { 62 | buddy.send(amount * 5/100); 63 | } 64 | buddies[msg.sender] += amount * 110 / 100; 65 | // 90% of the money will be used to pay out old creditors 66 | if (creditorAmounts[lastCreditorPayedOut] <= address(this).balance - profitFromCrash) { 67 | creditorAddresses[lastCreditorPayedOut].send(creditorAmounts[lastCreditorPayedOut]); 68 | buddies[creditorAddresses[lastCreditorPayedOut]] -= creditorAmounts[lastCreditorPayedOut]; 69 | lastCreditorPayedOut += 1; 70 | } 71 | return true; 72 | } 73 | else { 74 | msg.sender.send(amount); 75 | return false; 76 | } 77 | } 78 | } 79 | 80 | // fallback function 81 | function() { 82 | lendGovernmentMoney(0); 83 | } 84 | 85 | function totalDebt() returns (uint debt) { 86 | for(uint i=lastCreditorPayedOut; i> 16 25 | // y = coordinates & 0xFFFF 26 | // coordinates = (x << 16) | y 27 | // x is a 16-bit unsigned integer 28 | // y is a 16-bit unsigned integer 29 | mapping(uint32 => address) public coordinatesToAddresses; 30 | uint32[] public allBlockCoordinates; 31 | 32 | // In the user interface, the rows of blocks will be 33 | // progressively shifted more to the right, as y increases 34 | // 35 | // For example, these blocks in the contract's coordinate system: 36 | // ______ 37 | // 2 |__A__|______ 38 | // /|\ 1 |__B__|__D__|______ 39 | // | 0 |__C__|__E__|__F__| 40 | // y 0 1 2 41 | // 42 | // x --> 43 | // 44 | // 45 | // Become these blocks in the user interface: 46 | // __ ______ 47 | // /| __|__A__|___ 48 | // / __|__B__|__D__|___ 49 | // y |__C__|__E__|__F__| 50 | // 51 | // x --> 52 | // 53 | // 54 | 55 | ///////////////////////////////////////////// 56 | // Address properties 57 | mapping(address => uint256) public addressesToTotalWeiPlaced; 58 | mapping(address => uint256) public addressBalances; 59 | 60 | //////////////////////////////////////////// 61 | // Game Constructor 62 | function PyramidGame() public 63 | { 64 | administrator = msg.sender; 65 | adminFeeDivisor = 200; // Default fee is 0.5% 66 | 67 | // The administrator gets a few free chat messages :-) 68 | addressesToChatMessagesLeft[administrator] += 5; 69 | 70 | // Set the first block in the middle of the bottom row 71 | coordinatesToAddresses[uint32(1 << 15) << 16] = msg.sender; 72 | allBlockCoordinates.push(uint32(1 << 15) << 16); 73 | } 74 | 75 | //////////////////////////////////////////// 76 | // Pyramid grid reading functions 77 | function getBetAmountAtLayer(uint16 y) public pure returns (uint256) 78 | { 79 | // The minimum bet doubles every time you go up 1 layer 80 | return BOTTOM_LAYER_BET_AMOUNT * (uint256(1) << y); 81 | } 82 | 83 | function isThereABlockAtCoordinates(uint16 x, uint16 y) public view returns (bool) 84 | { 85 | return coordinatesToAddresses[(uint32(x) << 16) | uint16(y)] != 0; 86 | } 87 | 88 | function getTotalAmountOfBlocks() public view returns (uint256) 89 | { 90 | return allBlockCoordinates.length; 91 | } 92 | 93 | //////////////////////////////////////////// 94 | // Pyramid grid writing functions 95 | function placeBlock(uint16 x, uint16 y) external payable 96 | { 97 | // You may only place a block on an empty spot 98 | require(!isThereABlockAtCoordinates(x, y)); 99 | 100 | // Add the transaction amount to the person's balance 101 | addressBalances[msg.sender] += msg.value; 102 | 103 | // Calculate the required bet amount at the specified layer 104 | uint256 betAmount = getBetAmountAtLayer(y); 105 | 106 | // If the block is at the lowest layer... 107 | if (y == 0) 108 | { 109 | // There must be a block to the left or to the right of it 110 | require(isThereABlockAtCoordinates(x-1, y) || 111 | isThereABlockAtCoordinates(x+1, y)); 112 | } 113 | 114 | // If the block is NOT at the lowest layer... 115 | else 116 | { 117 | // There must be two existing blocks below it: 118 | require(isThereABlockAtCoordinates(x , y-1) && 119 | isThereABlockAtCoordinates(x+1, y-1)); 120 | } 121 | 122 | // Subtract the bet amount from the person's balance 123 | addressBalances[msg.sender] -= betAmount; 124 | 125 | // Place the block 126 | coordinatesToAddresses[(uint32(x) << 16) | y] = msg.sender; 127 | allBlockCoordinates.push((uint32(x) << 16) | y); 128 | 129 | // If the block is at the lowest layer... 130 | if (y == 0) 131 | { 132 | // The bet goes to the administrator 133 | addressBalances[administrator] += betAmount; 134 | } 135 | 136 | // If the block is NOT at the lowest layer... 137 | else 138 | { 139 | // Calculate the administrator fee 140 | uint256 adminFee = betAmount / adminFeeDivisor; 141 | 142 | // Calculate the bet amount minus the admin fee 143 | uint256 betAmountMinusAdminFee = betAmount - adminFee; 144 | 145 | // Add the money to the balances of the people below 146 | addressBalances[coordinatesToAddresses[(uint32(x ) << 16) | (y-1)]] += betAmountMinusAdminFee / 2; 147 | addressBalances[coordinatesToAddresses[(uint32(x+1) << 16) | (y-1)]] += betAmountMinusAdminFee / 2; 148 | 149 | // Give the admin fee to the admin 150 | addressBalances[administrator] += adminFee; 151 | } 152 | 153 | // The new sender's balance must not have underflowed 154 | // (this verifies that the sender has enough balance to place the block) 155 | require(addressBalances[msg.sender] < (1 << 255)); 156 | 157 | // Give the sender their chat message rights 158 | addressesToChatMessagesLeft[msg.sender] += uint32(1) << y; 159 | 160 | // Register the sender's total bets placed 161 | addressesToTotalWeiPlaced[msg.sender] += betAmount; 162 | } 163 | 164 | //////////////////////////////////////////// 165 | // Withdrawing balance 166 | function withdrawBalance(uint256 amountToWithdraw) external 167 | { 168 | require(amountToWithdraw != 0); 169 | 170 | // The user must have enough balance to withdraw 171 | require(addressBalances[msg.sender] >= amountToWithdraw); 172 | 173 | // Subtract the withdrawn amount from the user's balance 174 | addressBalances[msg.sender] -= amountToWithdraw; 175 | 176 | // Transfer the amount to the user's address 177 | // If the transfer() call fails an exception will be thrown, 178 | // and therefore the user's balance will be automatically restored 179 | msg.sender.transfer(amountToWithdraw); 180 | } 181 | 182 | ///////////////////////////////////////////// 183 | // Chatbox data 184 | struct ChatMessage 185 | { 186 | address person; 187 | string message; 188 | } 189 | mapping(bytes32 => address) public usernamesToAddresses; 190 | mapping(address => bytes32) public addressesToUsernames; 191 | mapping(address => uint32) public addressesToChatMessagesLeft; 192 | ChatMessage[] public chatMessages; 193 | mapping(uint256 => bool) public censoredChatMessages; 194 | 195 | ///////////////////////////////////////////// 196 | // Chatbox functions 197 | function registerUsername(bytes32 username) external 198 | { 199 | // The username must not already be token 200 | require(usernamesToAddresses[username] == 0); 201 | 202 | // The address must not already have a username 203 | require(addressesToUsernames[msg.sender] == 0); 204 | 205 | // Register the new username & address combination 206 | usernamesToAddresses[username] = msg.sender; 207 | addressesToUsernames[msg.sender] = username; 208 | } 209 | 210 | function sendChatMessage(string message) external 211 | { 212 | // The sender must have at least 1 chat message allowance 213 | require(addressesToChatMessagesLeft[msg.sender] >= 1); 214 | 215 | // Deduct 1 chat message allowence from the sender 216 | addressesToChatMessagesLeft[msg.sender]--; 217 | 218 | // Add the chat message 219 | chatMessages.push(ChatMessage(msg.sender, message)); 220 | } 221 | 222 | function getTotalAmountOfChatMessages() public view returns (uint256) 223 | { 224 | return chatMessages.length; 225 | } 226 | 227 | function getChatMessageAtIndex(uint256 index) public view returns (address, bytes32, string) 228 | { 229 | address person = chatMessages[index].person; 230 | bytes32 username = addressesToUsernames[person]; 231 | return (person, username, chatMessages[index].message); 232 | } 233 | 234 | // In case of chat messages with extremely rude or inappropriate 235 | // content, the administrator can censor a chat message. 236 | function censorChatMessage(uint256 chatMessageIndex) public 237 | { 238 | require(msg.sender == administrator); 239 | censoredChatMessages[chatMessageIndex] = true; 240 | } 241 | 242 | ///////////////////////////////////////////// 243 | // Game ownership functions 244 | function transferOwnership(address newAdministrator) external 245 | { 246 | require(msg.sender == administrator); 247 | administrator = newAdministrator; 248 | } 249 | 250 | function setFeeDivisor(uint256 newFeeDivisor) external 251 | { 252 | require(msg.sender == administrator); 253 | require(newFeeDivisor >= 20); // The fee may never exceed 5% 254 | adminFeeDivisor = newFeeDivisor; 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ethereum (Crypto Blockchain) Contract / Transaction Scripts 2 | 3 | _Ponzi & pyramid schemes, lotteries, gambling casinos and more_ 4 | 5 | 6 | **BEWARE: Gambling is fun and addictive. Winning and losing. Up and down. 7 | Treat crypto "games" as entertainment like casino gambling, sports betting or poker cards playing. 8 | Do NOT "invest" trying to get-rich-quick 9 | or raise the stakes trying to win back what you have lost, and so on.** 10 | 11 | 12 | ## Ponzi & Pyramid Schemes 13 | 14 | - [**GradualPonzi.sol**](GradualPonzi.sol) - [(Live)](https://etherscan.io/address/0xf89e29fd10716757d1d3d2997975c639c8750e92#code) 15 | - [**KingOfTheEtherThrone.sol**](KingOfTheEtherThrone.sol) 16 | - [**PonzICO.sol**](PonzICO.sol) 17 | - [**PonziGovernmental.sol**](PonziGovernmental.sol) 18 | - [**SimplePonzi.sol**](SimplePonzi.sol) 19 | - [**SimplePyramid.sol**](SimplePyramid.sol) 20 | 21 | ## Lotteries 22 | 23 | 24 | ## Gambling Casinos 25 | 26 | _Satoshi (Roll) Dice, Roulette, and more_ 27 | 28 | - [**Dice2Win.sol**](Dice2Win.sol) - [(Source)](https://github.com/dice2-win/contracts), [(Live)](https://etherscan.io/address/0xD1CEeeeee83F8bCF3BEDad437202b6154E9F5405#code) 29 | - [**FckDice.sol**](FckDice.sol) - [(Source)](https://github.com/FCKOfficial/FCK-contracts) 30 | 31 | 32 | ## Collectibles 33 | 34 | - [**GodsUnchained.sol**](GodsUnchained.sol) - [(Live)](https://etherscan.io/address/0x6EbeAf8e8E946F0716E6533A6f2cefc83f60e8Ab#code) 35 | 36 | -------------------------------------------------------------------------------- /SimplePonzi.sol: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////// 2 | // see https://etherscan.io/address/0xd09180f956c97a165c23c7f932908600c2e3e0fb#code 3 | 4 | contract SimplePonzi { 5 | address public currentInvestor; 6 | uint public currentInvestment = 0; 7 | 8 | function () payable public { 9 | // new investments must be 10% greater than current 10 | uint minimumInvestment = currentInvestment * 11 / 10; 11 | require(msg.value > minimumInvestment); 12 | 13 | // document new investor 14 | address previousInvestor = currentInvestor; 15 | currentInvestor = msg.sender; 16 | currentInvestment = msg.value; 17 | 18 | 19 | // payout previous investor 20 | previousInvestor.send(msg.value); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SimplePyramid.sol: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////// 2 | // see https://etherscan.io/address/0x9b0033bccf2d913dd17c08a5844c9dd31dd34833#code 3 | 4 | contract SimplePyramid { 5 | uint public constant MINIMUM_INVESTMENT = 1e15; // 0.001 ether 6 | uint public numInvestors = 0; 7 | uint public depth = 0; 8 | address[] public investors; 9 | mapping(address => uint) public balances; 10 | 11 | function SimplePyramid () public payable { 12 | require(msg.value >= MINIMUM_INVESTMENT); 13 | investors.length = 3; 14 | investors[0] = msg.sender; 15 | numInvestors = 1; 16 | depth = 1; 17 | balances[address(this)] = msg.value; 18 | } 19 | 20 | function () payable public { 21 | require(msg.value >= MINIMUM_INVESTMENT); 22 | balances[address(this)] += msg.value; 23 | 24 | numInvestors += 1; 25 | investors[numInvestors - 1] = msg.sender; 26 | 27 | if (numInvestors == investors.length) { 28 | // pay out previous layer 29 | uint endIndex = numInvestors - 2**depth; 30 | uint startIndex = endIndex - 2**(depth-1); 31 | for (uint i = startIndex; i < endIndex; i++) 32 | balances[investors[i]] += MINIMUM_INVESTMENT; 33 | 34 | // spread remaining ether among all participants 35 | uint paid = MINIMUM_INVESTMENT * 2**(depth-1); 36 | uint eachInvestorGets = (balances[address(this)] - paid) / numInvestors; 37 | for(i = 0; i < numInvestors; i++) 38 | balances[investors[i]] += eachInvestorGets; 39 | 40 | // update state variables 41 | balances[address(this)] = 0; 42 | depth += 1; 43 | investors.length += 2**depth; 44 | } 45 | } 46 | 47 | function withdraw () public { 48 | uint payout = balances[msg.sender]; 49 | balances[msg.sender] = 0; 50 | msg.sender.transfer(payout); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /utils/Addresses.sol: -------------------------------------------------------------------------------- 1 | /////////////////////////////////// 2 | // see https://github.com/willitscale/solidity-util 3 | 4 | pragma solidity ^0.4.0; 5 | 6 | /** 7 | * Addresses Library 8 | * 9 | * In summary this is a simple library of address functions which extends the 10 | * pre-existing functionality 11 | * 12 | * @author James Lockhart 13 | */ 14 | library Addresses { 15 | /** 16 | * Is Contract 17 | * 18 | * Check to see if the subject address is a contract on the Ethereum network 19 | * 20 | * @param _base The address on the network to check if it is a contract 21 | * @return bool Returns true if it is a valid contract 22 | */ 23 | function isContract(address _base) returns (bool _r) { 24 | assembly { 25 | _r := gt(extcodesize(_base), 0) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /utils/Integers.sol: -------------------------------------------------------------------------------- 1 | /////////////////////////////////// 2 | // see https://github.com/willitscale/solidity-util 3 | 4 | pragma solidity ^0.4.0; 5 | 6 | /** 7 | * Integers Library 8 | * 9 | * In summary this is a simple library of integer functions which allow a simple 10 | * conversion to and from strings 11 | * 12 | * @author James Lockhart 13 | */ 14 | library Integers { 15 | /** 16 | * Parse Int 17 | * 18 | * Converts an ASCII string value into an uint as long as the string 19 | * its self is a valid unsigned integer 20 | * 21 | * @param _value The ASCII string to be converted to an unsigned integer 22 | * @return uint The unsigned value of the ASCII string 23 | */ 24 | function parseInt(string _value) 25 | public 26 | returns (uint _ret) { 27 | bytes memory _bytesValue = bytes(_value); 28 | uint j = 1; 29 | for(uint i = _bytesValue.length-1; i >= 0 && i < _bytesValue.length; i--) { 30 | assert(_bytesValue[i] >= 48 && _bytesValue[i] <= 57); 31 | _ret += (uint(_bytesValue[i]) - 48)*j; 32 | j*=10; 33 | } 34 | } 35 | 36 | /** 37 | * To String 38 | * 39 | * Converts an unsigned integer to the ASCII string equivalent value 40 | * 41 | * @param _base The unsigned integer to be converted to a string 42 | * @return string The resulting ASCII string value 43 | */ 44 | function toString(uint _base) 45 | internal 46 | returns (string) { 47 | bytes memory _tmp = new bytes(32); 48 | uint i; 49 | for(i = 0;_base > 0;i++) { 50 | _tmp[i] = byte((_base % 10) + 48); 51 | _base /= 10; 52 | } 53 | bytes memory _real = new bytes(i--); 54 | for(uint j = 0; j < _real.length; j++) { 55 | _real[j] = _tmp[i--]; 56 | } 57 | return string(_real); 58 | } 59 | 60 | /** 61 | * To Byte 62 | * 63 | * Convert an 8 bit unsigned integer to a byte 64 | * 65 | * @param _base The 8 bit unsigned integer 66 | * @return byte The byte equivalent 67 | */ 68 | function toByte(uint8 _base) 69 | public 70 | returns (byte _ret) { 71 | assembly { 72 | let m_alloc := add(msize(),0x1) 73 | mstore8(m_alloc, _base) 74 | _ret := mload(m_alloc) 75 | } 76 | } 77 | 78 | /** 79 | * To Bytes 80 | * 81 | * Converts an unsigned integer to bytes 82 | * 83 | * @param _base The integer to be converted to bytes 84 | * @return bytes The bytes equivalent 85 | */ 86 | function toBytes(uint _base) 87 | internal 88 | returns (bytes _ret) { 89 | assembly { 90 | let m_alloc := add(msize(),0x1) 91 | _ret := mload(m_alloc) 92 | mstore(_ret, 0x20) 93 | mstore(add(_ret, 0x20), _base) 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /utils/Strings.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.0; 2 | 3 | /** 4 | * Strings Library 5 | * 6 | * In summary this is a simple library of string functions which make simple 7 | * string operations less tedious in solidity. 8 | * 9 | * Please be aware these functions can be quite gas heavy so use them only when 10 | * necessary not to clog the blockchain with expensive transactions. 11 | * 12 | * @author James Lockhart 13 | */ 14 | library Strings { 15 | 16 | /** 17 | * Concat (High gas cost) 18 | * 19 | * Appends two strings together and returns a new value 20 | * 21 | * @param _base When being used for a data type this is the extended object 22 | * otherwise this is the string which will be the concatenated 23 | * prefix 24 | * @param _value The value to be the concatenated suffix 25 | * @return string The resulting string from combinging the base and value 26 | */ 27 | function concat(string _base, string _value) 28 | internal 29 | pure 30 | returns (string) { 31 | bytes memory _baseBytes = bytes(_base); 32 | bytes memory _valueBytes = bytes(_value); 33 | 34 | assert(_valueBytes.length > 0); 35 | 36 | string memory _tmpValue = new string(_baseBytes.length + 37 | _valueBytes.length); 38 | bytes memory _newValue = bytes(_tmpValue); 39 | 40 | uint i; 41 | uint j; 42 | 43 | for(i = 0; i < _baseBytes.length; i++) { 44 | _newValue[j++] = _baseBytes[i]; 45 | } 46 | 47 | for(i = 0; i<_valueBytes.length; i++) { 48 | _newValue[j++] = _valueBytes[i]; 49 | } 50 | 51 | return string(_newValue); 52 | } 53 | 54 | /** 55 | * Index Of 56 | * 57 | * Locates and returns the position of a character within a string 58 | * 59 | * @param _base When being used for a data type this is the extended object 60 | * otherwise this is the string acting as the haystack to be 61 | * searched 62 | * @param _value The needle to search for, at present this is currently 63 | * limited to one character 64 | * @return int The position of the needle starting from 0 and returning -1 65 | * in the case of no matches found 66 | */ 67 | function indexOf(string _base, string _value) 68 | internal 69 | pure 70 | returns (int) { 71 | return _indexOf(_base, _value, 0); 72 | } 73 | 74 | /** 75 | * Index Of 76 | * 77 | * Locates and returns the position of a character within a string starting 78 | * from a defined offset 79 | * 80 | * @param _base When being used for a data type this is the extended object 81 | * otherwise this is the string acting as the haystack to be 82 | * searched 83 | * @param _value The needle to search for, at present this is currently 84 | * limited to one character 85 | * @param _offset The starting point to start searching from which can start 86 | * from 0, but must not exceed the length of the string 87 | * @return int The position of the needle starting from 0 and returning -1 88 | * in the case of no matches found 89 | */ 90 | function _indexOf(string _base, string _value, uint _offset) 91 | internal 92 | pure 93 | returns (int) { 94 | bytes memory _baseBytes = bytes(_base); 95 | bytes memory _valueBytes = bytes(_value); 96 | 97 | assert(_valueBytes.length == 1); 98 | 99 | for(uint i = _offset; i < _baseBytes.length; i++) { 100 | if (_baseBytes[i] == _valueBytes[0]) { 101 | return int(i); 102 | } 103 | } 104 | 105 | return -1; 106 | } 107 | 108 | /** 109 | * Length 110 | * 111 | * Returns the length of the specified string 112 | * 113 | * @param _base When being used for a data type this is the extended object 114 | * otherwise this is the string to be measured 115 | * @return uint The length of the passed string 116 | */ 117 | function length(string _base) 118 | internal 119 | pure 120 | returns (uint) { 121 | bytes memory _baseBytes = bytes(_base); 122 | return _baseBytes.length; 123 | } 124 | 125 | /** 126 | * Sub String 127 | * 128 | * Extracts the beginning part of a string based on the desired length 129 | * 130 | * @param _base When being used for a data type this is the extended object 131 | * otherwise this is the string that will be used for 132 | * extracting the sub string from 133 | * @param _length The length of the sub string to be extracted from the base 134 | * @return string The extracted sub string 135 | */ 136 | function substring(string _base, int _length) 137 | internal 138 | pure 139 | returns (string) { 140 | return _substring(_base, _length, 0); 141 | } 142 | 143 | /** 144 | * Sub String 145 | * 146 | * Extracts the part of a string based on the desired length and offset. The 147 | * offset and length must not exceed the lenth of the base string. 148 | * 149 | * @param _base When being used for a data type this is the extended object 150 | * otherwise this is the string that will be used for 151 | * extracting the sub string from 152 | * @param _length The length of the sub string to be extracted from the base 153 | * @param _offset The starting point to extract the sub string from 154 | * @return string The extracted sub string 155 | */ 156 | function _substring(string _base, int _length, int _offset) 157 | internal 158 | pure 159 | returns (string) { 160 | bytes memory _baseBytes = bytes(_base); 161 | 162 | assert(uint(_offset+_length) <= _baseBytes.length); 163 | 164 | string memory _tmp = new string(uint(_length)); 165 | bytes memory _tmpBytes = bytes(_tmp); 166 | 167 | uint j = 0; 168 | for(uint i = uint(_offset); i < uint(_offset+_length); i++) { 169 | _tmpBytes[j++] = _baseBytes[i]; 170 | } 171 | 172 | return string(_tmpBytes); 173 | } 174 | 175 | /** 176 | * String Split (Very high gas cost) 177 | * 178 | * Splits a string into an array of strings based off the delimiter value. 179 | * Please note this can be quite a gas expensive function due to the use of 180 | * storage so only use if really required. 181 | * 182 | * @param _base When being used for a data type this is the extended object 183 | * otherwise this is the string value to be split. 184 | * @param _value The delimiter to split the string on which must be a single 185 | * character 186 | * @return string[] An array of values split based off the delimiter, but 187 | * do not container the delimiter. 188 | */ 189 | function split(string _base, string _value) 190 | internal 191 | returns (string[] storage splitArr) { 192 | bytes memory _baseBytes = bytes(_base); 193 | uint _offset = 0; 194 | 195 | while(_offset < _baseBytes.length-1) { 196 | 197 | int _limit = _indexOf(_base, _value, _offset); 198 | if (_limit == -1) { 199 | _limit = int(_baseBytes.length); 200 | } 201 | 202 | string memory _tmp = new string(uint(_limit)-_offset); 203 | bytes memory _tmpBytes = bytes(_tmp); 204 | 205 | uint j = 0; 206 | for(uint i = _offset; i < uint(_limit); i++) { 207 | _tmpBytes[j++] = _baseBytes[i]; 208 | } 209 | _offset = uint(_limit) + 1; 210 | splitArr.push(string(_tmpBytes)); 211 | } 212 | return splitArr; 213 | } 214 | 215 | /** 216 | * Compare To 217 | * 218 | * Compares the characters of two strings, to ensure that they have an 219 | * identical footprint 220 | * 221 | * @param _base When being used for a data type this is the extended object 222 | * otherwise this is the string base to compare against 223 | * @param _value The string the base is being compared to 224 | * @return bool Simply notates if the two string have an equivalent 225 | */ 226 | function compareTo(string _base, string _value) 227 | internal 228 | pure 229 | returns (bool) { 230 | bytes memory _baseBytes = bytes(_base); 231 | bytes memory _valueBytes = bytes(_value); 232 | 233 | if (_baseBytes.length != _valueBytes.length) { 234 | return false; 235 | } 236 | 237 | for(uint i = 0; i < _baseBytes.length; i++) { 238 | if (_baseBytes[i] != _valueBytes[i]) { 239 | return false; 240 | } 241 | } 242 | 243 | return true; 244 | } 245 | 246 | /** 247 | * Compare To Ignore Case (High gas cost) 248 | * 249 | * Compares the characters of two strings, converting them to the same case 250 | * where applicable to alphabetic characters to distinguish if the values 251 | * match. 252 | * 253 | * @param _base When being used for a data type this is the extended object 254 | * otherwise this is the string base to compare against 255 | * @param _value The string the base is being compared to 256 | * @return bool Simply notates if the two string have an equivalent value 257 | * discarding case 258 | */ 259 | function compareToIgnoreCase(string _base, string _value) 260 | internal 261 | pure 262 | returns (bool) { 263 | bytes memory _baseBytes = bytes(_base); 264 | bytes memory _valueBytes = bytes(_value); 265 | 266 | if (_baseBytes.length != _valueBytes.length) { 267 | return false; 268 | } 269 | 270 | for(uint i = 0; i < _baseBytes.length; i++) { 271 | if (_baseBytes[i] != _valueBytes[i] && 272 | _upper(_baseBytes[i]) != _upper(_valueBytes[i])) { 273 | return false; 274 | } 275 | } 276 | 277 | return true; 278 | } 279 | 280 | /** 281 | * Upper 282 | * 283 | * Converts all the values of a string to their corresponding upper case 284 | * value. 285 | * 286 | * @param _base When being used for a data type this is the extended object 287 | * otherwise this is the string base to convert to upper case 288 | * @return string 289 | */ 290 | function upper(string _base) 291 | internal 292 | pure 293 | returns (string) { 294 | bytes memory _baseBytes = bytes(_base); 295 | for (uint i = 0; i < _baseBytes.length; i++) { 296 | _baseBytes[i] = _upper(_baseBytes[i]); 297 | } 298 | return string(_baseBytes); 299 | } 300 | 301 | /** 302 | * Lower 303 | * 304 | * Converts all the values of a string to their corresponding lower case 305 | * value. 306 | * 307 | * @param _base When being used for a data type this is the extended object 308 | * otherwise this is the string base to convert to lower case 309 | * @return string 310 | */ 311 | function lower(string _base) 312 | internal 313 | pure 314 | returns (string) { 315 | bytes memory _baseBytes = bytes(_base); 316 | for (uint i = 0; i < _baseBytes.length; i++) { 317 | _baseBytes[i] = _lower(_baseBytes[i]); 318 | } 319 | return string(_baseBytes); 320 | } 321 | 322 | /** 323 | * Upper 324 | * 325 | * Convert an alphabetic character to upper case and return the original 326 | * value when not alphabetic 327 | * 328 | * @param _b1 The byte to be converted to upper case 329 | * @return bytes1 The converted value if the passed value was alphabetic 330 | * and in a lower case otherwise returns the original value 331 | */ 332 | function _upper(bytes1 _b1) 333 | private 334 | pure 335 | returns (bytes1) { 336 | 337 | if (_b1 >= 0x61 && _b1 <= 0x7A) { 338 | return bytes1(uint8(_b1)-32); 339 | } 340 | 341 | return _b1; 342 | } 343 | 344 | /** 345 | * Lower 346 | * 347 | * Convert an alphabetic character to lower case and return the original 348 | * value when not alphabetic 349 | * 350 | * @param _b1 The byte to be converted to lower case 351 | * @return bytes1 The converted value if the passed value was alphabetic 352 | * and in a upper case otherwise returns the original value 353 | */ 354 | function _lower(bytes1 _b1) 355 | private 356 | pure 357 | returns (bytes1) { 358 | 359 | if (_b1 >= 0x41 && _b1 <= 0x5A) { 360 | return bytes1(uint8(_b1)+32); 361 | } 362 | 363 | return _b1; 364 | } 365 | } 366 | --------------------------------------------------------------------------------