Skip to content

Commit

Permalink
send bulk txn script, for paying out a bounty that im too lazy to sig…
Browse files Browse the repository at this point in the history
…n a bunch of MM txns for
  • Loading branch information
owocki committed May 2, 2020
1 parent c0fe310 commit 6531400
Show file tree
Hide file tree
Showing 2 changed files with 195 additions and 0 deletions.
3 changes: 3 additions & 0 deletions app/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -823,5 +823,8 @@ def callback(request):
GRANTS_COUPON_50_OFF = env('GRANTS_COUPON_50_OFF', default='OWOCKIFOREVER')
GRANTS_COUPON_100_OFF = env('GRANTS_COUPON_100_OFF', default='OWOCKIFOREVER')

TIP_PAYOUT_ADDRESS = env('TIP_PAYOUT_ADDRESS', default='0x00De4B13153673BCAE2616b67bf822500d325Fc3')
TIP_PAYOUT_PRIVATE_KEY = env('TIP_PAYOUT_PRIVATE_KEY', default='0x00De4B13153673BCAE2616b67bf822500d325Fc3')


ELASTIC_SEARCH_URL = env('ELASTIC_SEARCH_URL', default='')
192 changes: 192 additions & 0 deletions app/dashboard/management/commands/send_bulk_tips.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
'''
Copyright (C) 2020 Gitcoin Core
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
'''

import json
import time

from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.core import management
from django.core.management.base import BaseCommand
from django.utils import timezone
from dashboard.views import record_user_action

from dashboard.abi import erc20_abi as abi
from dashboard.models import Activity, Earning, Profile, Tip, TipPayout
from dashboard.utils import get_tx_status, get_web3, has_tx_mined
from gas.utils import recommend_min_gas_price_to_confirm_in_time
from marketing.mails import (
grant_match_distribution_final_txn, grant_match_distribution_kyc, grant_match_distribution_test_txn,
)
from townsquare.models import Comment
from web3 import HTTPProvider, Web3
from dashboard.notifications import maybe_market_tip_to_email, maybe_market_tip_to_github, maybe_market_tip_to_slack
from dashboard.tip_views import record_tip_activity

WAIT_TIME_BETWEEN_PAYOUTS = 15

class Command(BaseCommand):

help = 'finalizes + sends grants round payouts'

def add_arguments(self, parser):
parser.add_argument('from_name',
default='from_name',
type=str,
help="from_username, eg: owocki"
)
parser.add_argument('usernames',
default='usernames',
type=str,
help="list of usernames to pay, a la: user1,user2,user3"
)

parser.add_argument('amount',
default='amount',
type=float,
help="amount of DAI to send, a la: 0.001"
)

parser.add_argument('comments_priv',
default='comments_priv',
type=str,
help="private comments"
)

parser.add_argument('comments_public',
default='comments_public',
type=str,
help="public comments"
)


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'

# 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

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:
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,
)
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")

4 comments on commit 6531400

@sifaw23
Copy link

@sifaw23 sifaw23 commented on 6531400 May 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i just added my ether address i still will get a tip ?
Thank you

@molecula451
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

living legend, honestly

@oussema
Copy link

@oussema oussema commented on 6531400 May 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice ! how to join ?

@owocki
Copy link
Contributor Author

@owocki owocki commented on 6531400 May 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sifaw23 sure just comment on the video bounty thread to remind
me

@oussema do something tip worthy :)

Please sign in to comment.