def handle(self, *args, **options): # setup payment_threshold_usd = 1 network = 'mainnet' if not settings.DEBUG else 'rinkeby' from_address = settings.MINICLR_ADDRESS from_pk = settings.MINICLR_PRIVATE_KEY DAI_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f' if network == 'mainnet' else '0x8f2e097e79b1c51be9cba42658862f0192c3e487' # find a round that has recently expired minutes_ago = options['minutes_ago'] cursor_time = timezone.now() - timezone.timedelta(minutes=minutes_ago) mr = MatchRound.objects.filter(valid_from__lt=cursor_time, valid_to__gt=cursor_time, valid_to__lt=timezone.now()).first() if options['round_number']: mr = MatchRound.objects.get(number=options['round_number']) if not mr: print( f'No Match Round Found that ended between {cursor_time} <> {timezone.now()}' ) return print(mr) # finalize rankings if options['what'] == 'finalize': rankings = mr.ranking.filter(final=False, paid=False).order_by('-match_total') print(rankings.count(), "to finalize") for ranking in rankings: ranking.final = True ranking.save() print(rankings.count(), " finalied") # payout rankings (round must be finalized first) if options['what'] == 'payout': rankings = mr.ranking.filter(final=True, paid=False).order_by('-match_total') print(rankings.count(), " to pay") w3 = get_web3(network) for ranking in rankings: # figure out amount_owed profile = ranking.profile owed_rankings = profile.match_rankings.filter(final=True, paid=False) amount_owed = sum( owed_rankings.values_list('match_total', flat=True)) print( f"paying {ranking.profile.handle} who is owed {amount_owed} ({ranking.match_total} from this round)" ) # validate error = None if amount_owed < payment_threshold_usd: error = ("- less than amount owed; continue") address = profile.preferred_payout_address if not address: error = ("- address not on file") if error: print(error) ranking.payout_tx_status = error ranking.save() continue # issue payment contract = w3.eth.contract(Web3.toChecksumAddress(DAI_ADDRESS), abi=abi) address = Web3.toChecksumAddress(address) amount = int(amount_owed * 10**18) tx = contract.functions.transfer( address, amount ).buildTransaction({ 'nonce': w3.eth.getTransactionCount(from_address), 'gas': 100000, 'gasPrice': int( float(recommend_min_gas_price_to_confirm_in_time(1)) * 10**9 * 1.4) }) signed = w3.eth.account.signTransaction(tx, from_pk) tx_id = w3.eth.sendRawTransaction(signed.rawTransaction).hex() print("paid via", tx_id) # wait for tx to clear while not has_tx_mined(tx_id, network): time.sleep(1) ranking.payout_tx_status, ranking.payout_tx_issued = get_tx_status( tx_id, network, timezone.now()) ranking.paid = True ranking.payout_txid = tx_id ranking.save() for other_ranking in owed_rankings: other_ranking.paid = True other_ranking.payout_txid = ranking.payout_txid other_ranking.payout_tx_issued = ranking.payout_tx_issued other_ranking.payout_tx_status = ranking.payout_tx_status other_ranking.save() # create earning object from_profile = Profile.objects.get(handle='gitcoinbot') Earning.objects.update_or_create( source_type=ContentType.objects.get(app_label='townsquare', model='matchranking'), source_id=ranking.pk, defaults={ "created_on": ranking.created_on, "org_profile": None, "from_profile": from_profile, "to_profile": ranking.profile, "value_usd": amount_owed, "url": 'https://gitcoin.co/#clr', "network": network, }) Activity.objects.create(created_on=timezone.now(), profile=ranking.profile, activity_type='mini_clr_payout', metadata={ "amount": float(amount_owed), "number": int(mr.number), "mr_pk": int(mr.pk), "round_description": f"Mini CLR Round {mr.number}" }) from marketing.mails import match_distribution match_distribution(ranking) print("paid ", ranking) time.sleep(30) # announce finalists (round must be finalized first) from_profile = Profile.objects.get(handle='gitcoinbot') if options['what'] == 'announce': copy = f"Mini CLR Round {mr.number} Winners:<BR>" rankings = mr.ranking.filter( final=True).order_by('-match_total')[0:10] print(rankings.count(), " to announce") for ranking in rankings: profile_link = f"<a href=/{ranking.profile}>@{ranking.profile}</a>" copy += f" - {profile_link} was ranked <strong>#{ranking.number}</strong>. <BR>" metadata = { 'copy': copy, } Activity.objects.create( created_on=timezone.now(), profile=from_profile, activity_type='consolidated_mini_clr_payout', metadata=metadata)
def handle(self, *args, **options): # setup minutes_ago = 10 if not settings.DEBUG else 40 payment_threshold_usd = 1 network = 'mainnet' if not settings.DEBUG else 'rinkeby' from_address = settings.MINICLR_ADDRESS from_pk = settings.MINICLR_PRIVATE_KEY DAI_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f' if network == 'mainnet' else '0x8f2e097e79b1c51be9cba42658862f0192c3e487' provider = settings.WEB3_HTTP_PROVIDER if network == 'mainnet' else "https://rinkeby.infura.io/" # find a round that has recently expired cursor_time = timezone.now() - timezone.timedelta(minutes=minutes_ago) mr = MatchRound.objects.filter(valid_from__lt=cursor_time, valid_to__gt=cursor_time, valid_to__lt=timezone.now()).first() if not mr: print( f'No Match Round Found that ended between {cursor_time} <> {timezone.now()}' ) return print(mr) # finalize rankings rankings = mr.ranking.filter(final=False, paid=False).order_by('number') print(rankings.count()) for ranking in rankings: ranking.final = True ranking.save() # payout rankings rankings = mr.ranking.filter(final=True, paid=False).order_by('number') print(rankings.count()) w3 = Web3(HTTPProvider(provider)) for ranking in rankings: print(ranking) # figure out amount_owed profile = ranking.profile owed_rankings = profile.match_rankings.filter(final=True, paid=False) amount_owed = sum( owed_rankings.values_list('match_total', flat=True)) # validate error = None if amount_owed < payment_threshold_usd: error = ("- less than amount owed; continue") address = profile.preferred_payout_address if not address: error = ("- address not on file") if error: ranking.payout_tx_status = error ranking.save() continue # issue payment contract = w3.eth.contract(Web3.toChecksumAddress(DAI_ADDRESS), abi=abi) address = Web3.toChecksumAddress(address) amount = int(amount_owed * 10**18) tx = contract.functions.transfer(address, amount).buildTransaction( { 'nonce': w3.eth.getTransactionCount(from_address), 'gas': 100000, 'gasPrice': recommend_min_gas_price_to_confirm_in_time(1) * 10**9 }) signed = w3.eth.account.signTransaction(tx, from_pk) tx_id = w3.eth.sendRawTransaction(signed.rawTransaction).hex() # wait for tx to clear while not has_tx_mined(tx_id, network): time.sleep(1) ranking.payout_tx_status, ranking.payout_tx_issued = get_tx_status( tx_id, network, timezone.now()) ranking.paid = True ranking.payout_txid = tx_id ranking.save() for other_ranking in owed_rankings: other_ranking.paid = True other_ranking.payout_txid = ranking.payout_txid other_ranking.payout_tx_issued = ranking.payout_tx_issued other_ranking.payout_tx_status = ranking.payout_tx_status other_ranking.save() # create earning object from dashboard.models import Earning, Profile, Activity from django.contrib.contenttypes.models import ContentType from_profile = Profile.objects.get(handle='gitcoinbot') Earning.objects.update_or_create( source_type=ContentType.objects.get(app_label='townsquare', model='matchranking'), source_id=ranking.pk, defaults={ "created_on": ranking.created_on, "org_profile": None, "from_profile": from_profile, "to_profile": ranking.profile, "value_usd": amount_owed, "url": 'https://gitcoin.co/#clr', "network": network, }) Activity.objects.create(created_on=timezone.now(), profile=ranking.profile, activity_type='mini_clr_payout', metadata={ "amount": amount_owed, }) from marketing.mails import match_distribution match_distribution(ranking)