import locale import math from collections import defaultdict from decimal import Decimal from aspen import Response from gittip import db, CARDINALS ^L _suspicious = db.fetchall(""" SELECT username , balance , ctime FROM participants WHERE is_suspicious AND ctime < '2012-11-05'::timestamptz ORDER BY ctime """) if _suspicious is None: _suspicious = [] def suspicious(): for person in _suspicious: person['gives_to'] = db.fetchall(""" SELECT DISTINCT tippee AS username , is_suspicious , tips.ctime FROM tips JOIN participants p ON tippee = p.username WHERE tipper=%s AND tips.ctime < '2012-11-05'::timestamptz ORDER BY tips.ctime """, (person['username'],)) person['receives_from'] = db.fetchall(""" SELECT DISTINCT tipper AS username , is_suspicious , tips.ctime FROM tips JOIN participants p ON tipper = p.username WHERE tippee=%s AND tips.ctime < '2012-11-05'::timestamptz ORDER BY tips.ctime """, (person['username'],)) person['transfers'] = list(db.fetchall(""" SELECT tippee , tipper , amount , timestamp FROM transfers WHERE tipper=%s OR tippee=%s AND timestamp < '2012-11-05'::timestamptz ORDER BY timestamp """, (person['username'], person['username']))) person['exchanges'] = list(db.fetchall(""" SELECT amount, fee, timestamp FROM exchanges WHERE participant=%s AND timestamp < '2012-11-05'::timestamptz ORDER BY timestamp """, (person['username'],))) yield person suspicious = list(suspicious()) names = set([person['username'] for person in suspicious]) total_charged = 0 total_withdrawn = 0 gittip_fees = 0 balanced_fees = 0 total_escrowed = 0 total_legit = 0 total_fraudulent = 0 bystanders = defaultdict(lambda: [Decimal('0.00')]) earliest = None latest = None for person in suspicious: total_escrowed += person['balance'] for transfer in person['transfers']: if transfer['tippee'] not in names: total_legit += transfer['amount'] bystanders[transfer['tippee']][0] += transfer['amount'] for exchange in person['exchanges']: total_fraudulent += 1 amount, fee = exchange['amount'], exchange['fee'] if amount > 0: if earliest is None or earliest > exchange['timestamp']: earliest = exchange['timestamp'] if latest is None or latest < exchange['timestamp']: latest = exchange['timestamp'] amount_charged = exchange['amount'] + fee total_charged += amount_charged balanced_fee = (amount_charged * Decimal('0.029')) + Decimal('0.30') balanced_fee = Decimal(balanced_fee) else: total_withdrawn += abs(exchange['amount']) balanced_fee = Decimal('0.25') balanced_fees += balanced_fee gittip_fees += fee - balanced_fee assert total_legit == total_charged - total_withdrawn - gittip_fees - balanced_fees - total_escrowed nweeks = CARDINALS[((latest.date() - earliest.date()).days / 7) + 1] overall = db.fetchone(""" SELECT sum(amount + fee), count(amount) FROM exchanges WHERE amount > 0 AND timestamp > %s AND timestamp < '2012-11-01'::timestamptz """, (earliest.date(),)) overall_volume = overall['sum'] overall_transactions = overall['count'] percentage_stolen = (total_charged / overall_volume) * 100 percentage_fraudulent = (total_fraudulent / float(overall_transactions)) * 100 pad = lambda d, n: locale.format("%.2f", d, grouping=True).rjust(n).replace(' ', ' ') w = 9 total_charged = pad(total_charged, w) total_withdrawn = pad(total_withdrawn, w) gittip_fees = pad(gittip_fees, w) balanced_fees = pad(balanced_fees, w) total_escrowed = pad(total_escrowed, w) total_legit = pad(total_legit, w) overall_volume = pad(overall_volume, w) percentage_stolen = pad(percentage_stolen, w) overall_transactions = pad(overall_transactions, w)[:-3] + (' ' * 3) total_fraudulent = pad(total_fraudulent, w)[:-3] + (' ' * 3) percentage_fraudulent = pad(percentage_fraudulent, w) bystander_balances = db.fetchall(""" SELECT username, balance FROM participants WHERE username = ANY(%s) """, (list(bystanders),)) if bystander_balances is None: bystander_balances = [] for row in bystander_balances: bystanders[row['username']].append(row['balance']) bystanders = sorted(bystanders.items(), key=lambda i: i[1], reverse=True) fmtdate = lambda d: str(d)[:10] title = "The Delpan Incident" ^L {% extends templates/base.html %} {% block box %}
Gittip's first fraud incident surfaced when an unknown user named delpan appeared among the top receivers on the site. This page provides data and collects information related to the incident.
This incident is closed.
The fraudulent credit card transactions associated with this incident occured over a period of {{ nweeks }} weeks, from {{ earliest.strftime("%B %d") }} to {{ latest.strftime("%B %d, %Y") }}.
| Withdrawn to a Bank Account | ${{ total_withdrawn }} |
|---|---|
| Given to Innocent Bystanders | ${{ total_legit }} |
| Still Escrowed in Gittip | ${{ total_escrowed }} |
| Fees - Balanced | ${{ balanced_fees }} |
| Fees - Gittip | ${{ gittip_fees }} |
| Total Stolen | ${{ total_charged }} |
| Overall Volume during the incident | ${{ overall_volume }} |
| Percentage Stolen | {{ percentage_stolen }}% |
| Total Credit Card Transactions | {{ overall_transactions }} |
| Fraudulent Transactions | {{ total_fraudulent }} |
| Percentage Fraudulent | {{ percentage_fraudulent }}% |
These people inadvertently received stolen money as part of this incident.
| Received | {% if user.ADMIN %}Balance | {% end %}|
|---|---|---|
| {{ name }} | ${{ pad(amount, 9) }} | {% if user.ADMIN %}${{ pad(balance, 7) }} | {% end %}
| Total | ${{ total_legit }} | {% if user.ADMIN %}{% end %} |
Suspicious Accounts (N = {{ len(suspicious) }}) |
||||
| Balance | Tip Graph | Transfers | Exchanges & Fees Negative means bank deposit, positive means credit card charge. |
|
|---|---|---|---|---|
| {{ row['username'] }} {{ fmtdate(row['ctime']) }} |
{{ pad(row['balance'], 5) }} |
{% for person in row['gives_to'] %}
→{{ person['username'] }} {% end %} {% for person in row['receives_from'] %} ←{{ person['username'] }} {% end %} |
{% for transfer in row['transfers'] %}
{% if row['username'] == transfer['tipper'] %}
{{ pad(transfer['amount'], 5)}}→
{{ transfer['tippee'] }}
{% else %}
{{ pad(transfer['amount'], 5) }}←
{{ transfer['tipper'] }}
{% end %}
{{ str(transfer['timestamp'])[:10] }}
{% end %} |
{% for exchange in row['exchanges'] %}
{{ pad(exchange['amount'], 6) }}
{{ pad(exchange['fee'], 4) }}
{{ str(exchange['timestamp'])[:10] }}
{% end %} |