Example #1
0
def address_webhook(request, secret_key, ignored_key):
    '''
    Process an inbound webhook from blockcypher
    '''

    # Log webhook
    webhook = WebHook.log_webhook(request,
                                  WebHook.BLOCKCYPHER_ADDRESS_NOTIFICATION)

    assert secret_key == WEBHOOK_SECRET_KEY
    assert request.method == 'POST', 'Request has no post'

    blockcypher_id = request.META.get('HTTP_X_EVENTID')
    assert 'tx-confirmation' == request.META.get('HTTP_X_EVENTTYPE')

    payload = json.loads(request.body.decode())

    address_subscription = AddressSubscription.objects.get(
        blockcypher_id=blockcypher_id)

    tx_hash = payload['hash']
    num_confs = payload['confirmations']
    double_spend = payload['double_spend']
    satoshis_sent = payload['total']
    fee_in_satoshis = payload['fees']

    tx_event = get_object_or_None(
        OnChainTransaction,
        tx_hash=tx_hash,
        address_subscription=address_subscription,
    )

    if tx_event:
        tx_event.num_confs = num_confs
        tx_event.double_spend = double_spend
        tx_event.save()
    else:
        tx_event = OnChainTransaction.objects.create(
            tx_hash=tx_hash,
            address_subscription=address_subscription,
            num_confs=num_confs,
            double_spend=double_spend,
            satoshis_sent=satoshis_sent,
            fee_in_satoshis=fee_in_satoshis,
        )

    tx_event.send_email_notification()

    # Update logging
    webhook.address_subscription = address_subscription
    webhook.succeeded = True
    webhook.save()

    # Return something
    return HttpResponse("*ok*")
Example #2
0
def address_webhook(request, secret_key, ignored_key):
    '''
    Process an inbound webhook from blockcypher
    '''

    # Log webhook
    webhook = WebHook.log_webhook(request, WebHook.BLOCKCYPHER_ADDRESS_NOTIFICATION)

    assert secret_key == WEBHOOK_SECRET_KEY
    assert request.method == 'POST', 'Request has no post'

    blockcypher_id = request.META.get('HTTP_X_EVENTID')
    assert 'tx-confirmation' == request.META.get('HTTP_X_EVENTTYPE')

    payload = json.loads(request.body.decode())

    address_subscription = AddressSubscription.objects.get(blockcypher_id=blockcypher_id)

    tx_hash = payload['hash']
    num_confs = payload['confirmations']
    double_spend = payload['double_spend']
    satoshis_sent = payload['total']
    fee_in_satoshis = payload['fees']

    tx_event = get_object_or_None(
            OnChainTransaction,
            tx_hash=tx_hash,
            address_subscription=address_subscription,
            )

    if tx_event:
        tx_event.num_confs = num_confs
        tx_event.double_spend = double_spend
        tx_event.save()
    else:
        tx_event = OnChainTransaction.objects.create(
                tx_hash=tx_hash,
                address_subscription=address_subscription,
                num_confs=num_confs,
                double_spend=double_spend,
                satoshis_sent=satoshis_sent,
                fee_in_satoshis=fee_in_satoshis,
                )

    tx_event.send_email_notification()

    # Update logging
    webhook.address_subscription = address_subscription
    webhook.succeeded = True
    webhook.save()

    # Return something
    return HttpResponse("*ok*")
Example #3
0
def process_bci_webhook(request, random_id):
    # Log webhook
    webhook = WebHook.log_webhook(request, WebHook.BCI_PAYMENT_FORWARDED)

    # parse webhook
    input_txn_hash = request.GET['input_transaction_hash']
    destination_txn_hash = request.GET['transaction_hash']
    satoshis = int(request.GET['value'])
    num_confirmations = int(request.GET['confirmations'])
    input_address = request.GET['input_address']
    destination_address = request.GET['destination_address']

    if input_address:
        forwarding_obj = get_object_or_None(ForwardingAddress,
                                            b58_address=input_address)
        if forwarding_obj:
            # Tie webhook to merchant. Optional.
            webhook.merchant = forwarding_obj.merchant
            webhook.save()

    # These defensive checks should always be true
    assert is_valid_btc_address(input_address), input_address
    assert is_valid_btc_address(destination_address), destination_address
    msg = '%s == %s' % (input_txn_hash, destination_txn_hash)
    assert input_txn_hash != destination_txn_hash, msg

    # process the transactions
    ForwardingAddress.handle_forwarding_txn(
        input_address=input_address,
        satoshis=satoshis,
        num_confirmations=num_confirmations,
        input_txn_hash=input_txn_hash,
    )
    ForwardingAddress.handle_destination_txn(
        forwarding_address=input_address,
        destination_address=destination_address,
        satoshis=satoshis,
        num_confirmations=num_confirmations,
        destination_txn_hash=destination_txn_hash,
    )

    if num_confirmations > 6:
        return HttpResponse("*ok*")
    else:
        return HttpResponse("Robot: please come back with more confirmations")
Example #4
0
def address_webhook(request, secret_key, ignored_key):
    '''
    Process an inbound webhook from blockcypher
    '''

    # Log webhook
    webhook = WebHook.log_webhook(request, WebHook.BLOCKCYPHER_ADDRESS_NOTIFICATION)

    assert secret_key == WEBHOOK_SECRET_KEY
    assert request.method == 'POST', 'Request has no post'

    blockcypher_id = request.META.get('HTTP_X_EVENTID')
    assert 'tx-confirmation' == request.META.get('HTTP_X_EVENTTYPE')

    payload = json.loads(request.body.decode())

    address_subscription = AddressSubscription.objects.get(blockcypher_id=blockcypher_id)

    tx_hash = payload['hash']
    num_confs = payload['confirmations']
    double_spend = payload['double_spend']
    satoshis_sent = payload['total']
    fee_in_satoshis = payload['fees']

    tx_event = get_object_or_None(
            OnChainTransaction,
            tx_hash=tx_hash,
            address_subscription=address_subscription,
            )

    if tx_event:
        tx_is_new = False
        tx_event.num_confs = num_confs
        tx_event.double_spend = double_spend
        tx_event.save()
    else:
        tx_is_new = True

        input_addresses = set()
        for input_entry in payload['inputs']:
            for address in input_entry.get('addresses', []):
                input_addresses.add(address)
        if address_subscription.b58_address in input_addresses:
            is_withdrawal = True
        else:
            is_withdrawal = False

        output_addresses = set()
        for output_entry in payload.get('outputs', []):
            for address in output_entry['addresses']:
                output_addresses.add(address)
        if address_subscription.b58_address in output_addresses:
            is_deposit = True
        else:
            is_deposit = False

        tx_event = OnChainTransaction.objects.create(
                tx_hash=tx_hash,
                address_subscription=address_subscription,
                num_confs=num_confs,
                double_spend=double_spend,
                satoshis_sent=satoshis_sent,
                fee_in_satoshis=fee_in_satoshis,
                is_deposit=is_deposit,
                is_withdrawal=is_withdrawal,
                )

    # email sending logic
    # TODO: add logic for notify on deposit vs withdrawal
    # TODO: add safety check to prevent duplicate email sending
    if tx_event.is_subscribed():
        if double_spend and (tx_is_new or not tx_event.double_spend):
            # We have the first reporting of a double-spend
            tx_event.send_double_spend_tx_notification()

        elif num_confs == 0 and tx_is_new:
            # First broadcast
            if tx_event.address_subscription.notify_on_broadcast:
                if tx_event.is_deposit and tx_event.address_subscription.notify_on_deposit:
                    tx_event.send_unconfirmed_tx_email()
                elif tx_event.is_withdrawal and tx_event.address_subscription.notify_on_withdrawal:
                    tx_event.send_unconfirmed_tx_email()

        elif num_confs == 6 and (tx_is_new or not tx_event.num_confs == num_confs):
            # Sixth confirm
            if tx_event.address_subscription.notify_on_sixth_confirm:
                if tx_event.is_deposit and tx_event.address_subscription.notify_on_deposit:
                    tx_event.send_confirmed_tx_email()
                elif tx_event.is_withdrawal and tx_event.address_subscription.notify_on_withdrawal:
                    tx_event.send_confirmed_tx_email()

    # Update logging
    webhook.address_subscription = address_subscription
    webhook.succeeded = True
    webhook.save()

    # Return something
    return HttpResponse("*ok*")
Example #5
0
def address_webhook(request, secret_key, ignored_key):
    '''
    Process an inbound webhook from blockcypher
    '''

    # Log webhook
    webhook = WebHook.log_webhook(request,
                                  WebHook.BLOCKCYPHER_ADDRESS_NOTIFICATION)

    assert secret_key == WEBHOOK_SECRET_KEY
    assert request.method == 'POST', 'Request has no post'

    blockcypher_id = request.META.get('HTTP_X_EVENTID')
    assert 'tx-confirmation' == request.META.get('HTTP_X_EVENTTYPE')

    payload = json.loads(request.body.decode())

    address_subscription = AddressSubscription.objects.get(
        blockcypher_id=blockcypher_id)

    tx_hash = payload['hash']
    num_confs = payload['confirmations']
    double_spend = payload['double_spend']
    satoshis_sent = payload['total']
    fee_in_satoshis = payload['fees']

    tx_event = get_object_or_None(
        OnChainTransaction,
        tx_hash=tx_hash,
        address_subscription=address_subscription,
    )

    if tx_event:
        tx_is_new = False
        tx_event.num_confs = num_confs
        tx_event.double_spend = double_spend
        tx_event.save()
    else:
        tx_is_new = True

        input_addresses = set()
        for input_entry in payload['inputs']:
            for address in input_entry.get('addresses', []):
                input_addresses.add(address)
        if address_subscription.b58_address in input_addresses:
            is_withdrawal = True
        else:
            is_withdrawal = False

        output_addresses = set()
        for output_entry in payload.get('outputs', []):
            for address in output_entry['addresses']:
                output_addresses.add(address)
        if address_subscription.b58_address in output_addresses:
            is_deposit = True
        else:
            is_deposit = False

        tx_event = OnChainTransaction.objects.create(
            tx_hash=tx_hash,
            address_subscription=address_subscription,
            num_confs=num_confs,
            double_spend=double_spend,
            satoshis_sent=satoshis_sent,
            fee_in_satoshis=fee_in_satoshis,
            is_deposit=is_deposit,
            is_withdrawal=is_withdrawal,
        )

    # email sending logic
    # TODO: add logic for notify on deposit vs withdrawal
    # TODO: add safety check to prevent duplicate email sending
    if tx_event.is_subscribed():
        if double_spend and (tx_is_new or not tx_event.double_spend):
            # We have the first reporting of a double-spend
            tx_event.send_double_spend_tx_notification()

        elif num_confs == 0 and tx_is_new:
            # First broadcast
            if tx_event.address_subscription.notify_on_broadcast:
                if tx_event.is_deposit and tx_event.address_subscription.notify_on_deposit:
                    tx_event.send_unconfirmed_tx_email()
                elif tx_event.is_withdrawal and tx_event.address_subscription.notify_on_withdrawal:
                    tx_event.send_unconfirmed_tx_email()

        elif num_confs == 6 and (tx_is_new
                                 or not tx_event.num_confs == num_confs):
            # Sixth confirm
            if tx_event.address_subscription.notify_on_sixth_confirm:
                if tx_event.is_deposit and tx_event.address_subscription.notify_on_deposit:
                    tx_event.send_confirmed_tx_email()
                elif tx_event.is_withdrawal and tx_event.address_subscription.notify_on_withdrawal:
                    tx_event.send_confirmed_tx_email()

    # Update logging
    webhook.address_subscription = address_subscription
    webhook.succeeded = True
    webhook.save()

    # Return something
    return HttpResponse("*ok*")
Example #6
0
def address_webhook(request, secret_key, ignored_key):
    '''
    Process an inbound webhook from blockcypher
    '''

    # Log webhook
    webhook = WebHook.log_webhook(request,
                                  WebHook.BLOCKCYPHER_ADDRESS_NOTIFICATION)

    assert secret_key == WEBHOOK_SECRET_KEY
    assert request.method == 'POST', 'Request has no post'

    blockcypher_id = request.META.get('HTTP_X_EVENTID')
    assert 'tx-confirmation' == request.META.get('HTTP_X_EVENTTYPE')

    payload = json.loads(request.body.decode())

    address_subscription = AddressSubscription.objects.get(
        blockcypher_id=blockcypher_id)

    tx_hash = payload['hash']
    num_confs = payload['confirmations']
    double_spend = payload['double_spend']
    satoshis_sent = payload['total']
    fee_in_satoshis = payload['fees']

    tx_event = get_object_or_None(
        OnChainTransaction,
        tx_hash=tx_hash,
        address_subscription=address_subscription,
    )

    if tx_event:
        tx_is_new = False
        tx_event.num_confs = num_confs
        tx_event.double_spend = double_spend
        tx_event.save()
    else:
        tx_is_new = True

        input_addresses = set()
        for input_entry in payload['inputs']:
            for address in input_entry.get('addresses', []):
                input_addresses.add(address)
        if address_subscription.b58_address in input_addresses:
            is_withdrawal = True
        else:
            is_withdrawal = False

        output_addresses = set()
        for output_entry in payload.get('outputs', []):
            for address in output_entry['addresses']:
                output_addresses.add(address)
        if address_subscription.b58_address in output_addresses:
            is_deposit = True
        else:
            is_deposit = False

        tx_event = OnChainTransaction.objects.create(
            tx_hash=tx_hash,
            address_subscription=address_subscription,
            num_confs=num_confs,
            double_spend=double_spend,
            satoshis_sent=satoshis_sent,
            fee_in_satoshis=fee_in_satoshis,
            is_deposit=is_deposit,
            is_withdrawal=is_withdrawal,
        )

    # email sending logic
    # TODO: add logic for notify on deposit vs withdrawal
    # TODO: add safety check to prevent duplicate email sending
    if tx_event.address_subscription.unsubscribed_at or tx_event.address_subscription.disabled_at:
        # unsubscribe from webhooks going forward
        try:
            unsub_result = unsubscribe_from_webhook(
                webhook_id=tx_event.address_subscription.blockcypher_id,
                api_key=BLOCKCYPHER_API_KEY,
                coin_symbol=tx_event.address_subscription.coin_symbol,
            )
            assert unsub_result is True, unsub_result
        except Exception:
            # there was a problem unsubscribing
            # notify using sentry but still return the webhook to blockcypher
            client.captureException()

    elif tx_event.address_subscription.auth_user.email_verified:
        # make sure we haven't contacted too many times (and unsub if so)

        earliest_dt = now() - timedelta(days=3)
        recent_emails_sent = SentEmail.objects.filter(
            address_subscription=tx_event.address_subscription,
            sent_at__gt=earliest_dt,
        ).count()

        if recent_emails_sent > 100:
            # too many emails, unsubscribe
            tx_event.address_subscription.admin_unsubscribe_subscription()
            client.captureMessage('TX Event %s unsubscribed' % tx_event.id)
            # TODO: notify user they've been unsubscribed

        else:
            # proceed with normal email sending

            if double_spend and (tx_is_new or not tx_event.double_spend):
                # We have the first reporting of a double-spend
                tx_event.send_double_spend_tx_notification()

            elif num_confs == 0 and tx_is_new:
                # First broadcast
                if tx_event.address_subscription.notify_on_broadcast:
                    if tx_event.is_deposit and tx_event.address_subscription.notify_on_deposit:
                        tx_event.send_unconfirmed_tx_email()
                    elif tx_event.is_withdrawal and tx_event.address_subscription.notify_on_withdrawal:
                        tx_event.send_unconfirmed_tx_email()

            elif num_confs == 6:
                # Sixth confirm
                if tx_event.address_subscription.notify_on_sixth_confirm:
                    if tx_event.is_deposit and tx_event.address_subscription.notify_on_deposit:
                        tx_event.send_confirmed_tx_email()
                    elif tx_event.is_withdrawal and tx_event.address_subscription.notify_on_withdrawal:
                        tx_event.send_confirmed_tx_email()
    else:
        # active subscription with unverfied email (can't contact)
        # TODO: add unsub if orig subscription is > X days old
        # eventually these could pile up
        pass

    # Update logging
    webhook.address_subscription = address_subscription
    webhook.succeeded = True
    webhook.save()

    # Return something
    return HttpResponse("*ok*")
Example #7
0
def address_webhook(request, secret_key, ignored_key):
    '''
    Process an inbound webhook from blockcypher
    '''

    # Log webhook
    webhook = WebHook.log_webhook(request, WebHook.BLOCKCYPHER_ADDRESS_NOTIFICATION)

    assert secret_key == WEBHOOK_SECRET_KEY
    assert request.method == 'POST', 'Request has no post'

    blockcypher_id = request.META.get('HTTP_X_EVENTID')
    assert 'tx-confirmation' == request.META.get('HTTP_X_EVENTTYPE')

    payload = json.loads(request.body.decode())

    address_subscription = AddressSubscription.objects.get(blockcypher_id=blockcypher_id)

    tx_hash = payload['hash']
    num_confs = payload['confirmations']
    double_spend = payload['double_spend']
    satoshis_sent = payload['total']
    fee_in_satoshis = payload['fees']

    tx_event = get_object_or_None(
            OnChainTransaction,
            tx_hash=tx_hash,
            address_subscription=address_subscription,
            )

    if tx_event:
        tx_is_new = False
        tx_event.num_confs = num_confs
        tx_event.double_spend = double_spend
        tx_event.save()
    else:
        tx_is_new = True

        input_addresses = set()
        for input_entry in payload['inputs']:
            for address in input_entry.get('addresses', []):
                input_addresses.add(address)
        if address_subscription.b58_address in input_addresses:
            is_withdrawal = True
        else:
            is_withdrawal = False

        output_addresses = set()
        for output_entry in payload.get('outputs', []):
            for address in output_entry['addresses']:
                output_addresses.add(address)
        if address_subscription.b58_address in output_addresses:
            is_deposit = True
        else:
            is_deposit = False

        tx_event = OnChainTransaction.objects.create(
                tx_hash=tx_hash,
                address_subscription=address_subscription,
                num_confs=num_confs,
                double_spend=double_spend,
                satoshis_sent=satoshis_sent,
                fee_in_satoshis=fee_in_satoshis,
                is_deposit=is_deposit,
                is_withdrawal=is_withdrawal,
                )

    # email sending logic
    # TODO: add logic for notify on deposit vs withdrawal
    # TODO: add safety check to prevent duplicate email sending
    if tx_event.address_subscription.unsubscribed_at or tx_event.address_subscription.disabled_at:
        # unsubscribe from webhooks going forward
        try:
            unsub_result = unsubscribe_from_webhook(
                    webhook_id=tx_event.address_subscription.blockcypher_id,
                    api_key=BLOCKCYPHER_API_KEY,
                    coin_symbol=tx_event.address_subscription.coin_symbol,
                    )
            assert unsub_result is True, unsub_result
        except Exception:
            # there was a problem unsubscribing
            # notify using sentry but still return the webhook to blockcypher
            client.captureException()

    elif tx_event.address_subscription.auth_user.email_verified:
        # make sure we haven't contacted too many times (and unsub if so)

        earliest_dt = now() - timedelta(days=3)
        recent_emails_sent = SentEmail.objects.filter(
                address_subscription=tx_event.address_subscription,
                sent_at__gt=earliest_dt,
                ).count()

        if recent_emails_sent > 100:
            # too many emails, unsubscribe
            tx_event.address_subscription.admin_unsubscribe_subscription()
            client.captureMessage(
                    'TX Event %s unsubscribed' % tx_event.id,
                    data={
                        'tx_event': tx_event.id,
                        'address_subscription': tx_event.address_subscription,
                        'recent_emails_sent': recent_emails_sent,
                        'webhook': webhook.id,
                        },
                    )
            # TODO: notify user they've been unsubscribed

        else:
            # proceed with normal email sending

            if double_spend and (tx_is_new or not tx_event.double_spend):
                # We have the first reporting of a double-spend
                tx_event.send_double_spend_tx_notification()

            elif num_confs == 0 and tx_is_new:
                # First broadcast
                if tx_event.address_subscription.notify_on_broadcast:
                    if tx_event.is_deposit and tx_event.address_subscription.notify_on_deposit:
                        tx_event.send_unconfirmed_tx_email()
                    elif tx_event.is_withdrawal and tx_event.address_subscription.notify_on_withdrawal:
                        tx_event.send_unconfirmed_tx_email()

            elif num_confs == 6:
                # Sixth confirm
                if tx_event.address_subscription.notify_on_sixth_confirm:
                    if tx_event.is_deposit and tx_event.address_subscription.notify_on_deposit:
                        tx_event.send_confirmed_tx_email()
                    elif tx_event.is_withdrawal and tx_event.address_subscription.notify_on_withdrawal:
                        tx_event.send_confirmed_tx_email()
    else:
        # active subscription with unverfied email (can't contact)
        # TODO: add unsub if orig subscription is > X days old
        # eventually these could pile up
        pass

    # Update logging
    webhook.address_subscription = address_subscription
    webhook.succeeded = True
    webhook.save()

    # Return something
    return HttpResponse("*ok*")