gratipay / inside.gratipay.com

Here lieth a pioneer in open source sustainability. RIP
https://gratipay.news/the-end-cbfba8f50981
57 stars 38 forks source link

Dispose of unclaimed balances #1205

Closed chadwhitacre closed 4 years ago

chadwhitacre commented 6 years ago

Reticketing from #1196.

chadwhitacre commented 6 years ago

http://www.patreasury.gov/unclaimed-property/

http://patreasury.gov/unclaimed-property/holder/

http://patreasury.gov/pdf/unclaimed-property/Voluntary-Disclosure-Agreement.pdf

chadwhitacre commented 6 years ago

http://www.unclaimedpropertyspecialists.com/contact

chadwhitacre commented 6 years ago

Greetings! I have been running a third-party payment processor for the past five years and we are now shutting down our service. We are sitting on approximately $100,000 of escrowed funds and are looking for advice on disposing of it.

chadwhitacre commented 6 years ago

Had a call with MarketSphere. They specialize in handling filings for unclaimed property but are not lawyers. The person I talked with was going to recommend some lawyers who could go over our terms and advise us on our liability.

From an unclaimed property point of view, it's unfortunate that don't have national identification info for everyone we're holding money for. At this point in a "clean environment" (i.e., w/ identification on file) we would send hard-copy paper letters to the last known address for everyone affected for three years before turning over the list of names/addresses and dollar amounts to the state of the last known address. For international or unknown people the property reverts to our state of incorporation, namely the Commonwealth of Pennsylvania. The fact that we don't have national identification information on file is a red flag, and could potentially lead to an "unclaimed property audit." Pennsylvania would be the most likely to be interested in conducting an audit, though the person I spoke with considered our exposure to be "minimal" and an audit to be "extremely unlikely." They went so far as to suggest, after I mentioned Readability (btw, archive: .org, .png), that donating the money in a well-documented fashion would be an option worth considering. (Again, not a lawyer.) However, donating the money would create liability for whomever we were donating it to: we'd have to be up-front with them about the source of the funds and make sure they were okay with it. I think both the letter and the spirit of the law suggest that we give the money to the Commonwealth of Pennsylvania.

So basically what we'll do is make a one-time filing with the Commonwealth. The general expectation is that companies who file, file year after year, so we need to make clear that we're closing up shop and this will be our one and only filing, relinquishing all of our liability, and that there won't be any future filings. We'll give them what we have: usernames, email addresses, social media accounts, dollar amounts, and transaction dates. We'll send the money via wire/ACH/check. We'll include a narrative describing the source of the funds and our attempts to notify owners and return the money. Even though the dormancy period is not up we can "force file" because we are going out of business.

Hopefully we can get this done in Q1 2018.

chadwhitacre commented 6 years ago

I've received from MarketSphere a list of law firms that specialize in unclaimed property.

chadwhitacre commented 6 years ago

Where we have an email address, we can try sending via PayPal even if not explicitly linked to PayPal.

gratipay-bak=# select count(*), sum(balance) volume, email_address is not null as have_email_address from participants where balance > 0 group by email_address is not null;
┌───────┬──────────┬────────────────────┐
│ count │  volume  │ have_email_address │
├───────┼──────────┼────────────────────┤
│  3162 │ 91861.94 │ f                  │
│   602 │ 12928.67 │ t                  │
└───────┴──────────┴────────────────────┘
(2 rows)

gratipay-bak=#
chadwhitacre commented 6 years ago

Looks like that's only about 10%. :-/

chadwhitacre commented 6 years ago

@JessWhit suggests that we should block this on https://github.com/gratipay/inside.gratipay.com/issues/1220.

chadwhitacre commented 5 years ago

This evening, I hand-delivered $420 in cash to someone who is friends with someone who had money escrowed with us. 💃

https://github.com/gratipay/inside.gratipay.com/issues/1219#issuecomment-442311277

chadwhitacre commented 5 years ago

I reimbursed myself the $420 via a cash withdrawal from New Alliance.

chadwhitacre commented 5 years ago

I note that the tax situation for recipients is as muddy as ever. We are the payment processor, not the employer/contracting company.

Is it better to push the money back upstream? 🤔

chadwhitacre commented 5 years ago

Because technically the money was income to people the moment they received it through Gittip/Gratipay, whether or not they reported it. Now it's just a pain. 😞

Would it be less inconvenient for the people who gave it originally to receive it back?

I am revisiting the idea of donating it to open source non-profits.

chadwhitacre commented 5 years ago

I sent money to one account under #1225 and emailed the other 12.

chadwhitacre commented 5 years ago

By quartile:

   n  cutoff
------------
3466   69.00
 217  227.00
  67  838.50
  13 4306.93
chadwhitacre commented 5 years ago
gratipay-bak=# \i charts.sql
ALTER TABLE
UPDATE 3467
UPDATE 217
UPDATE 67
UPDATE 13
ALTER TABLE
UPDATE 2112
┌──────┬──────────┐
│  n   │    s     │
├──────┼──────────┤
│   13 │ 24934.11 │
│   67 │ 27197.25 │
│  217 │ 26367.88 │
│ 3467 │ 26291.37 │
└──────┴──────────┘
(4 rows)

┌──────┬──────────┐
│  n   │    s     │
├──────┼──────────┤
│    7 │ 14153.18 │
│   42 │ 16848.07 │
│  125 │ 15790.67 │
│ 1938 │ 15280.23 │
└──────┴──────────┘
(4 rows)

gratipay-bak=#
alter table tmp add column bucket int default 0;
update tmp set bucket=0 where balance > 0 and balance <= 69;
update tmp set bucket=1 where balance > 69 and balance <= 227;
update tmp set bucket=2 where balance > 227 and balance <= 838.50;
update tmp set bucket=4 where balance > 838.50;

alter table tmp add column has_email bool default false;
update tmp
   set has_email=true
 where coalesce(address_1, address_2, address_3, address_4, address_5) is not null
      ;

select count(balance) n, sum(balance) s from tmp group by bucket order by bucket desc;
select count(balance) n, sum(balance) s from tmp where has_email group by bucket order by bucket desc;
#!/usr/bin/env python3
import csv
from collections import OrderedDict
from decimal import Decimal as D

payouts = csv.reader(open('payouts.csv'))
masspay = csv.writer(open('masspay.csv', 'w+'))
headers = next(payouts)
blacklist = set(open('blacklist.csv').read().splitlines())
TOTAL = total = settled = D('0.00')
amounts = []

for row in payouts:
    paid, balance = bool(int(row[0])), D(row[1])
    amounts.append(balance)
    TOTAL += balance
    if paid:
        settled += balance
        continue
    addresses = list(OrderedDict.fromkeys(row[4:]))
    for address in addresses:
        if not address or address in blacklist:
            continue
        masspay.writerow([address, balance, 'usd'])
        total += balance
        break

print(f'{settled} / {total} ({(settled / total * 100):.1f}%)')

# Print out quartiles
quartile = TOTAL / 4
current = quartile
print(TOTAL, quartile)
running = D('0.00')
amounts.sort()
j = 0

def log():
    print(f"{current:>9.02f} {running:>9.02f} {i-j:>4d} {amount:>7.02f}")

for i, amount in enumerate(amounts):
    if running >= current:
        log()
        current += quartile
        j = i
    running += amount
log()
chadwhitacre commented 5 years ago

Based on https://github.com/gratipay/inside.gratipay.com/issues/1205#issuecomment-446011658 I think we should manually reach out (#1225) to the top two quartiles. Sending another 67 emails in order to clear another 25% of the escrow is a good trade-off. From there we can move back to #1219 for the bottom half.

chadwhitacre commented 5 years ago

It seems like I should spin Gratipay.com back up locally and track these exchanges so we have a clear record.

chadwhitacre commented 5 years ago
gratipay-bak=# select done, sum(balance) from tmp group by done;
┌──────┬──────────┐
│ done │   sum    │
├──────┼──────────┤
│ f    │ 45282.42 │
│ t    │ 59508.19 │
└──────┴──────────┘
(2 rows)
chadwhitacre commented 5 years ago

Alright! MassPay Number 1 is done! Well, started. It looks like we successfully sent $31k+ (30%) right off the bat, with another $11k (10%) still potentially to be claimed.

We're now down to 1700 that aren't done and have no email. Here's the breakdown:

gratipay-bak=# select bucket, count(balance), sum(balance) from tmp where not done and n = 0 group by bucket order by bucket;
┌────────┬───────┬──────────┐
│ bucket │ count │   sum    │
├────────┼───────┼──────────┤
│      1 │  1580 │ 11385.23 │
│      2 │    95 │ 10961.71 │
│      3 │    25 │  9732.61 │
└────────┴───────┴──────────┘
(3 rows)

The buckets are:

  1. 0 — 69
  2. 69 — 227
  3. 227 — 834

I think I'll take a pass through buckets 2 and 3 and clear low-hanging fruit.

chadwhitacre commented 5 years ago

Note that the "done" amount of $59k includes $9k in pending payouts to the five top-13 folks that are actually still pending (#1225) though I've made initial contact with four and have a plan for the fifth.

chadwhitacre commented 5 years ago

The no email numbers are a little fudgy, another way I counted them I got 1650. ¯\_(ツ)_/¯

category amount ($) % estimate $
total 104,790.61
done done! 50,357.64 48.1
remaining 54,432.97 51.9
pending on #1225 9,150.55 8.7 1.0 9,150.55
pending on #1219 12,302.29 11.7 0.5 6,151.15
denied on #1219 2,318.57 2.2 0.0 0
no email 30,661.22 29.3 0.1 3,066.12
remaining maybe? 18,367.82
total maybe? 65.6 68,725.46
chadwhitacre commented 5 years ago

another way

https://github.com/gratipay/logs/commit/c69e005691a5c741590d75e81586d2aff667c947

chadwhitacre commented 5 years ago

^^^ Table updated with some estimates of what we'll be able to flush. Target: 2/3! 👍

chadwhitacre commented 5 years ago

I think I can surpass $3,066.12 for no email (state=4):

gratipay-bak=# select count(balance), sum(balance) from tmp where state=4 and balance >= 100;
┌───────┬──────────┐
│ count │   sum    │
├───────┼──────────┤
│    75 │ 16225.47 │
└───────┴──────────┘
(1 row)

gratipay-bak=# 

Excelsior!

chadwhitacre commented 5 years ago

Per the above table there would be $36,065.15 remaining.

2/3 gone would be $34,930.20 left.

Anything under $40,000 and especially if we could get under $30,000(!) I would start to feel pretty good about donating the rest to selected charities.

chadwhitacre commented 5 years ago

lol that's one way

screen shot 2018-12-17 at 6 52 46 am

chadwhitacre commented 5 years ago

lol owed Hank Green dollars:

screen shot 2018-12-17 at 10 50 31 am

chadwhitacre commented 5 years ago

double lol

screen shot 2018-12-17 at 10 52 38 am

chadwhitacre commented 5 years ago

I requested another PayPal Debit Card so I can pay out some accounts where there's a donation option on their website but they don't support PayPal.

screen shot 2018-12-17 at 11 02 07 am

chadwhitacre commented 5 years ago

tfw you manually trigger GitHub's rate-limiting 😬

screen shot 2018-12-17 at 11 15 45 am

chadwhitacre commented 5 years ago

$20,000 has cleared New Alliance.

PayPal debit card is in the mail.

I am updating the script to process payments.

Then:

[folded into ticket description]

chadwhitacre commented 5 years ago

Email harvesting script moved to a Gist:

https://gist.github.com/chadwhitacre/d4cb21261e41a2da1dc3bc7f86e6879c

chadwhitacre commented 5 years ago

Scripts updated in https://github.com/gratipay/logs/commit/c8d654b7157aed9194beb982d07ad2c05535c0b4.

$ ./tick.py 
               n                $
           ------------- ------------------
    ready     96 ( 2.6%)  15,280.99 (14.6%)
  pending    512 (13.6%)  14,473.53 (13.8%)
 complete  1,538 (40.9%)  61,690.20 (58.9%)
   failed  1,618 (43.0%)  13,345.89 (12.7%)
    total  3,764         104,790.61

  masspay     96 ( 2.6%)
   target                 15,280.99
remainder               -      0.00
                         ----------
   actual                 15,280.99 (14.6%)
      fee               -     91.28
                         ----------
      net                 15,189.71
$
chadwhitacre commented 5 years ago

Okay! Gonna take five, and then see about issuing this next masspay ...

chadwhitacre commented 5 years ago

Current balances:

Account Amount ($)
New Alliance 19,684.45
PayPal 3,243.00
total 22,927.45

The PayPal balance doesn't include pending money, so that's going to spring back significantly.

chadwhitacre commented 5 years ago

https://github.com/gratipay/logs/commit/7ed351d3c8e3edaa005104a1774b9d927c192b23

$ ./tick.py 
               n                $
           ------------- ------------------
    ready      0 ( 0.0%)       0.00 ( 0.0%)
  pending    475 (12.6%)  14,617.08 (13.9%)
 complete  1,663 (44.2%)  76,175.55 (72.7%)
   failed  1,626 (43.2%)  13,997.98 (13.4%)
    total  3,764         104,790.61

  masspay      0 ( 0.0%)
   target                      0.00
remainder               -      0.00
                         ----------
   actual                      0.00 ( 0.0%)
      fee               -      0.00
                         ----------
      net                      0.00
$
chadwhitacre commented 5 years ago

Damn. This feels like we are succeeding here!

Emails deduped in payouts.csv in https://github.com/gratipay/logs/commit/9ae34407f88f8d52bfd9413278cfa3f8dd14c355.

#!/usr/bin/env python
import csv
import lib

payouts_header, payouts = lib.load_payouts()
for row in payouts:
    addresses = lib.get_addresses(row)
    addresses += ([''] * (4-len(addresses)))
    row[5:] = addresses

csv.writer(open('payouts.csv', 'w+')).writerows([payouts_header] + payouts)

None of the current failures have a second email address. So they are failed indeed.

$ grep ',unaddressable,failed.*@.*@' payouts.csv
$

... or are they!?

I've gone through five failed payouts > $100 (not including ones where I couldn't find an email address the other day), one I was able to pay out via PayPal based on an updated email address from GitHub, the other four I emailed to ask for options. One of them is @techtonik! 👋 😍

Forty of the pending masspays have a second email address, so I guess that's an upper limit on the third MassPay we're expecting to do in ~30 days when the results are in from the first two. With those kind of numbers I don't anticipate a fourth.

$ grep 'masspay,pending.*@.*@' payouts.csv | wc -l
      40
$
chadwhitacre commented 5 years ago

Got the debit card!

Five people to pay ...

chadwhitacre commented 5 years ago

First wanted Cash.me. Won't take the new debit card because "blah blah issuing bank charges additional fees" 😖. Tried my own card "that looks like a credit card" tried my own other card. Worked! PayPaling myself the reimbursement ...

chadwhitacre commented 5 years ago

The rest of the debit card folks were straightforward. 👍

https://github.com/gratipay/logs/commit/0458e7288a60dc10ce4830193f019c385cc9c2e7

$ ./tick.py 
               n                $
           ------------- ------------------
    ready      0 ( 0.0%)       0.00 ( 0.0%)
  pending    473 (12.6%)  14,969.60 (14.3%)
 complete  1,670 (44.4%)  77,566.64 (74.0%)
   failed  1,621 (43.1%)  12,254.37 (11.7%)
    total  3,764         104,790.61

  masspay      0 ( 0.0%)
   target                      0.00
remainder               -      0.00
                         ----------
   actual                      0.00 ( 0.0%)
      fee               -      0.00
                         ----------
      net                      0.00
$
chadwhitacre commented 5 years ago

Yeah, this is going great. We've got ~$1,600 in flight on TransferWise that is all but certain to clear on Monday, plus five Patreon payouts that are supposed to clear on Jan 1. Those alone will put us over 3/4 complete at $79,867.06 (76.2%). 👍

Waddya think? Can we make 80%? 💃

chadwhitacre commented 5 years ago

Can we semi-automate harvesting GitHub emails for the 1500+ people that are failed unaddressable?

chadwhitacre commented 5 years ago

Because I'm pretty sure we were just looking at emails explicitly published on a GitHub account, vs. emails on commit logs.

chadwhitacre commented 5 years ago

That sounds like a new ticket: https://github.com/gratipay/inside.gratipay.com/issues/1226.

chadwhitacre commented 5 years ago

Gosh. What if we could clear 90%? I think we might be able to get there with #1226, though that will take a lot of manual review. It would really be worth it, though. If we have less than $10,000 left unsendable then we could really declare victory! And then just donate the rest.

I went back and revisited the Readability case. They donated 90% of all of the money they collected, which came to about $150,000. We collected $1,003,648.55 over the lifetime of Gratipay:

gratipay-bak=# select sum(amount) from exchanges where amount > 0 and status = 'succeeded';
┌────────────┐
│    sum     │
├────────────┤
│ 1003648.55 │
└────────────┘
(1 row)

gratipay-bak=#

So to only have $104,790.61 left to dispose of is already only 10.4% of our total volume—the inverse of Readability's situation. And as of today we've cleared $78,266.88 of that, leaving only $26,523.73, which is only 2.6% of our total volume ever processed. In other words, we're already in a very different situation than Readability, and I think we can feel good about where we stand today even if we make no further progress. Stretch goal: < 1% remaining! That'd be < $10,036.48. Can we get there?!?!? 😮

chadwhitacre commented 5 years ago

75% 💃

https://github.com/gratipay/logs/commit/05795f25caa75c3c28e9881250d031194bc47c54

$ ./tick.py 
                 n                $
             ------------- ------------------
      ready      0 ( 0.0%)       0.00 ( 0.0%)
    pending    471 (12.5%)  13,890.95 (13.3%)
   complete  1,672 (44.4%)  78,645.29 (75.0%)
     failed  1,621 (43.1%)  12,254.37 (11.7%)
      total  3,764         104,790.61
 incomplete  2,092 (55.6%)  26,145.32 (25.0%)
$
chadwhitacre commented 5 years ago

75.3%

https://github.com/gratipay/logs/commit/c96285952cd6f5bcd7b0d00aa30f0d14b3086eec

$ ./tick.py 
                 n                $
             ------------- ------------------
      ready      0 ( 0.0%)       0.00 ( 0.0%)
    pending    469 (12.5%)  13,660.95 (13.0%)
   complete  1,674 (44.5%)  78,875.29 (75.3%)
     failed  1,621 (43.1%)  12,254.37 (11.7%)
      total  3,764         104,790.61
 incomplete  2,090 (55.5%)  25,915.32 (24.7%)
$
chadwhitacre commented 5 years ago

I updated the blog post to emphasize the $1,000,000 base:

screen shot 2018-12-24 at 2 52 40 pm

chadwhitacre commented 5 years ago

https://github.com/gratipay/logs/commit/a41024a92ec651e6b514a267f2dbce4d570d689c

$ ./tick.py 
                 n                $
             ------------- ------------------
      ready      0 ( 0.0%)       0.00 ( 0.0%)
    pending    469 (12.5%)  13,660.95 (13.0%)
   complete  1,674 (44.5%)  78,875.29 (75.3%)
     failed  1,621 (43.1%)  12,254.37 (11.7%)
      total  3,764         104,790.61
 incomplete  2,090 (55.5%)  25,915.32 (24.7%)

     volume              1,003,648.55
  disbursed                977,733.23 (97.4)%
$
chadwhitacre commented 5 years ago

When we started this would've been:

     volume              1,003,648.55
  disbursed                898,857.94 (89.6)%