Skip to content

Instantly share code, notes, and snippets.

@vincentchu
Created March 15, 2018 16:52
Show Gist options
  • Save vincentchu/a4429de38ae15419f3b08c86c2bffd84 to your computer and use it in GitHub Desktop.
Save vincentchu/a4429de38ae15419f3b08c86c2bffd84 to your computer and use it in GitHub Desktop.
pragma solidity ^0.4.19;
import './ERC721.sol';
contract CryptoMarchMadness is ERC721, ERC721Metadata, ERC721Enumerable {
uint256 private constant MASK = 0x3f;
uint256 public basePoolFeeInWei; // Fee required to purchase a bracket
uint256 public collectorFeeInWei; // Flat fee reserved for the pool operator
uint256 public poolSizeInWei; // Funds reserved for the bracket pool
uint256 public collectorPoolSizeInWei; // Funds reserved for the pool operator
uint8 public currentRound; // Round 1-5 (1=Sweet 16, 5=Finals).
// Rounds 6 & 7 are special internal flags that
// indicate when people can buy brackets
// (6=half price, 7=full price)
uint256 public currentState; // Current bracket results
uint256 public totalPoints; // Total number of points (set by the pool owner)
address private _collector;
address private _delegateOwner;
uint256 public totalCount; // Total number of brackets (deeds) purchased
uint256[] public deeds; // Flat array of deeds created
mapping (uint256 => address) private _ownerOfMap;
mapping (uint256 => address) private _approvedMap;
mapping (uint256 => uint256) public priceMap;
// CryptoMarchMadness specific methods
function CryptoMarchMadness(uint256 _basePoolFeeInWei, uint256 _collectorFeeInWei, address collector) public {
totalCount = 0;
totalPoints = 0;
currentRound = 6;
currentState = 0;
_delegateOwner = msg.sender;
_collector = collector;
basePoolFeeInWei = _basePoolFeeInWei;
collectorFeeInWei = _collectorFeeInWei;
}
modifier mustBeValidDeed(uint256 _deedId) {
require(_ownerOfMap[_deedId] != address(0));
_;
}
modifier mustBeAuthorized(uint256 _deedId) {
require(msg.sender == _ownerOfMap[_deedId] || msg.sender == _approvedMap[_deedId] || msg.sender == _delegateOwner);
_;
}
modifier mustBeDelegateOwner {
require(msg.sender == _delegateOwner);
_;
}
function buyIn(uint256 _deedId) external payable {
require(currentRound == 6 || currentRound == 7);
if (currentRound == 6) {
require(msg.value >= basePoolFeeInWei);
} else {
require(msg.value >= 2 * basePoolFeeInWei);
}
collectorPoolSizeInWei += collectorFeeInWei;
poolSizeInWei += (msg.value - collectorFeeInWei);
_ownerOfMap[_deedId] = msg.sender;
deeds.push(_deedId);
totalCount += 1;
}
function _scorePred(uint256 predicted) private view returns (uint8 _score) {
require(currentRound > 0 && currentRound <= 5);
uint8 startIdx = 0;
for (uint8 round = 0; round < currentRound; round++) {
uint8 len = uint8(2)**(4-round);
for (uint8 game = 0; game<len; game++) {
uint8 gameIdx = game + startIdx;
uint256 predGame = (predicted >> (gameIdx * 6)) & MASK;
uint256 actualGame = (currentState >> (gameIdx * 6)) & MASK;
if (predGame == actualGame) {
_score += uint8(2)**round;
}
}
startIdx += len;
}
}
function scoreDeed(uint256 deedId) external view mustBeValidDeed(deedId) returns (uint8 _score) {
_score = _scorePred(deedId);
}
function redeem(uint256 deedId)
external
mustBeValidDeed(deedId)
mustBeAuthorized(deedId)
{
require(currentRound == 5);
uint8 score = _scorePred(deedId);
uint256 share = poolSizeInWei * score / totalPoints;
delete _ownerOfMap[deedId];
delete _approvedMap[deedId];
msg.sender.transfer(share);
}
function updateState(uint8 _currentRound, uint256 _currentState, uint256 _totalPoints) external mustBeDelegateOwner() {
currentRound = _currentRound;
currentState = _currentState;
totalPoints = _totalPoints;
}
function collectFee() external mustBeDelegateOwner() {
_delegateOwner.transfer(collectorPoolSizeInWei);
}
function quitquitquit() external mustBeDelegateOwner() {
selfdestruct(_collector);
}
function _approve(address _approved, uint256 _deedId, uint256 _price)
private
mustBeValidDeed(_deedId)
mustBeAuthorized(_deedId)
{
_approvedMap[_deedId] = _approved;
if (_price > 0) {
priceMap[_deedId] = _price;
}
Approval(msg.sender, _approved, _deedId);
}
function approveWithPrice(address _approved, uint256 _deedId, uint256 _price) external {
_approve(_approved, _deedId, _price);
}
// ERC721 Implementation
function balanceOf(address _owner) external view returns (uint256 _balance) {
require(false);
}
function ownerOf(uint256 _deedId)
external
mustBeValidDeed(_deedId)
view
returns (address _owner)
{
_owner = _ownerOfMap[_deedId];
}
function transfer(address _to, uint256 _deedId)
external
mustBeValidDeed(_deedId)
mustBeAuthorized(_deedId)
payable
{
address owner = _ownerOfMap[_deedId];
uint256 sellingPrice = priceMap[_deedId];
require(owner != _to);
require(msg.value >= sellingPrice);
_ownerOfMap[_deedId] = _to;
delete _approvedMap[_deedId];
delete priceMap[_deedId];
if (sellingPrice > 0) {
uint256 transferFee = sellingPrice * 5 / 100;
uint256 toTransfer = sellingPrice - transferFee;
collectorPoolSizeInWei += transferFee;
owner.transfer(toTransfer);
}
Transfer(owner, _to, _deedId);
}
function approve(address _approved, uint256 _deedId) external payable {
_approve(_approved, _deedId, 0);
}
function delegate(address _delegate) external mustBeDelegateOwner() {
if (_delegate != address(0)) {
_delegateOwner = _delegate;
}
Delegation(msg.sender, _delegate);
}
// ERC-721Metadata Implementation
function name() external pure returns (string _name) {
_name = "Crypto March Madness";
}
function symbol() external pure returns (string _symbol) {
_symbol = "CMM";
}
function deedUri(uint256 _deedId) external view returns (string _deedUri) {
_deedUri = "https://cryptofinalfour.com/brackets/deedIdHex";
}
// ERC721Enumerable
function totalSupply() external view returns (uint256 _count) {
_count = totalCount;
}
function deedByIndex(uint256 _index) external view returns (uint256 _deedId) {
require(_index < deeds.length);
return deeds[_index];
}
function countOfOwners() external view returns (uint256 _count) {
_count = 0; // We don't keep track of owners, so just return 0. Spec says "do not throw"
}
function ownerByIndex(uint256 _index) external view returns (address _owner) {
require(false);
}
function deedOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 _deedId) {
require(false);
}
// ERC165 Implementation
function supportsInterface(bytes4 interfaceID) external view returns (bool) {
return false;
}
}
pragma solidity ^0.4.19;
interface ERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// use less than 30000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
pragma solidity ^0.4.19;
import "./ERC165.sol";
/// @title Required part of ERC-721 Deed Standard
/// @author William Entriken (https://phor.net)
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
/// Note: the ERC-165 (DRAFT) identifier for this interface is 0xb3a99827
// State: https://github.com/fulldecent/EIPs/commit/1a1295c903dfd2da18024c8c717054af394b847f
interface ERC721 /* is ERC165 */ {
/// @dev This emits when ownership of any deed changes by any mechanism.
/// This event emits when deeds are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of deeds
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the "approved deed controller" is implicitly reset to the
/// zero address.
event Transfer(address indexed _from, address indexed _to, uint256 _deedId);
/// @dev This emits when the "approved deed controller" for a deed is
/// changed or reaffirmed. The zero address indicates there is no approved
/// deed controller. When a Transfer event emits, this also indicates the
/// approved deed controller (if any) is reset to none.
event Approval(address indexed _owner, address indexed _approved, uint256 _deedId);
/// @dev This emits when the "delegate operator" for an account is changed
/// or reaffirmed. The zero address indicates there is no delegate
/// operator.
event Delegation(address indexed _owner, address indexed _delegate);
/// @notice Count all deeds assigned to an owner
/// @dev Deeds assigned to zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of deeds owned by `_owner`, possibly zero
function balanceOf(address _owner) external view returns (uint256 _balance);
/// @notice Find the owner of a deed
/// @param _deedId The identifier for a deed we are inspecting
/// @dev Deeds assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @return The address of the owner of the deed
function ownerOf(uint256 _deedId) external view returns (address _owner);
/// @notice Set a new owner for a deed
/// @dev Throws unless `msg.sender` is the current deed owner, the "delegate
/// operator" of the current deed owner, or the "approved deed controller".
/// Throws if `_to` currently owns the deed. Throws if `_to` is the zero
/// address.
/// @param _to The new owner for the deed
/// @param _deedId The deed to transfer
function transfer(address _to, uint256 _deedId) external payable;
/// @notice Set or reaffirm the "approved deed controller" for a deed
/// @dev The zero address indicates there is no approved deed controller.
/// @dev Throws unless `msg.sender` is the current deed owner, or the
/// "delegate operator" of the current deed owner.
/// @param _approved The new approved deed controller
/// @param _deedId The deed to approve
function approve(address _approved, uint256 _deedId) external payable;
/// @notice Set or reaffirm the "delegate operator" for this account
/// @dev The zero address indicates there is no delegate operator.
/// @param _delegate The new delegate operator
function delegate(address _delegate) external;
// CONFORMANCE TO ERC-165 (DRAFT) //////////////////////////////////////////
/// @notice Query if this implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
/// @title Optional metadata extension to ERC-721 Deed Standard
/// @author William Entriken (https://phor.net)
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
/// Note: the ERC-165 (DRAFT) identifier for this interface is 0x2a786f11
interface ERC721Metadata /* is ERC721 */ {
/// @notice A descriptive name for a collection of deeds in this contract
function name() external pure returns (string _name);
/// @notice An abbreviated name for deeds in this contract
function symbol() external pure returns (string _symbol);
/// @notice A distinct Uniform Resource Identifier (URI) for a given deed.
/// @dev Throws if `_deedId` is not a valid deed. URIs are defined in RFC
/// 3986. The URI may point to a JSON file that conforms to the "ERC721
/// Metadata JSON Schema".
function deedUri(uint256 _deedId) external view returns (string _deedUri);
}
/// @title Optional enumeration extension to ERC-721 Deed Standard
/// @author William Entriken (https://phor.net)
/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
/// Note: the ERC-165 (DRAFT) identifier for this interface is 0x5576ab6a
interface ERC721Enumerable /* is ERC721 */ {
/// @notice Count deeds tracked by this contract
/// @return A count of valid deeds tracked by this contract, where each one of
/// them has an assigned and queryable owner not equal to the zero address
function totalSupply() external view returns (uint256 _count);
/// @notice Enumerate active deeds
/// @dev Throws if `_index` >= `countOfDeeds()`.
/// Otherwise must not throw.
/// @param _index A counter less than `countOfDeeds()`
/// @return The identifier for the `_index`th deed, (sort order not
/// specified)
function deedByIndex(uint256 _index) external view returns (uint256 _deedId);
/// @notice Count of owners which own at least one deed
/// Must not throw.
/// @return A count of the number of owners which own deeds
function countOfOwners() external view returns (uint256 _count);
/// @notice Enumerate owners
/// @dev Throws if `_index` >= `countOfOwners()`
/// Otherwise must not throw.
/// @param _index A counter less than `countOfOwners()`
/// @return The address of the `_index`th owner (sort order not specified)
function ownerByIndex(uint256 _index) external view returns (address _owner);
/// @notice Enumerate deeds assigned to an owner
/// @dev Throws if `_index` >= `countOfDeedsByOwner(_owner)` or if
/// `_owner` is the zero address, representing invalid deeds.
/// Otherwise this must not throw.
/// @param _owner An address where we are interested in deeds owned by them
/// @param _index A counter less than `countOfDeedsByOwner(_owner)`
/// @return The identifier for the `_index`th deed assigned to `_owner`,
/// (sort order not specified)
function deedOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256 _deedId);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment