Пример #1
0
def process_subscription(subscription, live):
    is_ready_to_be_processed_db = subscription.get_is_ready_to_be_processed_from_db()

    logger.info("  - subscription %d", subscription.pk)
    if is_ready_to_be_processed_db:
        logger.info("   -- (ready via db) ")
        are_we_past_next_valid_timestamp = subscription.get_are_we_past_next_valid_timestamp()

        # FOR DEBUGGING
        if not live:
            is_ready_to_be_processed_web3 = subscription.get_is_subscription_ready_from_web3()
            is_active_web3 = subscription.get_is_active_from_web3()
            signer = subscription.get_subscription_signer_from_web3()
            logger.info("    ---  DEBUG INFO")
            logger.info(
                "    --- %s, %s, %s, %s", are_we_past_next_valid_timestamp, is_ready_to_be_processed_web3,
                is_active_web3, signer,
            )

        if not are_we_past_next_valid_timestamp:
            logger.info(f"   -- ( NOT ready via web3, will be ready on {subscription.get_next_valid_timestamp()}) ")
        else:
            logger.info("   -- (ready via web3) ")
            status = 'failure'
            txid = None
            error = ""
            try:
                if live:
                    logger.info("   -- *executing* ")
                    while not has_tx_mined(subscription.new_approve_tx_id, subscription.grant.network):
                        time.sleep(SLEEP_TIME)
                        logger.info(f"   -- *waiting {SLEEP_TIME} seconds*")
                    txid = subscription.do_execute_subscription_via_web3()
                    logger.info("   -- *waiting for mine* (txid %s) ", txid)
                    while not has_tx_mined(txid, subscription.grant.network):
                        time.sleep(SLEEP_TIME)
                        logger.info(f"   -- *waiting {SLEEP_TIME} seconds*")
                    status, __ = get_tx_status(txid, subscription.grant.network, timezone.now())
                    if status != 'success':
                        error = f"tx status from RPC is {status} not success, txid: {txid}"
                else:
                    logger.info("   -- *not live, not executing* ")
            except Exception as e:
                error = str(e)
                logger.info("   -- *not live, not executing* ")

            logger.info("   -- *mined* (status: %s / error: %s) ", status, error)
            was_success = status == 'success'
            if live:
                if not was_success:
                    logger.warning('subscription processing failed')
                    subscription.error = True
                    error_comments = f"{error}\n\ndebug info: {subscription.get_debug_info()}"
                    subscription.subminer_comments = error_comments
                    subscription.save()
                    warn_subscription_failed(subscription)
                else:
                    logger.info('subscription processing successful')
                    subscription.successful_contribution(txid)
                    subscription.save()
Пример #2
0
    def handle(self, *args, **options):
        network = 'mainnet'
        if int(recommend_min_gas_price_to_confirm_in_time(1)) > 10:
            return
        kts = KudosTransfer.objects.not_submitted().filter(network='mainnet')
        for kt in kts:
            redemption = kt.bulk_transfer_redemptions.first()
            address = kt.receive_address
            profile = kt.recipient_profile
            coupon = redemption.coupon
            ip_address = redemption.ip_address
            tx_id, _, _ = redeem_bulk_coupon(coupon,
                                             profile,
                                             address,
                                             ip_address,
                                             exit_after_sending_tx=True)
            print(tx_id)
            while not has_tx_mined(tx_id, network):
                time.sleep(1)

            kt.txid = txid
            kt.receive_txid = txid
            kt.receive_tx_status = 'success'
            kt.tx_status = 'success'
            kt.received_on = timezone.now()
            kt.tx_time = timezone.now()
            kt.save()
Пример #3
0
def mint_token_request(self, token_req_id, retry=False):
    """
    :param self:
    :param token_req_id:
    :return:
    """
    with redis.lock("tasks:all_kudos_requests", timeout=LOCK_TIMEOUT):
        with redis.lock("tasks:token_req_id:%s" % token_req_id,
                        timeout=LOCK_TIMEOUT):
            from kudos.management.commands.mint_all_kudos import sync_latest
            from gas.utils import recommend_min_gas_price_to_confirm_in_time
            from dashboard.utils import has_tx_mined
            obj = TokenRequest.objects.get(pk=token_req_id)
            multiplier = 1
            gas_price = int(
                float(recommend_min_gas_price_to_confirm_in_time(1)) *
                multiplier)
            if gas_price > delay_if_gas_prices_gt_mint and self.request.retries < self.max_retries:
                self.retry(countdown=120)
                return
            tx_id = obj.mint(gas_price)
            if tx_id:
                while not has_tx_mined(tx_id, obj.network):
                    time.sleep(1)
                sync_latest(0)
                sync_latest(1)
                sync_latest(2)
                sync_latest(3)
                notify_kudos_minted(obj)
            else:
                self.retry(countdown=(30 * (self.request.retries + 1)))
Пример #4
0
def sync_web3(request):
    """ Sync up web3 with the database.  This function has a few different uses.  It is typically
        called from the front end using the javascript `sync_web3` function.  The `issueURL` is
        passed in first, followed optionally by a `bountydetails` argument.
    """
    # setup
    result = {
        'status': '400',
        'msg': "bad request"
    }

    issue_url = request.POST.get('url')
    txid = request.POST.get('txid')
    network = request.POST.get('network')

    if issue_url and txid and network:
        # confirm txid has mined
        print('* confirming tx has mined')
        if not has_tx_mined(txid, network):
            result = {
                'status': '400',
                'msg': 'tx has not mined yet'
            }
        else:

            # get bounty id
            print('* getting bounty id')
            bounty_id = get_bounty_id(issue_url, network)
            if not bounty_id:
                result = {
                    'status': '400',
                    'msg': 'could not find bounty id'
                }
            else:
                # get/process bounty
                print('* getting bounty')
                bounty = get_bounty(bounty_id, network)
                print('* processing bounty')
                did_change = False
                max_tries_attempted = False
                counter = 0
                url = None
                while not did_change and not max_tries_attempted:
                    did_change, _, new_bounty = web3_process_bounty(bounty)
                    if not did_change:
                        print("RETRYING")
                        time.sleep(3)
                        counter += 1
                        max_tries_attempted = counter > 3
                    if new_bounty:
                        url = new_bounty.url
                result = {
                    'status': '200',
                    'msg': "success",
                    'did_change': did_change,
                    'url': url,
                }

    return JsonResponse(result, status=result['status'])
Пример #5
0
def sync_web3(request):
    """ Sync up web3 with the database.  This function has a few different uses.  It is typically
        called from the front end using the javascript `sync_web3` function.  The `issueURL` is
        passed in first, followed optionally by a `bountydetails` argument.
    """
    # setup
    result = {
        'status': '400',
        'msg': "bad request"
    }

    issueURL = request.POST.get('url')
    txid = request.POST.get('txid')
    network = request.POST.get('network')

    if issueURL and txid and network:
        # confirm txid has mined
        print('* confirming tx has mined')
        if not has_tx_mined(txid, network):
            result = {
                'status': '400',
                'msg': 'tx has not mined yet'
            }
        else:

            # get bounty id
            print('* getting bounty id')
            bounty_id = getBountyID(issueURL, network)
            if not bounty_id:
                result = {
                    'status': '400',
                    'msg': 'could not find bounty id'
                }
            else:
                # get/process bounty
                print('* getting bounty')
                bounty = get_bounty(bounty_id, network)
                print('* processing bounty')
                did_change, _, _ = web3_process_bounty(bounty)
                result = {
                    'status': '200',
                    'msg': "success",
                    'did_change': did_change
                }

    return JsonResponse(result, status=result['status'])
Пример #6
0
def redeem_bulk_kudos(self, kt_id, signed_rawTransaction, retry=False):
    """
    :param self:
    :param kt_id:
    :param signed_rawTransaction:
    :return:
    """
    with redis.lock("tasks:all_redeem_bulk_kudos", timeout=LOCK_TIMEOUT):
        with redis.lock("tasks:redeem_bulk_kudos:%s" % kt_id, timeout=LOCK_TIMEOUT):
            from dashboard.utils import has_tx_mined
            try:
                obj = KudosTransfer.objects.get(pk=kt_id)
                w3 = get_web3(obj.network)
                obj.txid = w3.eth.sendRawTransaction(HexBytes(signed_rawTransaction)).hex()
                obj.receive_txid = obj.txid
                obj.save()
                while not has_tx_mined(obj.txid, obj.network):
                    time.sleep(1)
                pass
            except Exception as e:
                self.retry(30)
Пример #7
0
def mint_token_request(self, token_req_id, retry=False):
    """
    :param self:
    :param token_req_id:
    :return:
    """
    with redis.lock("tasks:token_req_id:%s" % token_req_id,
                    timeout=LOCK_TIMEOUT):
        from kudos.management.commands.mint_all_kudos import sync_latest
        from dashboard.utils import has_tx_mined
        obj = TokenRequest.objects.get(pk=token_req_id)
        tx_id = obj.mint()
        if tx_id:
            while not has_tx_mined(tx_id, obj.network):
                time.sleep(1)
            sync_latest(0)
            sync_latest(1)
            sync_latest(2)
            sync_latest(3)
        else:
            self.retry(30)
Пример #8
0
def mint_token_request(self, token_req_id, retry=False):
    """
    :param self:
    :param token_req_id:
    :return:
    """
    with redis.lock("tasks:all_token_mint_requests", timeout=LOCK_TIMEOUT):
        with redis.lock("tasks:token_req_id:%s" % token_req_id, timeout=LOCK_TIMEOUT):
            from kudos.management.commands.mint_all_kudos import sync_latest
            from gas.utils import recommend_min_gas_price_to_confirm_in_time
            from dashboard.utils import has_tx_mined
            obj = TokenRequest.objects.get(pk=token_req_id)
            multiplier = 1 if not retry else (mint_token_request.request.retries + 1)
            gas_price = int(recommend_min_gas_price_to_confirm_in_time(1) * multiplier)
            tx_id = obj.mint(gas_price)
            if tx_id:
                while not has_tx_mined(tx_id, obj.network):
                    time.sleep(1)
                sync_latest(0)
                sync_latest(1)
                sync_latest(2)
                sync_latest(3)
            else:
                self.retry(30)
Пример #9
0
def has_mined(txid, subscription):
    return has_tx_mined(txid, subscription.grant.network)
Пример #10
0
def redeem_bulk_kudos(self,
                      kt_id,
                      delay_if_gas_prices_gt_redeem=50,
                      override_gas_price=None,
                      send_notif_email=False,
                      override_lock_timeout=LOCK_TIMEOUT,
                      retry=False):
    """
    :param self:
    :param kt_id:
    :return:
    """
    try:
        if True:  # override for allowing many xdai minting; we can change this back later there is a race condition
            # but for now the lock was providing more trouble than good - KO 10/20/2020
            #with redis.lock("tasks:redeem_bulk_kudos:%s" % kt_id, timeout=override_lock_timeout):
            multiplier = 1
            # high gas prices, 5 hour gas limit - DL
            gas_price = int(
                float(recommend_min_gas_price_to_confirm_in_time(300)) *
                multiplier)
            if override_gas_price:
                gas_price = override_gas_price
            if gas_price > delay_if_gas_prices_gt_redeem:
                # do not retry is gas prices are too high
                # TODO: revisit this when gas prices go down
                # self.retry(countdown=60*10)
                return

            if override_gas_price:
                gas_price = override_gas_price * 10**9
            obj = KudosTransfer.objects.get(pk=kt_id)
            w3 = get_web3(obj.network)
            token = obj.kudos_token_cloned_from
            if token.owner_address.lower(
            ) != '0x6239FF1040E412491557a7a02b2CBcC5aE85dc8F'.lower():
                raise Exception(
                    "kudos isnt owned by Gitcoin; cowardly refusing to spend Gitcoin's ETH minting it"
                )
            kudos_owner_address = settings.KUDOS_OWNER_ACCOUNT
            kudos_owner_address = Web3.toChecksumAddress(kudos_owner_address)
            contract_addr = settings.KUDOS_CONTRACT_MAINNET
            if obj.network == 'xdai':
                contract_addr = settings.KUDOS_CONTRACT_XDAI
            if obj.network == 'rinkeby':
                contract_addr = settings.KUDOS_CONTRACT_RINKEBY
            kudos_contract_address = Web3.toChecksumAddress(contract_addr)
            contract = w3.eth.contract(
                Web3.toChecksumAddress(kudos_contract_address),
                abi=kudos_abi())
            nonce = w3.eth.getTransactionCount(kudos_owner_address)
            tx = contract.functions.clone(
                Web3.toChecksumAddress(obj.receive_address), token.token_id,
                1).buildTransaction({
                    'nonce':
                    nonce,
                    'gas':
                    500000,
                    'gasPrice':
                    gas_price,
                    'value':
                    int(token.price_finney / 1000.0 * 10**18),
                })
            private_key = settings.KUDOS_PRIVATE_KEY
            signed = w3.eth.account.signTransaction(tx, private_key)
            obj.txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex()
            obj.receive_txid = obj.txid
            obj.save()
            while not has_tx_mined(obj.txid, obj.network):
                time.sleep(1)
            pass
            if send_notif_email:
                from_email = '*****@*****.**'
                from_name = 'Kevin @ Gitcoin'
                _to_email = obj.recipient_profile.email
                subject = f"Your '{obj.kudos_token_cloned_from.name}' Kudos has been minted 🌈"
                block_url = f'https://etherscan.io/tx/{obj.txid}'
                if obj.network == 'xdai':
                    block_url = f'https://blockscout.com/poa/xdai/tx/{obj.txid}/internal-transactions'
                body = f'''
Hello @{obj.recipient_profile.handle},

Back on {obj.created_on} you minted a '{obj.kudos_token_cloned_from.name}' Kudos, but the Ethereum network's gas fees were too high for us to mint it on-chain.

We're writing with good news.  The gas prices on Ethereum have come down, and we are have now minted your token.  You can now see the Kudos in your gitcoin profile ( https://gitcoin.co/{obj.recipient_profile.handle} ) or any blockchain wallet that connects to the {obj.network} network ( {block_url} ).  HOORAY!

Party on,
Kevin + the Gitcoin team
                '''
                send_mail(from_email,
                          _to_email,
                          subject,
                          body,
                          from_name=from_name)
    except (SoftTimeLimitExceeded, TimeLimitExceeded):
        print('max timeout for bulk kudos redeem exceeded ... giving up!')
    except Exception as e:
        print(e)
        if self.request.retries < self.max_retries:
            self.retry(countdown=(30 * (self.request.retries + 1)))
        else:
            print("max retries for bulk kudos redeem exceeded ... giving up!")
Пример #11
0
def process_subscription(subscription, live):
    is_ready_to_be_processed_db = subscription.get_is_ready_to_be_processed_from_db()

    logger.info("  - subscription %d", subscription.pk)
    if is_ready_to_be_processed_db:
        logger.info("   -- (ready via db) ")
        are_we_past_next_valid_timestamp = subscription.get_are_we_past_next_valid_timestamp()
        has_approve_tx_mined = has_tx_mined(subscription.new_approve_tx_id, subscription.grant.network)

        # FOR DEBUGGING
        if not live:
            is_ready_to_be_processed_web3 = subscription.get_are_we_past_next_valid_timestamp()
            is_active_web3 = subscription.get_is_active_from_web3()
            signer = subscription.get_subscription_signer_from_web3()
            logger.info("    ---  DEBUG INFO")
            logger.info(
                "    --- %s, %s, %s, %s", are_we_past_next_valid_timestamp, is_ready_to_be_processed_web3,
                is_active_web3, signer,
            )

        if not are_we_past_next_valid_timestamp:
            logger.info(f"   -- ( NOT ready via web3, will be ready on {subscription.get_next_valid_timestamp()}) ")
        elif not has_approve_tx_mined:
            logger.info(f"   -- ( NOT ready via approve tx, will be ready when {subscription.new_approve_tx_id} mines) ")
        else:
            if subscription.contributor_signature == "onetime":
                subscription.error = True
                subscription.subminer_comments = "One time subscription"
                subscription.save()
                logger.info('skipping one time subscription: %s' % subscription.id)
                return
            web3_hash_arguments = subscription.get_subscription_hash_arguments()
            if web3_hash_arguments['periodSeconds'] < METATX_FREE_INTERVAL_SECONDS and web3_hash_arguments['gasPrice'] <= METATX_GAS_PRICE_THRESHOLD:
                subscription.error = True
                subscription.subminer_comments = "Gas price was too low to process"
                subscription.save()
                warn_subscription_failed(subscription)
                return

            logger.info("   -- (ready via web3) ")
            status = 'failure'
            txid = None
            error = ""
            try:
                if live:
                    logger.info("   -- *executing* ")

                    txid = subscription.do_execute_subscription_via_web3()
                    logger.info("   -- *waiting for mine* (txid %s) ", txid)

                    override = False
                    counter = 0
                    while not has_tx_mined(txid, subscription.grant.network) and not override:
                        time.sleep(SLEEP_TIME)
                        logger.info(f"   -- *waiting {SLEEP_TIME} seconds for {txid} to mine*")
                        counter += 1
                        if counter > MAX_COUNTER:
                            override = True
                            # force the subminer to continue on; this tx is taking too long.
                            # an admin will have to look at this later and determine what went wrong
                            # KO 2019/02/06

                    status, __ = get_tx_status(txid, subscription.grant.network, timezone.now())
                    if status != 'success':
                        error = f"tx status from RPC is {status} not success, txid: {txid}"
                else:
                    logger.info("   -- *not live, not executing* ")
            except Exception as e:
                error = str(e)
                logger.info("   -- *not live, not executing* ")

            logger.info("   -- *mined* (status: %s / error: %s) ", status, error)
            was_success = status == 'success'
            if live:
                if not was_success:
                    logger.warning('subscription processing failed')
                    subscription.error = True
                    error_comments = f"{error}\n\ndebug info: {subscription.get_debug_info()}"
                    subscription.subminer_comments = error_comments
                    subscription.save()
                    grant = subscription.grant
                    grant.updateActiveSubscriptions()
                    grant.save()
                    warn_subscription_failed(subscription)
                else:
                    logger.info('subscription processing successful')
                    subscription.successful_contribution(txid)
                    subscription.save()
Пример #12
0
                       * 10**9)
        if network == 'xdai':
            gasPrice = 1 * 10**9
        tx = contract.functions.clone(address, token_id, 1).buildTransaction({
            'nonce':
            nonce,
            'gas':
            500000,
            'gasPrice':
            gasPrice,
            'value':
            int(price_finney / 1000.0 * 10**18),
        })

        signed = w3.eth.account.signTransaction(tx, settings.KUDOS_PRIVATE_KEY)
        txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex()
        nonce += 1
        print(f'sent tx nonce:{nonce} for kt:{kt.id} on {network}')
        kt.txid = txid
        kt.receive_txid = txid
        kt.tx_status = 'pending'
        kt.network = network
        kt.save()

        while not has_tx_mined(txid, network):
            time.sleep(TIME_SLEEP)

    except Exception as e:
        print(e)
        error = "Could not redeem your kudos.  Please try again soon."
Пример #13
0
# note: only use this if the admin is failling

token_req_id = 2235

import time

from dashboard.utils import has_tx_mined
from gas.utils import recommend_min_gas_price_to_confirm_in_time
from kudos.management.commands.mint_all_kudos import sync_latest
from kudos.models import TokenRequest
from marketing.mails import notify_kudos_minted

obj = TokenRequest.objects.get(pk=token_req_id)
multiplier = 1
gas_price = int(
    float(recommend_min_gas_price_to_confirm_in_time(1)) * multiplier)
tx_id = obj.mint(gas_price)
while not has_tx_mined(tx_id, obj.network):
    time.sleep(1)
for i in range(0, 9):
    sync_latest(i, obj.network)
notify_kudos_minted(obj)
Пример #14
0
    def handle(self, *args, **options):
        ## creates text inputs which can be hidden in gitcoin avatars

        # setup
        network = 'mainnet' if not settings.DEBUG else 'rinkeby'
        amount = float(options['amount'])
        amount = int(amount * 10**18)
        number = int(options['number'])
        from_address = settings.AVATAR_ADDRESS
        from_address = Web3.toChecksumAddress(from_address)
        from_pk = settings.AVATAR_PRIVATE_KEY
        w3 = get_web3(network)

        # generate accounts
        accounts = []
        for i in range(0, number):
            entropy = str(uuid.uuid4())
            acct = w3.eth.account.create(entropy)
            accounts.append(acct)

        # generate the accounts and
        # send them to the database
        counter = 1
        for account in accounts:
            try:
                # do the send
                to = account.address
                private_key = account.privateKey
                to = Web3.toChecksumAddress(to)
                txn = {
                    'to':
                    to,
                    'from':
                    from_address,
                    'value':
                    amount,
                    'nonce':
                    w3.eth.getTransactionCount(from_address),
                    'gas':
                    22000,
                    'gasPrice':
                    int(
                        float(recommend_min_gas_price_to_confirm_in_time(1)) *
                        10**9 * 1.4),
                    'data':
                    b'',
                }
                signed = w3.eth.account.signTransaction(txn, from_pk)
                tx_id = w3.eth.sendRawTransaction(signed.rawTransaction).hex()

                # wait for it to mine
                print(f"({counter}/{number}) - paid via", tx_id)
                while not has_tx_mined(tx_id, network):
                    time.sleep(1)

                # save to db
                AvatarTextOverlayInput.objects.create(
                    active=True,
                    text=private_key.hex(),
                    coment='auto avatar text creation',
                    num_uses_total=1,
                    current_uses=0,
                    num_uses_remaining=1,
                )
                counter += 1
            except Exception as e:
                print(e)
Пример #15
0
def redeem_bulk_kudos(self, kt_id, retry=False):
    """
    :param self:
    :param kt_id:
    :return:
    """
    with redis.lock("tasks:all_kudos_requests", timeout=LOCK_TIMEOUT):
        with redis.lock("tasks:redeem_bulk_kudos:%s" % kt_id,
                        timeout=LOCK_TIMEOUT):
            from dashboard.utils import has_tx_mined
            from gas.utils import recommend_min_gas_price_to_confirm_in_time
            try:
                multiplier = 1
                gas_price = int(
                    float(recommend_min_gas_price_to_confirm_in_time(1)) *
                    multiplier)
                if gas_price > delay_if_gas_prices_gt:
                    self.retry(countdown=120)
                    return

                obj = KudosTransfer.objects.get(pk=kt_id)
                w3 = get_web3(obj.network)
                token = obj.kudos_token_cloned_from
                if token.owner_address.lower(
                ) != '0x6239FF1040E412491557a7a02b2CBcC5aE85dc8F'.lower():
                    raise Exception(
                        "kudos isnt owned by Gitcoin; cowardly refusing to spend Gitcoin's ETH minting it"
                    )
                kudos_owner_address = settings.KUDOS_OWNER_ACCOUNT
                kudos_owner_address = Web3.toChecksumAddress(
                    kudos_owner_address)
                kudos_contract_address = Web3.toChecksumAddress(
                    settings.KUDOS_CONTRACT_MAINNET)
                contract = w3.eth.contract(
                    Web3.toChecksumAddress(kudos_contract_address),
                    abi=kudos_abi())
                nonce = w3.eth.getTransactionCount(kudos_owner_address)
                tx = contract.functions.clone(
                    Web3.toChecksumAddress(obj.receive_address),
                    token.token_id, 1).buildTransaction({
                        'nonce':
                        nonce,
                        'gas':
                        500000,
                        'gasPrice':
                        gas_price,
                        'value':
                        int(token.price_finney / 1000.0 * 10**18),
                    })
                private_key = settings.KUDOS_PRIVATE_KEY
                signed = w3.eth.account.signTransaction(tx, private_key)
                obj.txid = w3.eth.sendRawTransaction(
                    signed.rawTransaction).hex()
                obj.receive_txid = obj.txid
                obj.save()
                while not has_tx_mined(obj.txid, obj.network):
                    time.sleep(1)
                pass
            except Exception as e:
                print(e)
                self.retry(countdown=(30 * (self.request.retries + 1)))
Пример #16
0
    def handle(self, *args, **options):

        # setup
        payment_threshold_usd = 0
        KYC_THRESHOLD = settings.GRANTS_PAYOUT_CLR_KYC_THRESHOLD
        network = 'mainnet' if not settings.DEBUG else 'rinkeby'
        from_address = settings.GRANTS_PAYOUT_ADDRESS
        from_pk = settings.GRANTS_PAYOUT_PRIVATE_KEY
        DECIMALS = 18
        what = options['what']
        clr_round = options['clr_round']
        DAI_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f' if network=='mainnet' else '0x6a6e8b58dee0ca4b4ee147ad72d3ddd2ef1bf6f7'
        CLR_TOKEN_ADDRESS = '0xe4101d014443af2b7f6f9f603e904adc9faf0de5' if network=='mainnet' else '0xc19b694ebd4309d7a2adcd9970f8d7f424a1528b'

        # get data
        clr_pks = options['clr_pks'].split(',')
        gclrs = GrantCLR.objects.filter(pk__in=clr_pks)
        pks = []
        for gclr in gclrs:
            pks += gclr.grants.values_list('pk', flat=True)
        scheduled_matches = CLRMatch.objects.filter(round_number=clr_round)
        grants = Grant.objects.filter(active=True, network='mainnet', link_to_new_grant__isnull=True, pk__in=pks)
        print(f"got {grants.count()} grants")

        # finalize rankings
        if what == 'finalize':
            total_owed_grants = 0
            for grant in grants:
                try:
                    for gclr in grant.clr_calculations.filter(grantclr__in=gclrs, latest=True):
                        total_owed_grants += gclr.clr_prediction_curve[0][1]
                except:
                    pass
            total_owed_matches = sum(sm.amount for sm in scheduled_matches)
            print(f"there are {grants.count()} grants to finalize worth ${round(total_owed_grants,2)}")
            print(f"there are {scheduled_matches.count()} Match Payments already created worth ${round(total_owed_matches,2)}")
            print('------------------------------')
            user_input = input("continue? (y/n) ")
            if user_input != 'y':
                return
            for grant in grants:
                amount = sum(ele.clr_prediction_curve[0][1] for ele in grant.clr_calculations.filter(grantclr__in=gclrs, latest=True))
                has_already_kyc = grant.clr_matches.filter(has_passed_kyc=True).exists()
                if not amount:
                    continue
                already_exists = scheduled_matches.filter(grant=grant).exists()
                if already_exists:
                    continue
                needs_kyc = amount > KYC_THRESHOLD and not has_already_kyc
                comments = "" if not needs_kyc else "Needs KYC"
                ready_for_test_payout = not needs_kyc
                match = CLRMatch.objects.create(
                    round_number=clr_round,
                    amount=amount,
                    grant=grant,
                    comments=comments,
                    ready_for_test_payout=ready_for_test_payout,
                    )
                if needs_kyc:
                    grant_match_distribution_kyc(match)


        # payout rankings (round must be finalized first)
        if what in ['prepare_final_payout']:
            payout_matches = scheduled_matches.exclude(test_payout_tx='').filter(ready_for_payout=False)
            payout_matches_amount = sum(sm.amount for sm in payout_matches)
            print(f"there are {payout_matches.count()} UNPAID Match Payments already created worth ${round(payout_matches_amount,2)} {network} DAI")
            print('------------------------------')
            user_input = input("continue? (y/n) ")
            if user_input != 'y':
                return
            for match in payout_matches:
                match.ready_for_payout=True
                match.save()
            print('promoted')


        # payout rankings (round must be finalized first)
        if what in ['payout_test', 'payout_dai']:
            is_real_payout = what == 'payout_dai'
            TOKEN_ADDRESS = DAI_ADDRESS if is_real_payout else CLR_TOKEN_ADDRESS
            kwargs = {}
            token_name = f'CLR{clr_round}' if not is_real_payout else 'DAI'
            key = 'ready_for_test_payout' if not is_real_payout else 'ready_for_payout'
            kwargs[key] = False
            not_ready_scheduled_matches = scheduled_matches.filter(**kwargs)
            kwargs[key] = True
            kwargs2 = {}
            key2 = 'test_payout_tx' if not is_real_payout else 'payout_tx'
            kwargs2[key2] = ''
            unpaid_scheduled_matches = scheduled_matches.filter(**kwargs).filter(**kwargs2)
            paid_scheduled_matches = scheduled_matches.filter(**kwargs).exclude(**kwargs2)
            total_not_ready_matches = sum(sm.amount for sm in not_ready_scheduled_matches)
            total_owed_matches = sum(sm.amount for sm in unpaid_scheduled_matches)
            total_paid_matches = sum(sm.amount for sm in paid_scheduled_matches)
            print(f"there are {not_ready_scheduled_matches.count()} NOT READY Match Payments already created worth ${round(total_not_ready_matches,2)} {network} {token_name}")
            print(f"there are {unpaid_scheduled_matches.count()} UNPAID Match Payments already created worth ${round(total_owed_matches,2)} {network} {token_name}")
            print(f"there are {paid_scheduled_matches.count()} PAID Match Payments already created worth ${round(total_paid_matches,2)} {network} {token_name}")
            print('------------------------------')
            user_input = input("continue? (y/n) ")
            if user_input != 'y':
                return

            print(f"continuing with {unpaid_scheduled_matches.count()} unpaid scheduled payouts")

            if is_real_payout:
                user_input = input(F"THIS IS A REAL PAYOUT FOR {network} {token_name}.  ARE YOU DOUBLE SECRET SUPER SURE? (y/n) ")
                if user_input != 'y':
                    return

            for match in unpaid_scheduled_matches.order_by('amount'):

                # issue payment
                print(f"- issuing payout {match.pk} worth {match.amount} {token_name}")
                address = match.grant.admin_address
                amount_owed = match.amount

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

                amount = int(amount_owed * 10**DECIMALS)
                tx_args = {
                    'nonce': w3.eth.getTransactionCount(from_address),
                    'gas': 100000,
                    'gasPrice': int(float(recommend_min_gas_price_to_confirm_in_time(1)) * 10**9 * 1.4)
                }
                tx = contract.functions.transfer(address, amount).buildTransaction(tx_args)

                signed = w3.eth.account.signTransaction(tx, from_pk)
                tx_id = None
                success = False
                counter = 0
                while not success:
                    try:
                        tx_id = w3.eth.sendRawTransaction(signed.rawTransaction).hex()
                        success = True
                    except Exception as e:
                        counter +=1
                        if 'replacement transaction underpriced' in str(e):
                            print(f'replacement transaction underpriced. retrying {counter}')
                            time.sleep(WAIT_TIME_BETWEEN_PAYOUTS)
                        elif 'nonce too low' in str(e):
                            print(f'nonce too low. retrying {counter}')
                            time.sleep(WAIT_TIME_BETWEEN_PAYOUTS)

                            # rebuild txn
                            tx_args['nonce'] = w3.eth.getTransactionCount(from_address)
                            tx = contract.functions.transfer(address, amount).buildTransaction(tx_args)
                            signed = w3.eth.account.signTransaction(tx, from_pk)
                        else:
                            raise e

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

                print("paid via", tx_id)

                # make save state to DB
                if is_real_payout:
                    match.payout_tx = tx_id
                else:
                    match.test_payout_tx = tx_id
                match.save()

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

                # make save state to DB
                if is_real_payout:
                    match.payout_tx_date = timezone.now()
                    grant_match_distribution_final_txn(match)
                else:
                    match.test_payout_tx_date = timezone.now()
                    grant_match_distribution_test_txn(match)
                match.save()

                # create payout obj artifacts
                profile = Profile.objects.get(handle__iexact='gitcoinbot')
                validator_comment = f"created by ingest payout_round_script"
                subscription = Subscription()
                subscription.is_postive_vote = True
                subscription.active = False
                subscription.error = True
                subscription.contributor_address = 'N/A'
                subscription.amount_per_period = match.amount
                subscription.real_period_seconds = 2592000
                subscription.frequency = 30
                subscription.frequency_unit = 'N/A'
                subscription.token_address = TOKEN_ADDRESS
                subscription.token_symbol = token_name
                subscription.gas_price = 0
                subscription.new_approve_tx_id = '0x0'
                subscription.num_tx_approved = 1
                subscription.network = network
                subscription.contributor_profile = profile
                subscription.grant = match.grant
                subscription.comments = validator_comment
                subscription.amount_per_period_usdt = match.amount if is_real_payout else 0
                subscription.save()

                contrib = Contribution.objects.create(
                    success=True,
                    tx_cleared=True,
                    tx_override=True,
                    tx_id=tx_id,
                    subscription=subscription,
                    validator_passed=True,
                    validator_comment=validator_comment,
                    )
                print(f"ingested {subscription.pk} / {contrib.pk}")

                if is_real_payout:
                    match.payout_contribution = contrib
                else:
                    match.test_payout_contribution = contrib
                match.save()

                metadata = {
                    'id': subscription.id,
                    'value_in_token': str(subscription.amount_per_period),
                    'value_in_usdt_now': str(round(subscription.amount_per_period_usdt,2)),
                    'token_name': subscription.token_symbol,
                    'title': subscription.grant.title,
                    'grant_url': subscription.grant.url,
                    'num_tx_approved': subscription.num_tx_approved,
                    'category': 'grant',
                }
                kwargs = {
                    'profile': profile,
                    'subscription': subscription,
                    'grant': subscription.grant,
                    'activity_type': 'new_grant_contribution',
                    'metadata': metadata,
                }

                activity = Activity.objects.create(**kwargs)

                if is_real_payout:
                    comment = f"CLR Round {clr_round} Payout"
                    comment = Comment.objects.create(profile=profile, activity=activity, comment=comment)

                print("SLEEPING")
                time.sleep(WAIT_TIME_BETWEEN_PAYOUTS)
                print("DONE SLEEPING")
Пример #17
0
def redeem_bulk_kudos(self, kt_id, retry=False):
    """
    :param self:
    :param kt_id:
    :return:
    """
    try:
        with redis.lock("tasks:redeem_bulk_kudos:%s" % kt_id,
                        timeout=LOCK_TIMEOUT):
            multiplier = 1
            # high gas prices, 5 hour gas limit - DL
            gas_price = int(
                float(recommend_min_gas_price_to_confirm_in_time(300)) *
                multiplier)
            if gas_price > delay_if_gas_prices_gt_redeem:
                # do not retry is gas prices are too high
                # TODO: revisit this when gas prices go down
                # self.retry(countdown=60*10)
                return

            obj = KudosTransfer.objects.get(pk=kt_id)
            w3 = get_web3(obj.network)
            token = obj.kudos_token_cloned_from
            if token.owner_address.lower(
            ) != '0x6239FF1040E412491557a7a02b2CBcC5aE85dc8F'.lower():
                raise Exception(
                    "kudos isnt owned by Gitcoin; cowardly refusing to spend Gitcoin's ETH minting it"
                )
            kudos_owner_address = settings.KUDOS_OWNER_ACCOUNT
            kudos_owner_address = Web3.toChecksumAddress(kudos_owner_address)
            kudos_contract_address = Web3.toChecksumAddress(
                settings.KUDOS_CONTRACT_MAINNET)
            contract = w3.eth.contract(
                Web3.toChecksumAddress(kudos_contract_address),
                abi=kudos_abi())
            nonce = w3.eth.getTransactionCount(kudos_owner_address)
            tx = contract.functions.clone(
                Web3.toChecksumAddress(obj.receive_address), token.token_id,
                1).buildTransaction({
                    'nonce':
                    nonce,
                    'gas':
                    500000,
                    'gasPrice':
                    gas_price,
                    'value':
                    int(token.price_finney / 1000.0 * 10**18),
                })
            private_key = settings.KUDOS_PRIVATE_KEY
            signed = w3.eth.account.signTransaction(tx, private_key)
            obj.txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex()
            obj.receive_txid = obj.txid
            obj.save()
            while not has_tx_mined(obj.txid, obj.network):
                time.sleep(1)
            pass
    except (SoftTimeLimitExceeded, TimeLimitExceeded):
        print('max timeout for bulk kudos redeem exceeded ... giving up!')
    except Exception as e:
        print(e)
        if self.request.retries < self.max_retries:
            self.retry(countdown=(30 * (self.request.retries + 1)))
        else:
            print("max retries for bulk kudos redeem exceeded ... giving up!")
Пример #18
0
def process_subscription(subscription, live):
    is_ready_to_be_processed_db = subscription.get_is_ready_to_be_processed_from_db(
    )

    logger.info("  - subscription %d", subscription.pk)
    if is_ready_to_be_processed_db:
        logger.info("   -- (ready via db) ")
        are_we_past_next_valid_timestamp = subscription.get_are_we_past_next_valid_timestamp(
        )

        # FOR DEBUGGING
        if not live:
            is_ready_to_be_processed_web3 = subscription.get_is_subscription_ready_from_web3(
            )
            is_active_web3 = subscription.get_is_active_from_web3()
            signer = subscription.get_subscription_signer_from_web3()
            logger.info("    ---  DEBUG INFO")
            logger.info(
                "    --- %s, %s, %s, %s",
                are_we_past_next_valid_timestamp,
                is_ready_to_be_processed_web3,
                is_active_web3,
                signer,
            )

        if not are_we_past_next_valid_timestamp:
            logger.info(
                f"   -- ( NOT ready via web3, will be ready on {subscription.get_next_valid_timestamp()}) "
            )
        else:
            logger.info("   -- (ready via web3) ")
            status = 'failure'
            txid = None
            error = ""
            try:
                if live:
                    logger.info("   -- *executing* ")
                    counter = 0
                    while not has_tx_mined(subscription.new_approve_tx_id,
                                           subscription.grant.network):
                        time.sleep(SLEEP_TIME)
                        logger.info(
                            f"   -- *waiting {SLEEP_TIME} seconds for {subscription.new_approve_tx_id} to mine*"
                        )
                        counter += 1
                        if counter > MAX_COUNTER:
                            raise Exception(
                                f"waited more than {MAX_COUNTER} times for tx  to mine"
                            )

                    txid = subscription.do_execute_subscription_via_web3()
                    logger.info("   -- *waiting for mine* (txid %s) ", txid)

                    override = False
                    counter = 0
                    while not has_tx_mined(
                            txid, subscription.grant.network) and not override:
                        time.sleep(SLEEP_TIME)
                        logger.info(
                            f"   -- *waiting {SLEEP_TIME} seconds for {txid} to mine*"
                        )
                        counter += 1
                        if counter > MAX_COUNTER:
                            override = True
                            # force the subminer to continue on; this tx is taking too long.
                            # an admin will have to look at this later and determine what went wrong
                            # KO 2019/02/06

                    status, __ = get_tx_status(txid,
                                               subscription.grant.network,
                                               timezone.now())
                    if status != 'success':
                        error = f"tx status from RPC is {status} not success, txid: {txid}"
                else:
                    logger.info("   -- *not live, not executing* ")
            except Exception as e:
                error = str(e)
                logger.info("   -- *not live, not executing* ")

            logger.info("   -- *mined* (status: %s / error: %s) ", status,
                        error)
            was_success = status == 'success'
            if live:
                if not was_success:
                    logger.warning('subscription processing failed')
                    subscription.error = True
                    error_comments = f"{error}\n\ndebug info: {subscription.get_debug_info()}"
                    subscription.subminer_comments = error_comments
                    subscription.save()
                    warn_subscription_failed(subscription)
                else:
                    logger.info('subscription processing successful')
                    subscription.successful_contribution(txid)
                    subscription.save()
Пример #19
0
    def handle(self, *args, **options):
        # setup
        minutes_ago = 10 if not settings.DEBUG else 40
        payment_threshold_usd = 1
        network = 'mainnet' if not settings.DEBUG else 'rinkeby'
        from_address = settings.MINICLR_ADDRESS
        from_pk = settings.MINICLR_PRIVATE_KEY
        DAI_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f' if network == 'mainnet' else '0x8f2e097e79b1c51be9cba42658862f0192c3e487'
        provider = settings.WEB3_HTTP_PROVIDER if network == 'mainnet' else "https://rinkeby.infura.io/"

        # find a round that has recently expired
        cursor_time = timezone.now() - timezone.timedelta(minutes=minutes_ago)
        mr = MatchRound.objects.filter(valid_from__lt=cursor_time,
                                       valid_to__gt=cursor_time,
                                       valid_to__lt=timezone.now()).first()
        if not mr:
            print(
                f'No Match Round Found that ended between {cursor_time} <> {timezone.now()}'
            )
            return
        print(mr)

        # finalize rankings
        rankings = mr.ranking.filter(final=False,
                                     paid=False).order_by('number')
        print(rankings.count())
        for ranking in rankings:
            ranking.final = True
            ranking.save()

        # payout rankings
        rankings = mr.ranking.filter(final=True, paid=False).order_by('number')
        print(rankings.count())
        w3 = Web3(HTTPProvider(provider))
        for ranking in rankings:
            print(ranking)

            # figure out amount_owed
            profile = ranking.profile
            owed_rankings = profile.match_rankings.filter(final=True,
                                                          paid=False)
            amount_owed = sum(
                owed_rankings.values_list('match_total', flat=True))

            # validate
            error = None
            if amount_owed < payment_threshold_usd:
                error = ("- less than amount owed; continue")
            address = profile.preferred_payout_address
            if not address:
                error = ("- address not on file")

            if error:
                ranking.payout_tx_status = error
                ranking.save()
                continue

            # issue payment
            contract = w3.eth.contract(Web3.toChecksumAddress(DAI_ADDRESS),
                                       abi=abi)
            address = Web3.toChecksumAddress(address)
            amount = int(amount_owed * 10**18)
            tx = contract.functions.transfer(address, amount).buildTransaction(
                {
                    'nonce':
                    w3.eth.getTransactionCount(from_address),
                    'gas':
                    100000,
                    'gasPrice':
                    recommend_min_gas_price_to_confirm_in_time(1) * 10**9
                })

            signed = w3.eth.account.signTransaction(tx, from_pk)
            tx_id = w3.eth.sendRawTransaction(signed.rawTransaction).hex()

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

            ranking.payout_tx_status, ranking.payout_tx_issued = get_tx_status(
                tx_id, network, timezone.now())

            ranking.paid = True
            ranking.payout_txid = tx_id
            ranking.save()
            for other_ranking in owed_rankings:
                other_ranking.paid = True
                other_ranking.payout_txid = ranking.payout_txid
                other_ranking.payout_tx_issued = ranking.payout_tx_issued
                other_ranking.payout_tx_status = ranking.payout_tx_status
                other_ranking.save()

            # create earning object
            from dashboard.models import Earning, Profile, Activity
            from django.contrib.contenttypes.models import ContentType
            from_profile = Profile.objects.get(handle='gitcoinbot')
            Earning.objects.update_or_create(
                source_type=ContentType.objects.get(app_label='townsquare',
                                                    model='matchranking'),
                source_id=ranking.pk,
                defaults={
                    "created_on": ranking.created_on,
                    "org_profile": None,
                    "from_profile": from_profile,
                    "to_profile": ranking.profile,
                    "value_usd": amount_owed,
                    "url": 'https://gitcoin.co/#clr',
                    "network": network,
                })

            Activity.objects.create(created_on=timezone.now(),
                                    profile=ranking.profile,
                                    activity_type='mini_clr_payout',
                                    metadata={
                                        "amount": amount_owed,
                                    })

            from marketing.mails import match_distribution
            match_distribution(ranking)
Пример #20
0
    def handle(self, *args, **options):

        # setup
        payment_threshold_usd = 1
        network = 'mainnet' if not settings.DEBUG else 'rinkeby'
        from_address = settings.MINICLR_ADDRESS
        from_pk = settings.MINICLR_PRIVATE_KEY
        DAI_ADDRESS = '0x6b175474e89094c44da98b954eedeac495271d0f' if network == 'mainnet' else '0x8f2e097e79b1c51be9cba42658862f0192c3e487'

        # find a round that has recently expired
        minutes_ago = options['minutes_ago']
        cursor_time = timezone.now() - timezone.timedelta(minutes=minutes_ago)
        mr = MatchRound.objects.filter(valid_from__lt=cursor_time,
                                       valid_to__gt=cursor_time,
                                       valid_to__lt=timezone.now()).first()
        if options['round_number']:
            mr = MatchRound.objects.get(number=options['round_number'])
        if not mr:
            print(
                f'No Match Round Found that ended between {cursor_time} <> {timezone.now()}'
            )
            return
        print(mr)

        # finalize rankings
        if options['what'] == 'finalize':
            rankings = mr.ranking.filter(final=False,
                                         paid=False).order_by('-match_total')
            print(rankings.count(), "to finalize")
            for ranking in rankings:
                ranking.final = True
                ranking.save()
            print(rankings.count(), " finalied")

        # payout rankings (round must be finalized first)
        if options['what'] == 'payout':
            rankings = mr.ranking.filter(final=True,
                                         paid=False).order_by('-match_total')
            print(rankings.count(), " to pay")
            w3 = get_web3(network)
            for ranking in rankings:

                # figure out amount_owed
                profile = ranking.profile
                owed_rankings = profile.match_rankings.filter(final=True,
                                                              paid=False)
                amount_owed = sum(
                    owed_rankings.values_list('match_total', flat=True))
                print(
                    f"paying {ranking.profile.handle} who is owed {amount_owed} ({ranking.match_total} from this round)"
                )

                # validate
                error = None
                if amount_owed < payment_threshold_usd:
                    error = ("- less than amount owed; continue")
                address = profile.preferred_payout_address
                if not address:
                    error = ("- address not on file")

                if error:
                    print(error)
                    ranking.payout_tx_status = error
                    ranking.save()
                    continue

                # issue payment
                contract = w3.eth.contract(Web3.toChecksumAddress(DAI_ADDRESS),
                                           abi=abi)
                address = Web3.toChecksumAddress(address)
                amount = int(amount_owed * 10**18)
                tx = contract.functions.transfer(
                    address, amount
                ).buildTransaction({
                    'nonce':
                    w3.eth.getTransactionCount(from_address),
                    'gas':
                    100000,
                    '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()
                print("paid via", tx_id)

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

                ranking.payout_tx_status, ranking.payout_tx_issued = get_tx_status(
                    tx_id, network, timezone.now())

                ranking.paid = True
                ranking.payout_txid = tx_id
                ranking.save()
                for other_ranking in owed_rankings:
                    other_ranking.paid = True
                    other_ranking.payout_txid = ranking.payout_txid
                    other_ranking.payout_tx_issued = ranking.payout_tx_issued
                    other_ranking.payout_tx_status = ranking.payout_tx_status
                    other_ranking.save()

                # create earning object
                from_profile = Profile.objects.get(handle='gitcoinbot')
                Earning.objects.update_or_create(
                    source_type=ContentType.objects.get(app_label='townsquare',
                                                        model='matchranking'),
                    source_id=ranking.pk,
                    defaults={
                        "created_on": ranking.created_on,
                        "org_profile": None,
                        "from_profile": from_profile,
                        "to_profile": ranking.profile,
                        "value_usd": amount_owed,
                        "url": 'https://gitcoin.co/#clr',
                        "network": network,
                    })

                Activity.objects.create(created_on=timezone.now(),
                                        profile=ranking.profile,
                                        activity_type='mini_clr_payout',
                                        metadata={
                                            "amount":
                                            float(amount_owed),
                                            "number":
                                            int(mr.number),
                                            "mr_pk":
                                            int(mr.pk),
                                            "round_description":
                                            f"Mini CLR Round {mr.number}"
                                        })

                from marketing.mails import match_distribution
                match_distribution(ranking)

                print("paid ", ranking)
                time.sleep(30)

        # announce finalists (round must be finalized first)
        from_profile = Profile.objects.get(handle='gitcoinbot')
        if options['what'] == 'announce':
            copy = f"Mini CLR Round {mr.number} Winners:<BR>"
            rankings = mr.ranking.filter(
                final=True).order_by('-match_total')[0:10]
            print(rankings.count(), " to announce")
            for ranking in rankings:
                profile_link = f"<a href=/{ranking.profile}>@{ranking.profile}</a>"
                copy += f" - {profile_link} was ranked <strong>#{ranking.number}</strong>. <BR>"
            metadata = {
                'copy': copy,
            }

            Activity.objects.create(
                created_on=timezone.now(),
                profile=from_profile,
                activity_type='consolidated_mini_clr_payout',
                metadata=metadata)
Пример #21
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")
Пример #22
0
 def is_verified(tx_details, tx_hash, tx_amount, network):
     gitcoin_account = '0x00De4B13153673BCAE2616b67bf822500d325Fc3'
     return has_tx_mined(tx_hash, network) and\
         tx_details.to.lower() == gitcoin_account.lower()
Пример #23
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 = not has_tx_mined(tip.txid, tip.network)
    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']
            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() + 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)