Provably-Fair Jackpots
DATA AND CONTRACT TRANSPARENCY
Everyworld is committed to the highest standards of transparency and fairness in the selection of jackpot winners. The system is designed to be provably fair, utilizing blockchain technology to ensure that all participants can verify the integrity and fairness of each jackpot.A diagram is provided below to help visualize the mechanism:
1. S3 Data Storage: Drawing and calculation data relevant to Everyworld jackpots are stored in a publicly accessible S3 bucket. This allows any participant to verify the data used in the drawing process. The URLs to access this data are provided below, using the May 14, 2024 jackpot as an example:
- User-Ticket Manifest: https://cdn.prod.everyworld.com/jackpots/s2d6/s2d6-entries-1715700664756.csv
- Winner-Selection Manifest: https://cdn.prod.everyworld.com/jackpots/s2d6/s2d6-calculation-results-1715700712596.txt
2. Blockchain Verification: Everyworld uses a smart contract to manage and verify jackpot metadata. This contract is deployed on Base and its code is verified for transparency. Additionally, a version of the contract is also available on the Base Sepolia testnet.
- JackpotMetaData Base (verified): https://basescan.org/address/0xdeba89f0B0606b0B26a0522b3Bd262C37B381eCa
- Owner Wallet Address: The JackpotMetadata contract is managed by the wallet address 0x085F788da51D82cA8AB67D7eC269c29312e970A5.
3. Checksum Verification: After uploading the drawing data to the S3 bucket, Everyworld generates a SHA-256 hash of the content. This hash, along with the creation time of the document, is recorded on the blockchain via the JackpotMetadata contract, providing a timestamped and immutable record. To verify the integrity of the data, use this tool:
PUBLISHING METADATA AND WINNER SELECTION
1. Metadata Publishing: Throughout the drawing period, participants can earn tickets for various activities, such as engaging with content in the Everyworld web app or holding $EVERY tokens. At the end of the drawing period, Everyworld compiles a list of all participants, with each entry in the CSV file detailing the user ID and the total number of tickets that user has earned. This structured data ensures that every ticket has an equal chance of winning relative to the number of tickets held by each user. The finalized CSV is then uploaded to the public S3 bucket.
2. Provably Fair Winner Selection:some text
- Data Formatting: Before selecting a winner, the data is formatted to facilitate weighted randomness in the drawing process. This means organizing the data so that the number of tickets each user holds is represented continuously in the dataset. For example, if User A has 4 tickets and User B has 2, the entries might appear as follows in the drawing data:
Javascript
{
0: User,
4: UserB,
6: UserC
...
}
3. Random Selection: A random number is generated using a seed derived from the hash of the subsequent Ethereum block after the data upload. This high-entropy method ensures the drawing is tamper-proof. The random number directly determines the winner by indexing into the structured user-ticket data, allowing each participant a fair chance based on the number of tickets held.
VERIFICATION PROCESS
Participants and observers can independently verify the winner by following these steps:
- Access the drawing data from the S3 URLs.
- Calculate the SHA-256 hash of the downloaded data.
- Compare the hash from the S3 upload with the one recorded on the blockchain.
- Review the structured ticket data and the blockchain-derived random seed to independently ascertain the winner.
REPRODUCIBLE RNG USING SEED
Everyworld provides the following sample code to assist with the verification process.
import pandas as pd
import numpy as np
import requests
WINNER_SELECTION_MANIFEST = 'https://cdn.prod.everyworld.com/jackpots/s2d6/s2d6-calculation-results-1715700712596.txt'
USER_TICKETS_MANIFEST='https://cdn.prod.everyworld.com/jackpots/s2d6/s2d6-entries-1715700664756.csv'
def get_winner_data():
# Fetch the data
response = requests.get(WINNER_SELECTION_MANIFEST)
data_dict=None
if response.status_code == 200:
data = response.text
# Parse the string to create a dictionary
data_dict = {}
for line in data.strip().split('\n'):
key, value = line.split(':', 1) # Split only at the first colon
data_dict[key.strip()] = value.strip()
return data_dict
def get_random_index_from_hash_numpy(hash_hex, array_size):
# Convert hash to an integer
seed = int(hash_hex, 16)
# Initialize the randomgen generator with the seed
rng = np.random.default_rng(seed)
# Generate a single random integer from 0 to 99
random_int = rng.integers(0, array_size)
return random_int
def getNumTickets():
data = pd.read_csv(USER_TICKETS_MANIFEST)
num_tickets = sum(data['entries'])
return num_tickets
winner_data = get_winner_data()
print("winner_data=", winner_data)
num_tickets = getNumTickets()
print("num_tickets=", num_tickets)
random_index = get_random_index_from_hash_numpy(winner_data["block_hash_used"], num_tickets)
print("ticket index from winner_data file=", winner_data["ticket_index"])
print("ticket index verified =", random_index)
if random_index == int(winner_data["ticket_index"]):
print("Winner ticket verified")
else:
print("Winner ticket not verified")
SUMMARY OF ARTIFACTS:
Wallet address that is owner of JackpotMetadata contract:
0x085F788da51D82cA8AB67D7eC269c29312e970A5
JackpotMetadata Base (verified):
https://basescan.org/address/0xdeba89f0B0606b0B26a0522b3Bd262C37B381eCa
JackpotMetadata Base Sepolia (verified):
https://sepolia.basescan.org/address/0xe8255A51c9eFC3F740895D803fFFe001812769DC
User-Ticket Manifest
https://cdn.prod.everyworld.com/jackpots/s2d6/s2d6-entries-1715700664756.csv
Winner-Selection Manifest
https://cdn.prod.everyworld.com/jackpots/s2d6/s2d6-calculation-results-1715700712596.txt