import hashlib import requests import random from io import StringIO import pandas as pd import time import urllib3 urllib3.disable_warnings() t0 = time.time() # Depressed Citizens NFTs to be distributed according to block #837777. We are ART, we are Ordinals. # The block hash is used as a seed to determine airdrop winners. # Check if you won. Learn more on https://depressedcitizens.com | https://discord.gg/nTh9vQs5sq # pull bitcoin block hash friom blockchain def get_block_hash(block_number): # Use the blockchain.com API to get block hash response = requests.get(f'https://blockchain.info/block-height/{block_number}?format=json') response_json = response.json() # The first block at this height block_hash = response_json['blocks'][0]['hash'] return block_hash # pull seed from block hash def get_seed_from_block(block_number): block_hash = get_block_hash(block_number) seed = int(block_hash, 16) return seed def read_csv_from_url(url): response = requests.get(url, verify=False) data = pd.read_csv(StringIO(response.text)) return data TARGET_BLOCK = 837777 NFT_ID_START = 8 NFT_ID_END = 3333 sheets = { 'Summary':'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=858543402&single=true&output=csv', 'PT': 'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=138126265&single=true&output=csv', 'OGs': 'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=1045826528&single=true&output=csv', 'TOP': 'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=27982701&single=true&output=csv', 'EARLY': 'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=811631446&single=true&output=csv', 'A+P+F': 'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=421503567&single=true&output=csv', 'LATE': 'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=153563119&single=true&output=csv', 'X': 'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=250760731&single=true&output=csv', 'SIMPLE': 'https://docs.google.com/spreadsheets/d/e/2PACX-1vTEKpIn_RV1scaDoobCD0W1v8H1QhOzP-mtw2ToytEuxf1NQ42W4t1Jspx7lJrB2ZDd--bFgt_hMjEs/pub?gid=0&single=true&output=csv' } # Planned draws (the order will be shuffled later) draws = ['PT','OGs','TOP','EARLY','A+P+F','LATE','X','SIMPLE'] # verify the checksum hash of Summary sheet is "ed19155d22423cd9e2b7f867ef0dc596751cc9ceaa548623e1af028153242fef" summary_csv = requests.get(sheets['Summary']).content #response.encoding = 'utf-8' hash = hashlib.sha256(summary_csv).hexdigest() # we ensure the summary hash is correct assert hash == 'ed19155d22423cd9e2b7f867ef0dc596751cc9ceaa548623e1af028153242fef', f'hash is invalid: {hash}' # set up NFT allocation table for PT #PT = pd.read_csv(sheets['PT']) PT = read_csv_from_url(sheets['PT']) column_ids = [4, 1] PT = PT.iloc[:, column_ids] PT_allocation_table = dict(zip(PT.iloc[1:,0], PT.iloc[1:,1].astype(int))) # set up NFT allocation table for OGs #OGs = pd.read_csv(sheets['OGs']) OGs = read_csv_from_url(sheets['OGs']) column_ids = [1 , 2] OGs = OGs.iloc[:, column_ids] OGs_allocation_table = dict(zip(OGs.iloc[1:,0], OGs.iloc[1:,1].astype(int))) # load summary sheet #summary = pd.read_csv(sheets['Summary']) summary = read_csv_from_url(sheets['Summary']) # Pull addresses from summary sheet summary_PT_list = summary.iloc[15:19, 0].tolist() summary_OGs_list = summary.iloc[21:68, 0].tolist() summary_TOP_list = summary.iloc[15:1295, 1].tolist() summary_EARLY_list = summary.iloc[15:117, 2].tolist() summary_APF_list = summary.iloc[15:82, 3].tolist() summary_LATE_list = summary.iloc[15:84, 4].tolist() summary_X_list = summary.iloc[15:170, 5].tolist() summary_SIMPLE_list = summary.iloc[15:22422, 6].tolist() draws_specs = { 'PT': {"type": "guaranteed", "amount":326 ,"number of participants": 4, "allocation_table": PT_allocation_table }, # 7 legendary NFTS (1-7) will be removed from the allocation. 'OGs': {"type": "guaranteed", "amount":146 ,"number of participants": 47, "allocation_table": OGs_allocation_table }, 'TOP': {"type": "random", "amount":1222, "number of participants": 1279, "table": summary_TOP_list}, 'EARLY': {"type": "random", "amount":90 , "number of participants": 102, "table": summary_EARLY_list}, 'A+P+F': {"type": "random", "amount":52, "number of participants": 67, "table": summary_APF_list}, 'LATE': {"type": "random", "amount":46 , "number of participants": 69, "table": summary_LATE_list}, 'X': {"type": "random", "amount":85, "number of participants": 155, "table": summary_X_list}, 'SIMPLE': {"type": "random", "amount":1333, "number of participants": 22406, "table": summary_SIMPLE_list} } # verify the sum of all draws is 3333 - 7 - 26 = 3300 assert sum([draws_specs[draw]['amount'] for draw in draws]) == 3300, "The sum of all draws should be equal to the number of NFTs to be allocated minus the number of legendary NFTs" random.seed(get_seed_from_block(TARGET_BLOCK)) reserved_nfts = set() winners = {} winner_list = {} nfts = [str(nft_id) for nft_id in range(NFT_ID_START, NFT_ID_END+1)] # shuffle the list of NFTs using the block hash as seed for i in range(777): random.shuffle(nfts) random.shuffle(draws) print("\nThe draws will be run in the following order:", draws) print("\nStarting draws...") for draw in draws: print(f"\n* Running draw {draws.index(draw)+1} of {len(draws)} for", draw) random.shuffle(nfts) draw_spec = draws_specs[draw] print(f" - {draw_spec['amount']} NFTs to be allocated") print(f" - type of draw: {draw_spec['type']}") print(f" - number of participants: {draw_spec['number of participants']}") if draw_spec['type'] == 'guaranteed': shuffle_participants = list(draw_spec['allocation_table'].keys()) random.shuffle(shuffle_participants) for i in range(draw_spec['number of participants']): winner = shuffle_participants[i] allocated_nfts = draw_spec['allocation_table'][winner] winner_list[winner] = draw for nft in range(allocated_nfts): chosen_nft = random.choice(nfts) while chosen_nft in reserved_nfts: chosen_nft = random.choice(nfts) if winner in winners: winners[winner].append(chosen_nft) else: winners[winner] = [chosen_nft] reserved_nfts.add(chosen_nft) elif draw_spec['type'] == 'random': shuffle_participants = draw_spec['table'] random.shuffle(shuffle_participants) for i in range(draw_spec['amount']): winner = random.choice(shuffle_participants) while winner in winners: winner = random.choice(shuffle_participants) winner_list[winner] = draw chosen_nft = random.choice(nfts) while chosen_nft in reserved_nfts: chosen_nft = random.choice(nfts) if winner in winners: winners[winner].append(chosen_nft) else: winners[winner] = [chosen_nft] reserved_nfts.add(chosen_nft) # print unallocated NFTs (should be 26, the legendary NFTs are not included in the draw) print("\nUnallocated NFTs:") unallocated_nfts = [] for nft in (nfts): if nft not in reserved_nfts: unallocated_nfts.append(nft) print(unallocated_nfts) # save winners to csv (Wallet, NFT won, list of NFTs won) winners_df = pd.DataFrame(winners.items(), columns=['wallet', 'nfts']) # Add a new column 'nfts_count' for the number of NFTs won winners_df['nfts_count'] = winners_df['nfts'].apply(len) # Convert the list of NFTs won to a string in 'nfts' column winners_df['nfts'] = winners_df['nfts'].apply(', '.join) # Add a new column 'draw_type' for the type of draw winners_df['draw_type'] = winners_df['wallet'].map(winner_list) # Sort the winners by the number of NFTs won winners_df = winners_df.sort_values('nfts_count', ascending=False) # Save the DataFrame to a CSV file winners_df.to_csv(f'winners_at_#{TARGET_BLOCK}.csv', index=False) print("\n*****************************************************************************************") print(f"\tWinners saved to winners_at_#{TARGET_BLOCK}.csv, congratulations to all winners!") print("*****************************************************************************************") print(f"\nTime taken: {time.time()-t0:.2f} seconds")
#67,309,432
TXT
#67,309,433
HTML
Preview not available
#67,309,437
JPEG
#67,309,438
HTML
#67,309,439
HTML
Preview not available
#67,309,440
PNG
#67,309,443
HTML
Preview not available
#67,309,446
WEBP
#67,309,448
HTML
Preview not available
#67,309,450
WEBP
#67,309,453
HTML
Preview not available
#67,309,455
JPEG
#67,309,456
MP4
#67,309,457
MP4
#67,309,458
MP4
#67,309,459
MP4
#67,309,460
MP4
#67,309,461
MP4
#67,309,463
MP4
#67,309,465
MP4
#67,309,466
MP4
#67,309,467
MP4
#67,309,469
MP4
#67,309,470
MP4
#67,309,474
MP4
#67,309,475
MP4
#67,309,476
MP4
#67,309,477
MP4
#67,309,480
MP4
#67,309,481
MP4
#67,309,482
MP4
#67,309,484
MP4
#67,309,485
MP4
#67,309,487
MP4
#67,309,488
MP4
#67,309,489
MP4
#67,309,490
MP4
#67,309,491
MP4
#67,309,492
MP4
#67,309,494
MP4
#67,309,495
MP4
#67,309,496
MP4
JS
#67,309,568
JavaScript
#67,309,664
HTML
#67,309,775
HTML
#67,309,776
HTML
#67,309,777
HTML
#67,309,778
HTML
#67,309,779
HTML
#67,309,780
HTML