Example #1
0
    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)
Example #2
0
    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)