Esempio n. 1
0
def send_tip_4(request):
    """Handle the fourth stage of sending a tip (the POST).

    Returns:
        JsonResponse: response with success state.

    """
    response = {
        'status': 'OK',
        'message': _('Tip Sent'),
    }

    is_user_authenticated = request.user.is_authenticated
    from_username = request.user.username if is_user_authenticated else ''

    params = json.loads(request.body)
    txid = params['txid']
    destinationAccount = params['destinationAccount']
    is_direct_to_recipient = params.get('is_direct_to_recipient', False)
    if is_direct_to_recipient:
        tip = Tip.objects.get(
            metadata__direct_address=destinationAccount,
            metadata__creation_time=params['creation_time'],
            metadata__salt=params['salt'],
        )
    else:
        tip = Tip.objects.get(
            metadata__address=destinationAccount,
            metadata__salt=params['salt'],
        )
    is_authenticated_for_this_via_login = (tip.from_username and
                                           tip.from_username == from_username)
    is_authenticated_for_this_via_ip = tip.ip == get_ip(request)
    is_authed = is_authenticated_for_this_via_ip or is_authenticated_for_this_via_login
    if not is_authed:
        response = {
            'status': 'error',
            'message': _('Permission Denied'),
        }
        return JsonResponse(response)

    # db mutations
    tip.txid = txid
    tip.tx_status = 'pending'
    if is_direct_to_recipient:
        tip.receive_txid = txid
        tip.receive_tx_status = 'pending'
        tip.receive_address = destinationAccount
    tip.save()

    # notifications
    maybe_market_tip_to_github(tip)
    maybe_market_tip_to_slack(tip, 'New tip')
    if tip.primary_email:
        maybe_market_tip_to_email(tip, [tip.primary_email])
    record_user_action(tip.from_username, 'send_tip', tip)
    record_tip_activity(tip, tip.from_username,
                        'new_tip' if tip.username else 'new_crowdfund')

    return JsonResponse(response)
Esempio n. 2
0
def receive_tip_v2(request, pk, txid, network):
    """Handle the receiving of a tip (the POST).
    TODO: Deprecate after v3 has been live for a month.
    Returns:
        TemplateResponse: the UI with the tip confirmed

    """

    tip = Tip.objects.get(web3_type='v2',
                          metadata__priv_key=pk,
                          txid=txid,
                          network=network)

    if tip.receive_txid:
        messages.info(request, 'This tip has already been received')

    not_mined_yet = get_web3(tip.network).eth.getBalance(
        Web3.toChecksumAddress(tip.metadata['address'])) == 0
    if not_mined_yet:
        messages.info(
            request,
            f'This tx {tip.txid}, is still mining.  Please wait a moment before submitting the receive form.'
        )
    """Receive a tip."""
    if request.POST and not tip.receive_txid:
        params = request.POST

        # db mutations
        try:
            address = params['forwarding_address']
            tip.receive_txid = tip.payout_to(address)
            tip.receive_address = address
            tip.received_on = timezone.now()
            tip.save()
            record_user_action(tip.from_username, 'receive_tip', tip)
            record_tip_activity(tip, tip.from_username, 'receive_tip')
            messages.success(request, 'This tip has been received')
        except Exception as e:
            messages.error(request, str(e))
            logger.exception(e)

    params = {
        'issueURL':
        request.GET.get('source'),
        'class':
        'receive',
        'title':
        _('Receive Tip'),
        'gas_price':
        round(
            recommend_min_gas_price_to_confirm_in_time(
                confirm_time_minutes_target), 1),
        'tip':
        tip,
        'disable_inputs':
        tip.receive_txid or not_mined_yet,
    }

    return TemplateResponse(request, 'onepager/receive_v2.html', params)
def start_work_applicant_expired_executer(interest, bounty):

    start_work_approved(interest, bounty)
    start_work_applicant_expired(interest, bounty)
    interest.pending = False
    interest.acceptance_date = timezone.now()
    interest.save()
    record_user_action(interest.profile.user, 'worker_approved', bounty)
Esempio n. 4
0
def send_tip_4(request):
    """Handle the fourth stage of sending a tip (the POST)

    Returns:
        JsonResponse: response with success state.

    """
    response = {
        'status': 'OK',
        'message': _('Tip Sent'),
    }

    is_user_authenticated = request.user.is_authenticated
    from_username = request.user.username if is_user_authenticated else ''
    primary_from_email = request.user.email if is_user_authenticated else ''
    access_token = request.user.profile.get_access_token(
    ) if is_user_authenticated else ''
    to_emails = []

    params = json.loads(request.body)
    txid = params['txid']
    destinationAccount = params['destinationAccount']
    tip = Tip.objects.get(metadata__address=destinationAccount)
    is_authenticated_for_this_via_login = (tip.from_username and
                                           tip.from_username == from_username)
    is_authenticated_for_this_via_ip = tip.ip == get_ip(request)
    is_authed = is_authenticated_for_this_via_ip or is_authenticated_for_this_via_login
    if not is_authed:
        response = {
            'status': 'error',
            'message': _('Permission Denied'),
        }
        return JsonResponse(response)

    # db mutations
    tip.txid = txid
    tip.save()

    # notifications
    maybe_market_tip_to_github(tip)
    maybe_market_tip_to_slack(tip, 'new_tip')
    maybe_market_tip_to_email(tip, to_emails)
    record_user_action(tip.username, 'send_tip', tip)
    record_tip_activity(tip, tip.from_name, 'new_tip')

    return JsonResponse(response)
Esempio n. 5
0
def receive_tip_legacy(request):
    """Receive a tip."""
    # TODO: Deprecate after v2 has been live for a month
    if request.body:
        status = 'OK'
        message = _('Tip has been received')
        params = json.loads(request.body)

        # db mutations
        try:
            tip = Tip.objects.get(txid=params['txid'])
            tip.receive_address = params['receive_address']
            tip.receive_txid = params['receive_txid']
            tip.received_on = timezone.now()
            tip.save()
            record_user_action(tip.from_username, 'receive_tip', tip)
            record_tip_activity(tip, tip.from_username, 'receive_tip')
        except Exception as e:
            status = 'error'
            message = str(e)

        # http response
        response = {
            'status': status,
            'message': message,
        }

        return JsonResponse(response)

    params = {
        'issueURL':
        request.GET.get('source'),
        'class':
        'receive',
        'title':
        _('Receive Tip'),
        'gas_price':
        round(
            recommend_min_gas_price_to_confirm_in_time(
                confirm_time_minutes_target), 1),
    }

    return TemplateResponse(request, 'onepager/receive_legacy.html', params)
Esempio n. 6
0
def receive_tip_v3(request, key, txid, network):
    """Handle the receiving of a tip (the POST).

    Returns:
        TemplateResponse: the UI with the tip confirmed.

    """
    these_tips = Tip.objects.filter(web3_type='v3', txid=txid, network=network)
    tips = these_tips.filter(metadata__reference_hash_for_receipient=key) | these_tips.filter(metadata__reference_hash_for_funder=key)
    tip = tips.first()
    is_authed = request.user.username.lower() == tip.username.lower() or request.user.username.lower() == tip.from_username.lower() or not tip.username
    not_mined_yet = get_web3(tip.network).eth.getBalance(Web3.toChecksumAddress(tip.metadata['address'])) == 0
    did_fail = False
    if not_mined_yet:
        tip.update_tx_status()
        did_fail = tip.tx_status in ['dropped', 'unknown', 'na', 'error']

    if not request.user.is_authenticated or request.user.is_authenticated and not getattr(
        request.user, 'profile', None
    ):
        login_redirect = redirect('/login/github?next=' + request.get_full_path())
        return login_redirect
    num_redemptions = tip.metadata.get("num_redemptions", 0)
    max_redemptions = tip.metadata.get("max_redemptions", 0)
    is_redeemable = not (tip.receive_txid and (num_redemptions >= max_redemptions)) and is_authed
    has_this_user_redeemed = request.user.profile.tip_payouts.filter(tip=tip).count()
    if has_this_user_redeemed:
        is_redeemable = False
    if not is_redeemable:
        messages.info(request, 'This tip has been received already')
    elif not is_authed:
        messages.error(request, f'This tip is for @{tip.username} but you are logged in as @{request.user.username}.  Please logout and log back in as {tip.username}.')
    elif did_fail:
        messages.info(request, f'This tx {tip.txid}, failed.  Please contact the sender and ask them to send the tx again.')
    elif not_mined_yet:
        messages.info(request, f'This tx {tip.txid}, is still mining.  Please wait a moment before submitting the receive form.')
    elif request.POST.get('receive_txid') and is_redeemable:
        params = request.POST

        # db mutations
        try:
            profile = get_profile(tip.username)
            eth_address = params['forwarding_address']
            if not is_valid_eth_address(eth_address):
                eth_address = profile.preferred_payout_address
            if params['save_addr']:
                if profile:
                    profile.preferred_payout_address = eth_address
                    profile.save()
            tip.receive_txid = params['receive_txid']
            tip.receive_tx_status = 'pending'
            tip.receive_address = eth_address
            tip.received_on = timezone.now()
            num_redemptions = tip.metadata.get("num_redemptions", 0)
            # note to future self: to create a tip like this in the future set
            # tip.username
            # tip.metadata.max_redemptions
            # tip.metadata.override_send_amount
            # tip.amount to the amount you want to send 
            # ,"override_send_amount":1,"max_redemptions":29

            num_redemptions += 1
            tip.metadata["num_redemptions"] = num_redemptions
            tip.save()
            record_user_action(tip.from_username, 'receive_tip', tip)
            record_tip_activity(tip, tip.username, 'receive_tip')
            TipPayout.objects.create(
                txid=tip.receive_txid,
                profile=request.user.profile,
                tip=tip,
                )
            messages.success(request, 'This tip has been received')
            is_redeemable = False
            has_this_user_redeemed = True
        except Exception as e:
            messages.error(request, str(e))
            logger.exception(e)

    params = {
        'issueURL': request.GET.get('source'),
        'class': 'receive',
        'title': _('Receive Tip'),
        'gas_price': round(recommend_min_gas_price_to_confirm_in_time(120), 1),
        'tip': tip,
        'has_this_user_redeemed': has_this_user_redeemed,
        'key': key,
        'is_redeemable': is_redeemable,
        'is_authed': is_authed,
        'disable_inputs': not is_redeemable or not is_authed,
    }

    return TemplateResponse(request, 'onepager/receive.html', params)
Esempio n. 7
0
def receive(request, key, txid, network):
    """Handle the receiving of a kudos (the POST).

    Returns:
        TemplateResponse: the UI with the kudos confirmed

    """
    these_kudos_transfers = KudosTransfer.objects.filter(web3_type='v3', txid=txid, network=network)
    kudos_transfers = these_kudos_transfers.filter(
        Q(metadata__reference_hash_for_receipient=key) |
        Q(metadata__reference_hash_for_funder=key)
    )
    kudos_transfer = kudos_transfers.first()
    if not kudos_transfer:
        raise Http404

    is_authed = kudos_transfer.trust_url or request.user.username.replace('@', '') in [
        kudos_transfer.username.replace('@', ''),
        kudos_transfer.from_username.replace('@', '')
    ]
    not_mined_yet = get_web3(kudos_transfer.network).eth.getBalance(
        Web3.toChecksumAddress(kudos_transfer.metadata['address'])) == 0
    did_fail = False
    if not_mined_yet:
        kudos_transfer.update_tx_status()
        did_fail = kudos_transfer.tx_status in ['dropped', 'unknown', 'na', 'error']

    if not kudos_transfer.trust_url:
        if not request.user.is_authenticated or request.user.is_authenticated and not getattr(
            request.user, 'profile', None
        ):
            login_redirect = redirect('/login/github?next=' + request.get_full_path())
            return login_redirect

    if kudos_transfer.receive_txid:
        messages.info(request, _('This kudos has been received'))
    elif not is_authed:
        messages.error(
            request, f'This kudos is for {kudos_transfer.username} but you are logged in as {request.user.username}.  Please logout and log back in as {kudos_transfer.username}.')
    elif did_fail:
        messages.info(request, f'This tx {kudos_transfer.txid}, failed.  Please contact the sender and ask them to send the tx again.')
    elif not_mined_yet and not request.GET.get('receive_txid'):
        message = mark_safe(
            f'The <a href="https://etherscan.io/tx/{txid}">transaction</a> is still mining.  '
            'Please wait a moment before submitting the receive form.'
        )
        messages.info(request, message)
    elif request.GET.get('receive_txid') and not kudos_transfer.receive_txid:
        params = request.GET

        # db mutations
        try:
            if params['save_addr']:
                profile = get_profile(kudos_transfer.username.replace('@', ''))
                if profile:
                    # TODO: Does this mean that the address the user enters in the receive form
                    # Will overwrite an already existing preferred_payout_address?  Should we
                    # ask the user to confirm this?
                    profile.preferred_payout_address = params['forwarding_address']
                    profile.save()
            kudos_transfer.receive_txid = params['receive_txid']
            kudos_transfer.receive_address = params['forwarding_address']
            kudos_transfer.received_on = timezone.now()
            if request.user.is_authenticated:
                kudos_transfer.recipient_profile = request.user.profile
            kudos_transfer.save()
            record_user_action(kudos_transfer.from_username, 'receive_kudos', kudos_transfer)
            record_kudos_email_activity(kudos_transfer, kudos_transfer.username, 'receive_kudos')
            record_kudos_activity(
                kudos_transfer,
                kudos_transfer.from_username,
                'new_kudos' if kudos_transfer.username else 'new_crowdfund'
            )
            messages.success(request, _('This kudos has been received'))
        except Exception as e:
            messages.error(request, str(e))
            logger.exception(e)

    params = {
        'issueURL': request.GET.get('source'),
        'class': 'receive',
        'gas_price': round(recommend_min_gas_price_to_confirm_in_time(120), 1),
        'kudos_transfer': kudos_transfer,
        'title': f"Receive {kudos_transfer.kudos_token_cloned_from.humanized_name} Kudos" if kudos_transfer and kudos_transfer.kudos_token_cloned_from else _('Receive Kudos'),
        'avatar_url': kudos_transfer.kudos_token_cloned_from.img_url if kudos_transfer and kudos_transfer.kudos_token_cloned_from else None,
        'card_desc': f"You've received a {kudos_transfer.kudos_token_cloned_from.humanized_name} kudos!" if kudos_transfer and kudos_transfer.kudos_token_cloned_from else _('You\'ve received a kudos'),
        'key': key,
        'is_authed': is_authed,
        'disable_inputs': kudos_transfer.receive_txid or not_mined_yet or not is_authed,
        'tweet_text': urllib.parse.quote_plus(f"I just got a {kudos_transfer.kudos_token_cloned_from.humanized_name} Kudos on @GetGitcoin.  ")
    }

    return TemplateResponse(request, 'transaction/receive.html', params)
Esempio n. 8
0
def receive_tip_v3(request, key, txid, network):
    """Handle the receiving of a tip (the POST)

    Returns:
        TemplateResponse: the UI with the tip confirmed

    """

    these_tips = Tip.objects.filter(web3_type='v3', txid=txid, network=network)
    tips = these_tips.filter(
        metadata__reference_hash_for_receipient=key) | these_tips.filter(
            metadata__reference_hash_for_funder=key)
    tip = tips.first()
    is_authed = request.user.username == tip.username or request.user.username == tip.from_username
    not_mined_yet = get_web3(tip.network).eth.getBalance(
        Web3.toChecksumAddress(tip.metadata['address'])) == 0

    if not request.user.is_authenticated or request.user.is_authenticated and not getattr(
            request.user, 'profile'):
        login_redirect = redirect('/login/github?next=' +
                                  request.get_full_path())
        return login_redirect
    elif tip.receive_txid:
        messages.info(request, 'This tip has been received')
    elif not is_authed:
        messages.error(
            request,
            f'This tip is for {tip.username} but you are logged in as {request.user.username}.  Please logout and log back in as {tip.username}.'
        )
    elif not_mined_yet:
        messages.info(
            request,
            f'This tx {tip.txid}, is still mining.  Please wait a moment before submitting the receive form.'
        )
    elif request.GET.get('receive_txid') and not tip.receive_txid:
        params = request.GET

        # db mutations
        try:
            if params['save_addr']:
                profile = get_profile(tip.username)
                if profile:
                    profile.preferred_payout_address = params[
                        'forwarding_address']
                    profile.save()
            tip.receive_txid = params['receive_txid']
            tip.receive_address = params['forwarding_address']
            tip.received_on = timezone.now()
            tip.save()
            record_user_action(tip.from_username, 'receive_tip', tip)
            record_tip_activity(tip, tip.from_username, 'receive_tip')
            messages.success(request, 'This tip has been received')
        except Exception as e:
            messages.error(request, str(e))
            logger.exception(e)

    params = {
        'issueURL': request.GET.get('source'),
        'class': 'receive',
        'title': _('Receive Tip'),
        'gas_price': round(recommend_min_gas_price_to_confirm_in_time(120), 1),
        'tip': tip,
        'key': key,
        'is_authed': is_authed,
        'disable_inputs': tip.receive_txid or not_mined_yet or not is_authed,
    }

    return TemplateResponse(request, 'onepager/receive.html', params)
Esempio n. 9
0
def redeem_bulk_coupon(coupon,
                       profile,
                       address,
                       ip_address,
                       save_addr=False,
                       submit_later=False,
                       exit_after_sending_tx=False,
                       max_gas_price_we_are_willing_to_pay_gwei=15):
    try:
        address = Web3.toChecksumAddress(address)
    except:
        error = "You must enter a valid Ethereum address (so we know where to send your Kudos). Please try again."
        return None, error, None

    # handle form submission
    kudos_transfer = None
    if save_addr:
        profile.preferred_payout_address = address
        profile.save()

    private_key = settings.KUDOS_PRIVATE_KEY if not coupon.sender_pk else coupon.sender_pk
    kudos_owner_address = settings.KUDOS_OWNER_ACCOUNT if not coupon.sender_address else coupon.sender_address
    gas_price_confirmation_time = 1 if not coupon.sender_address else 60
    gas_price_multiplier = 1.3 if not coupon.sender_address else 1
    kudos_contract_address = Web3.toChecksumAddress(
        settings.KUDOS_CONTRACT_MAINNET)
    kudos_owner_address = Web3.toChecksumAddress(kudos_owner_address)
    w3 = get_web3(coupon.token.contract.network)
    contract = w3.eth.contract(Web3.toChecksumAddress(kudos_contract_address),
                               abi=kudos_abi())
    nonce = w3.eth.getTransactionCount(kudos_owner_address)
    gas_price = int(
        int(
            recommend_min_gas_price_to_confirm_in_time(
                gas_price_confirmation_time) * 10**9) * gas_price_multiplier)
    tx = contract.functions.clone(
        address, coupon.token.token_id, 1).buildTransaction({
            'nonce':
            nonce,
            'gas':
            500000,
            'gasPrice':
            gas_price,
            'value':
            int(coupon.token.price_finney / 1000.0 * 10**18),
        })

    if not profile.is_brightid_verified and not profile.is_twitter_verified and not profile.trust_profile and profile.github_created_on > (
            timezone.now() - timezone.timedelta(days=7)):
        error = f'Your github profile is too new, so you cannot receive kudos.  Please verifiy your profile on BrightID and/or Twitter to proceed.'
        return None, error, None
    else:

        if profile.bulk_transfer_redemptions.filter(coupon=coupon).exists():
            error = f'You have already redeemed this kudos.'
            return None, error, None

        signed = w3.eth.account.signTransaction(tx, private_key)
        retry_later = False
        tx_status = 'pending'

        if submit_later:
            txid = ''
            tx_status = 'not_subed'
        else:
            try:
                # TODO - in the future, override this if the user pays for expediated processing
                if recommend_min_gas_price_to_confirm_in_time(
                        1) > max_gas_price_we_are_willing_to_pay_gwei:
                    if coupon.token.contract.network == 'mainnet':
                        raise Exception(
                            "gas price is too high.  try again when its not pls"
                        )

                txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex()
            except Exception as e:
                txid = "pending_celery"
                retry_later = True

        if exit_after_sending_tx:
            return txid, None, None

        with transaction.atomic():
            kudos_transfer = KudosTransfer.objects.create(
                emails=[profile.email],
                # For kudos, `token` is a kudos.models.Token instance.
                kudos_token_cloned_from=coupon.token,
                amount=coupon.token.price_in_eth,
                comments_public=coupon.comments_to_put_in_kudos_transfer,
                ip=ip_address,
                github_url='',
                from_name=coupon.sender_profile.handle,
                from_email='',
                from_username=coupon.sender_profile.handle,
                username=profile.handle,
                network=coupon.token.contract.network,
                from_address=kudos_owner_address,
                is_for_bounty_fulfiller=False,
                metadata={
                    'coupon_redemption': True,
                    'nonce': nonce
                },
                recipient_profile=profile,
                sender_profile=coupon.sender_profile,
                txid=txid,
                receive_txid=txid,
                tx_status=tx_status,
                receive_tx_status=tx_status,
                receive_address=address,
            )

            # save to DB
            BulkTransferRedemption.objects.create(
                coupon=coupon,
                redeemed_by=profile,
                ip_address=ip_address,
                kudostransfer=kudos_transfer,
            )

            coupon.num_uses_remaining -= 1
            coupon.current_uses += 1
            coupon.save()

            # user actions
            record_user_action(kudos_transfer.username, 'new_kudos',
                               kudos_transfer)
            record_user_action(kudos_transfer.from_username, 'receive_kudos',
                               kudos_transfer)
            record_kudos_activity(kudos_transfer, kudos_transfer.username,
                                  'receive_kudos')

            # send email
            maybe_market_kudos_to_email(kudos_transfer)

            if retry_later:
                redeem_bulk_kudos.delay(kudos_transfer.id)

    return True, None, kudos_transfer
Esempio n. 10
0
def redeem_bulk_coupon(coupon, profile, address, ip_address, save_addr=False):
    try:
        address = Web3.toChecksumAddress(address)
    except:
        error = "You must enter a valid Ethereum address (so we know where to send your Kudos). Please try again."
        return None, error, None

    # handle form submission
    kudos_transfer = None
    if save_addr:
        profile.preferred_payout_address = address
        profile.save()

    private_key = settings.KUDOS_PRIVATE_KEY if not coupon.sender_pk else coupon.sender_pk
    kudos_owner_address = settings.KUDOS_OWNER_ACCOUNT if not coupon.sender_address else coupon.sender_address
    gas_price_confirmation_time = 1 if not coupon.sender_address else 60
    kudos_contract_address = Web3.toChecksumAddress(settings.KUDOS_CONTRACT_MAINNET)
    kudos_owner_address = Web3.toChecksumAddress(kudos_owner_address)
    w3 = get_web3(coupon.token.contract.network)
    contract = w3.eth.contract(Web3.toChecksumAddress(kudos_contract_address), abi=kudos_abi())
    nonce = w3.eth.getTransactionCount(kudos_owner_address)
    tx = contract.functions.clone(address, coupon.token.token_id, 1).buildTransaction({
        'nonce': nonce,
        'gas': 500000,
        'gasPrice': int(recommend_min_gas_price_to_confirm_in_time(gas_price_confirmation_time) * 10**9),
        'value': int(coupon.token.price_finney / 1000.0 * 10**18),
    })

    if not profile.trust_profile and profile.github_created_on > (timezone.now() - timezone.timedelta(days=7)):
        error = f'Your github profile is too new.  Cannot receive kudos.'
        return None, error, None
    else:

        signed = w3.eth.account.signTransaction(tx, private_key)
        retry_later = False
        try:
            txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex()
        except Exception as e:
            txid = "pending_celery"
            retry_later = True

        with transaction.atomic():
            kudos_transfer = KudosTransfer.objects.create(
                emails=[profile.email],
                # For kudos, `token` is a kudos.models.Token instance.
                kudos_token_cloned_from=coupon.token,
                amount=coupon.token.price_in_eth,
                comments_public=coupon.comments_to_put_in_kudos_transfer,
                ip=ip_address,
                github_url='',
                from_name=coupon.sender_profile.handle,
                from_email='',
                from_username=coupon.sender_profile.handle,
                username=profile.handle,
                network=coupon.token.contract.network,
                from_address=kudos_owner_address,
                is_for_bounty_fulfiller=False,
                metadata={'coupon_redemption': True, 'nonce': nonce},
                recipient_profile=profile,
                sender_profile=coupon.sender_profile,
                txid=txid,
                receive_txid=txid,
                tx_status='pending',
                receive_tx_status='pending',
            )

            # save to DB
            BulkTransferRedemption.objects.create(
                coupon=coupon,
                redeemed_by=profile,
                ip_address=ip_address,
                kudostransfer=kudos_transfer,
                )

            coupon.num_uses_remaining -= 1
            coupon.current_uses += 1
            coupon.save()

            # user actions
            record_user_action(kudos_transfer.username, 'new_kudos', kudos_transfer)
            record_user_action(kudos_transfer.from_username, 'receive_kudos', kudos_transfer)

            # send email
            maybe_market_kudos_to_email(kudos_transfer)

            if retry_later:
                from kudos.tasks import redeem_bulk_kudos
                redeem_bulk_kudos.delay(kudos_transfer.id, signed.rawTransaction.hex())

    return True, None, kudos_transfer
Esempio n. 11
0
    def handle(self, *args, **options):

        network = 'mainnet' if not settings.DEBUG else 'rinkeby'
        actually_send = not settings.DEBUG
        usernames = options['usernames'].split(",")
        _amount = options['amount']
        DECIMALS = 18
        from_address = settings.TIP_PAYOUT_ADDRESS
        from_pk = settings.TIP_PAYOUT_PRIVATE_KEY
        from_username = options['from_name']
        DAI_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f' if network == 'mainnet' else '0x6a6e8b58dee0ca4b4ee147ad72d3ddd2ef1bf6f7'
        token_name = 'DAI'
        # https://gitcoin.co/_administrationperftools/jsonstore/1801078/change/
        sybil_attack_addresses = JSONStore.objects.get(
            key='sybil_attack_addresses').data

        # payout rankings (round must be finalized first)
        TOKEN_ADDRESS = DAI_ADDRESS

        from_profile = Profile.objects.filter(
            handle=from_username.lower()).first()

        if not from_profile:
            print('no from_profile found')
            return

        sent_addresses = []
        for username in usernames:

            # issue payment
            print(f"- issuing payout to {username}")

            profile = Profile.objects.filter(handle=username.lower()).first()

            if not profile:
                print('no profile found')
                continue

            if not profile.preferred_payout_address:
                print('no profile preferred_payout_address found')
                continue

            address = profile.preferred_payout_address

            w3 = get_web3(network)
            contract = w3.eth.contract(Web3.toChecksumAddress(TOKEN_ADDRESS),
                                       abi=abi)
            address = Web3.toChecksumAddress(address)

            amount = int(_amount * 10**DECIMALS)
            tx_id = '0x0'
            if actually_send:

                if address.lower() in sent_addresses:
                    print(
                        'address was already in the sent addresess; skipping due to anti-sybil protections'
                    )
                    continue

                if address.lower() in sybil_attack_addresses:
                    print('skipping due to anti-sybil protections')
                    continue

                sent_addresses.append(address.lower())

                tx = contract.functions.transfer(
                    address, amount
                ).buildTransaction({
                    'nonce':
                    w3.eth.getTransactionCount(from_address),
                    'gas':
                    60000,
                    '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()

                if not tx_id:
                    print("cannot pay, did not get a txid")
                    continue

                print("paid via", tx_id)

                # wait for tx to clear
                while not has_tx_mined(tx_id, network):
                    time.sleep(1)

            metadata = {
                'direct_address': profile.preferred_payout_address,
                'creation_time': timezone.now().strftime("%Y-%m-%dT%H:00:00"),
            }

            # create objects
            tip = Tip.objects.create(
                primary_email=profile.email,
                emails=[profile.email],
                tokenName='DAI',
                amount=amount / 10**DECIMALS,
                comments_priv=options['comments_priv'],
                comments_public=options['comments_public'],
                ip="0.0.0.0",
                expires_date=timezone.now() + timezone.timedelta(days=10),
                github_url='',
                from_name=from_username,
                from_email=from_profile.email,
                from_username=from_username,
                username=profile.handle,
                network=network,
                tokenAddress=TOKEN_ADDRESS,
                from_address=from_address,
                is_for_bounty_fulfiller=False,
                metadata=metadata,
                recipient_profile=profile,
                sender_profile=from_profile,
                tx_status='pending',
                txid=tx_id,
                receive_tx_status='pending',
                receive_txid=tx_id,
                receive_address=profile.preferred_payout_address,
                tx_time=timezone.now(),
                receive_tx_time=timezone.now(),
                received_on=timezone.now(),
            )
            tip.trigger_townsquare()
            maybe_market_tip_to_github(tip)
            maybe_market_tip_to_slack(tip, 'New tip')
            if tip.primary_email:
                maybe_market_tip_to_email(tip, [tip.primary_email])
            record_user_action(tip.from_username, 'send_tip', tip)
            record_tip_activity(tip, tip.from_username,
                                'new_tip' if tip.username else 'new_crowdfund',
                                False, tip.username)
            TipPayout.objects.create(
                txid=tx_id,
                profile=profile,
                tip=tip,
            )

            print("SLEEPING")
            time.sleep(WAIT_TIME_BETWEEN_PAYOUTS)
            print("DONE SLEEPING")
Esempio n. 12
0
def receive(request, key, txid, network):
    """Handle the receiving of a kudos (the POST).

    Returns:
        TemplateResponse: the UI with the kudos confirmed

    """
    these_kudos_emails = KudosTransfer.objects.filter(web3_type='v3',
                                                      txid=txid,
                                                      network=network)
    kudos_emails = these_kudos_emails.filter(
        metadata__reference_hash_for_receipient=key
    ) | these_kudos_emails.filter(metadata__reference_hash_for_funder=key)
    kudos_transfer = kudos_emails.first()
    is_authed = kudos_transfer.trust_url or request.user.username.replace(
        '@', '') in [
            kudos_transfer.username.replace('@', ''),
            kudos_transfer.from_username.replace('@', '')
        ]
    not_mined_yet = get_web3(kudos_transfer.network).eth.getBalance(
        Web3.toChecksumAddress(kudos_transfer.metadata['address'])) == 0

    if not request.user.is_authenticated or request.user.is_authenticated and not getattr(
            request.user, 'profile', None):
        login_redirect = redirect('/login/github?next=' +
                                  request.get_full_path())
        return login_redirect

    if kudos_transfer.receive_txid:
        messages.info(request, _('This kudos has been received'))
    elif not is_authed:
        messages.error(
            request,
            f'This kudos is for {kudos_transfer.username} but you are logged in as {request.user.username}.  Please logout and log back in as {kudos_transfer.username}.'
        )
    elif not_mined_yet and not request.GET.get('receive_txid'):
        messages.info(
            request,
            f'This tx {kudos_transfer.txid}, is still mining.  Please wait a moment before submitting the receive form.'
        )
    elif request.GET.get('receive_txid') and not kudos_transfer.receive_txid:
        params = request.GET

        # db mutations
        try:
            if params['save_addr']:
                profile = get_profile(kudos_transfer.username)
                if profile:
                    # TODO: Does this mean that the address the user enters in the receive form
                    # Will overwrite an already existing preferred_payout_address?  Should we
                    # ask the user to confirm this?
                    profile.preferred_payout_address = params[
                        'forwarding_address']
                    profile.save()
            kudos_transfer.receive_txid = params['receive_txid']
            kudos_transfer.receive_address = params['forwarding_address']
            kudos_transfer.received_on = timezone.now()
            kudos_transfer.save()
            record_user_action(kudos_transfer.from_username, 'receive_kudos',
                               kudos_transfer)
            record_kudos_email_activity(kudos_transfer,
                                        kudos_transfer.username,
                                        'receive_kudos')
            messages.success(request, _('This kudos has been received'))
        except Exception as e:
            messages.error(request, str(e))
            logger.exception(e)

    params = {
        'issueURL':
        request.GET.get('source'),
        'class':
        'receive',
        'title':
        _('Receive Kudos'),
        'gas_price':
        round(recommend_min_gas_price_to_confirm_in_time(120), 1),
        'kudos_transfer':
        kudos_transfer,
        'key':
        key,
        'is_authed':
        is_authed,
        'disable_inputs':
        kudos_transfer.receive_txid or not_mined_yet or not is_authed,
    }

    return TemplateResponse(request, 'transaction/receive.html', params)
Esempio n. 13
0
def receive_tip_v2(request, pk, txid, network):
    """Handle the receiving of a tip (the POST).

    Returns:
        TemplateResponse: The UI with the tip confirmed.

    """
    tip = Tip.objects.get(web3_type='v2',
                          metadata__priv_key=pk,
                          txid=txid,
                          network=network)

    if tip.receive_txid:
        messages.info(request, 'This tip has already been received')

    not_mined_yet = get_web3(tip.network).eth.getBalance(
        Web3.toChecksumAddress(tip.metadata['address'])) == 0
    if not_mined_yet:
        messages.info(
            request,
            f'This tx {tip.txid}, is still mining.  Please wait a moment before submitting the receive form.'
        )

    if request.POST and not tip.receive_txid:
        params = request.POST

        # db mutations
        try:
            address = params['forwarding_address']
            if not address or address == '0x0':
                raise Exception('bad forwarding address')

            # send tokens

            address = Web3.toChecksumAddress(address)
            w3 = get_web3(tip.network)
            is_erc20 = tip.tokenName.lower() != 'eth'
            amount = int(tip.amount_in_wei)
            gasPrice = recommend_min_gas_price_to_confirm_in_time(25) * 10**9
            from_address = Web3.toChecksumAddress(tip.metadata['address'])
            nonce = w3.eth.getTransactionCount(from_address)
            if is_erc20:
                # ERC20 contract receive
                balance = w3.eth.getBalance(from_address)
                contract = w3.eth.contract(Web3.toChecksumAddress(
                    tip.tokenAddress),
                                           abi=erc20_abi)
                gas = contract.functions.transfer(address, amount).estimateGas(
                    {'from': from_address}) + 1
                gasPrice = gasPrice if ((gas * gasPrice) < balance) else (
                    balance * 1.0 / gas)
                tx = contract.functions.transfer(address,
                                                 amount).buildTransaction({
                                                     'nonce':
                                                     nonce,
                                                     'gas':
                                                     w3.toHex(gas),
                                                     'gasPrice':
                                                     w3.toHex(int(gasPrice)),
                                                 })
            else:
                # ERC20 contract receive
                gas = 100000
                amount -= gas * int(gasPrice)
                tx = dict(
                    nonce=nonce,
                    gasPrice=w3.toHex(int(gasPrice)),
                    gas=w3.toHex(gas),
                    to=address,
                    value=w3.toHex(amount),
                    data=b'',
                )
            signed = w3.eth.account.signTransaction(tx,
                                                    tip.metadata['priv_key'])
            receive_txid = w3.eth.sendRawTransaction(
                signed.rawTransaction).hex()

            tip.receive_address = params['forwarding_address']
            tip.receive_txid = receive_txid
            tip.received_on = timezone.now()
            tip.save()
            record_user_action(tip.username, 'receive_tip', tip)
            record_tip_activity(tip, tip.username, 'receive_tip')
            messages.success(request, 'This tip has been received')
        except Exception as e:
            messages.error(request, str(e))
            logger.exception(e)

    params = {
        'issueURL':
        request.GET.get('source'),
        'class':
        'receive',
        'title':
        _('Receive Tip'),
        'gas_price':
        round(
            recommend_min_gas_price_to_confirm_in_time(
                confirm_time_minutes_target), 1),
        'tip':
        tip,
        'disable_inputs':
        tip.receive_txid or not_mined_yet,
    }

    return TemplateResponse(request, 'onepager/receive.html', params)