Example #1
0
def receive_tip_v2(request, pk, txid, network):
    """Handle the receiving of a tip (the POST).
    TODO: Deprecate after v3 has been live for a month.
    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 = get_web3(tip.network).eth.getBalance(
        Web3.toChecksumAddress(tip.metadata['address'])) == 0
    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']
            tip.receive_txid = tip.payout_to(address)
            tip.receive_address = address
            tip.received_on = timezone.now()
            tip.save()
            record_user_action(tip.from_username, 'receive_tip', tip)
            record_tip_activity(tip, tip.from_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_v2.html', params)
Example #2
0
def getBountyContract(network):
    web3 = get_web3(network)
    standardbounties_abi = '[{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"}],"name":"killBounty","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_bountyId","type":"uint256"}],"name":"getBountyToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_data","type":"string"}],"name":"fulfillBounty","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_newDeadline","type":"uint256"}],"name":"extendDeadline","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getNumBounties","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_fulfillmentId","type":"uint256"},{"name":"_data","type":"string"}],"name":"updateFulfillment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_newFulfillmentAmount","type":"uint256"},{"name":"_value","type":"uint256"}],"name":"increasePayout","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_newFulfillmentAmount","type":"uint256"}],"name":"changeBountyFulfillmentAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_newIssuer","type":"address"}],"name":"transferIssuer","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_value","type":"uint256"}],"name":"activateBounty","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"_issuer","type":"address"},{"name":"_deadline","type":"uint256"},{"name":"_data","type":"string"},{"name":"_fulfillmentAmount","type":"uint256"},{"name":"_arbiter","type":"address"},{"name":"_paysTokens","type":"bool"},{"name":"_tokenContract","type":"address"}],"name":"issueBounty","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_issuer","type":"address"},{"name":"_deadline","type":"uint256"},{"name":"_data","type":"string"},{"name":"_fulfillmentAmount","type":"uint256"},{"name":"_arbiter","type":"address"},{"name":"_paysTokens","type":"bool"},{"name":"_tokenContract","type":"address"},{"name":"_value","type":"uint256"}],"name":"issueAndActivateBounty","outputs":[{"name":"","type":"uint256"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"_bountyId","type":"uint256"}],"name":"getBountyArbiter","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_value","type":"uint256"}],"name":"contribute","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_newPaysTokens","type":"bool"},{"name":"_newTokenContract","type":"address"}],"name":"changeBountyPaysTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_bountyId","type":"uint256"}],"name":"getBountyData","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_fulfillmentId","type":"uint256"}],"name":"getFulfillment","outputs":[{"name":"","type":"bool"},{"name":"","type":"address"},{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_newArbiter","type":"address"}],"name":"changeBountyArbiter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_newDeadline","type":"uint256"}],"name":"changeBountyDeadline","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_fulfillmentId","type":"uint256"}],"name":"acceptFulfillment","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"bounties","outputs":[{"name":"issuer","type":"address"},{"name":"deadline","type":"uint256"},{"name":"data","type":"string"},{"name":"fulfillmentAmount","type":"uint256"},{"name":"arbiter","type":"address"},{"name":"paysTokens","type":"bool"},{"name":"bountyStage","type":"uint8"},{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_bountyId","type":"uint256"}],"name":"getBounty","outputs":[{"name":"","type":"address"},{"name":"","type":"uint256"},{"name":"","type":"uint256"},{"name":"","type":"bool"},{"name":"","type":"uint256"},{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_bountyId","type":"uint256"},{"name":"_newData","type":"string"}],"name":"changeBountyData","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_bountyId","type":"uint256"}],"name":"getNumFulfillments","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_owner","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bountyId","type":"uint256"}],"name":"BountyIssued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bountyId","type":"uint256"},{"indexed":false,"name":"issuer","type":"address"}],"name":"BountyActivated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bountyId","type":"uint256"},{"indexed":true,"name":"fulfiller","type":"address"},{"indexed":true,"name":"_fulfillmentId","type":"uint256"}],"name":"BountyFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_bountyId","type":"uint256"},{"indexed":false,"name":"_fulfillmentId","type":"uint256"}],"name":"FulfillmentUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bountyId","type":"uint256"},{"indexed":true,"name":"fulfiller","type":"address"},{"indexed":true,"name":"_fulfillmentId","type":"uint256"}],"name":"FulfillmentAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bountyId","type":"uint256"},{"indexed":true,"name":"issuer","type":"address"}],"name":"BountyKilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bountyId","type":"uint256"},{"indexed":true,"name":"contributor","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"ContributionAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bountyId","type":"uint256"},{"indexed":false,"name":"newDeadline","type":"uint256"}],"name":"DeadlineExtended","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"bountyId","type":"uint256"}],"name":"BountyChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_bountyId","type":"uint256"},{"indexed":true,"name":"_newIssuer","type":"address"}],"name":"IssuerTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"_bountyId","type":"uint256"},{"indexed":false,"name":"_newFulfillmentAmount","type":"uint256"}],"name":"PayoutIncreased","type":"event"}]'
    standardbounties_addr = getStandardBountiesContractAddresss(network)
    bounty_abi = json.loads(standardbounties_abi)
    getBountyContract = web3.eth.contract(standardbounties_addr,
                                          abi=bounty_abi)
    return getBountyContract
Example #3
0
 def contract(self):
     """Return grants contract."""
     from dashboard.utils import get_web3
     web3 = get_web3(self.network)
     grant_contract = web3.eth.contract(Web3.toChecksumAddress(
         self.contract_address),
                                        abi=self.abi)
     return grant_contract
Example #4
0
 def update_user_balance(self, holder_profile, holder_address):
     if PTOKEN_ABI and self.token_address:
         web3 = get_web3(self.network)
         contract = web3.eth.contract(Web3.toChecksumAddress(self.token_address), abi=PTOKEN_ABI)
         decimals = 10 ** contract.functions.decimals().call()
         balance = contract.functions.balanceOf(holder_address).call() // decimals
         self.cached_balances[str(holder_profile.id)] = balance
         self.save()
Example #5
0
def index(request):
    # setup
    player = request.GET.get('coinbase')
    network = request.GET.get('network')
    if not request.user.is_authenticated:
        return JsonResponse({'status': 'error', 'msg': 'You must login'})

    # setup web3 interactions
    w3 = get_web3(network)
    player = w3.toChecksumAddress(player)
    contract_address_rinkeby = w3.toChecksumAddress('0xcEFBf0A9Ada7A03056dD08B470AA843ef8ca5D79')
    contract_address_mainnet = w3.toChecksumAddress('0xb4e903dc14dfe994fe291fc5b385c4718413366d')
    if network not in ['rinkeby', 'mainnet']:
        return JsonResponse({'status': 'error', 'msg': 'Unsupported network'})

    # get contract
    contract_address = contract_address_mainnet if network == 'mainnet' else contract_address_rinkeby
    abi = '[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"tokenURI","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"createPassport","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_messageHash","type":"bytes32"}],"name":"getEthSignedMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_message","type":"string"},{"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"getMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_ethSignedMessageHash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"recoverSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"splitSignature","outputs":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_message","type":"string"},{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"verify","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]'
    abi = json.loads(abi)
    contract = w3.eth.contract(contract_address, abi=abi)

    # validation
    balance = contract.functions.balanceOf(player).call()
    if balance > 0:
        return JsonResponse({'status': 'error', 'msg': 'You already have a passport.  You must burn your passport before you can generate another one!'})

    # validation passed
    nonce = contract.functions.totalSupply().call() + 5
    _uuid = uuid.uuid4()
    tokenURI = f'{_uuid}'

    if request.user.profile.passport_requests.filter(network=network).exists():
        return JsonResponse({'status': 'error', 'msg': 'You already have a passport.  You must burn your passport before you can generate another one!'})

    ppr = PassportRequest.objects.create(
        profile=request.user.profile,
        nonce=nonce,
        address=player,
        uuid=_uuid,
        network=network,
        uri=tokenURI,
        )

    # sign message
    message = contract.functions.getMessageHash(player, 0, tokenURI, nonce).call()
    message_hash = defunct_hash_message(primitive=message)
    private_key = settings.PASSPORT_PK_RINKEBY if network == 'rinkeby' else settings.PASSPORT_PK_MAINNET
    signed_message = w3.eth.account.signHash(message_hash, private_key=private_key).signature.hex()

    context = {
        'status': 'success',
        'contract_address': contract_address,
        'contract_abi': abi,
        'nonce': nonce,
        'tokenURI': tokenURI,
        'hash': signed_message,
    }
    return JsonResponse(context)
Example #6
0
 def test_get_web3():
     """Test the dashboard utility get_web3."""
     networks = ['mainnet', 'rinkeby', 'ropsten']
     for network in networks:
         web3_provider = get_web3(network)
         assert isinstance(web3_provider, Web3)
         assert len(web3_provider.providers) == 1
         assert isinstance(web3_provider.providers[0], HTTPProvider)
         assert web3_provider.providers[0].endpoint_uri == f'https://{network}.infura.io'
Example #7
0
def has_tx_mined(txid, network):
    web3 = get_web3(network)
    try:
        transaction = web3.eth.getTransaction(txid)
        if not transaction:
            return False
        return transaction.blockHash != HexBytes('0x0000000000000000000000000000000000000000000000000000000000000000')
    except Exception:
        return False
Example #8
0
def new_matching_partner(request):

    tx_hash = request.POST.get('hash')
    tx_amount = request.POST.get('amount')
    profile = get_profile(request)

    def get_json_response(message, status):
        return JsonResponse({
            'status': status,
            'message': message
        },
                            status=status)

    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()

    if not request.user.is_authenticated:
        return get_json_response("Not Authorized", 403)

    if not profile:
        return get_json_response("Profile not found.", 404)

    if request.POST and tx_hash:
        network = 'mainnet'
        web3 = get_web3(network)
        tx = web3.eth.getTransaction(tx_hash)
        if not tx:
            raise Http404
        match_pledge = MatchPledge.objects.create(profile=profile,
                                                  amount=convert_amount(
                                                      tx.value / 10**18, 'ETH',
                                                      'USDT'),
                                                  data=json.dumps({
                                                      'tx_hash':
                                                      tx_hash,
                                                      'network':
                                                      network,
                                                      'from':
                                                      tx['from'],
                                                      'to':
                                                      tx.to,
                                                      'tx_amount':
                                                      tx.value
                                                  }))
        match_pledge.active = is_verified(tx, tx_hash, tx_amount, network)
        match_pledge.save()

        return get_json_response(
            """Thank you for volunteering to match on Gitcoin Grants.
            You are supporting open source, and we thank you.""", 201)

    return get_json_response("Wrong request.", 400)
Example #9
0
 def test_get_web3():
     """Test the dashboard utility get_web3."""
     networks = ['mainnet', 'rinkeby', 'ropsten']
     for network in networks:
         web3_provider = get_web3(network)
         assert isinstance(web3_provider, Web3)
         assert len(web3_provider.providers) == 1
         assert isinstance(web3_provider.providers[0], HTTPProvider)
         if settings.INFURA_USE_V3:
             assert web3_provider.providers[0].endpoint_uri == f'https://{network}.infura.io/v3/{settings.INFURA_V3_PROJECT_ID}'
         else:
             assert web3_provider.providers[0].endpoint_uri == f'https://{network}.infura.io'
Example #10
0
    def handle(self, *args, **options):
        # Parse inputs / setup
        network = options['network']
        w3 = get_web3(network)
        if network != 'mainnet' and network != 'rinkeby':
            raise Exception('Invalid network: Must be mainnet or rinkeby')

        # Get array of subscriptions with N/A contributor address
        bad_subscriptions = Subscription.objects.filter(contributor_address="N/A")

        # For each one, find the from address and use that to replace the N/A
        for subscription in bad_subscriptions:
            try:
                tx_hash = subscription.split_tx_id
                if tx_hash[0:8].lower() == 'sync-tx:':
                    # zkSync transaction, so use zkSync's API: https://zksync.io/api/v0.1.html#transaction-details
                    tx_hash = tx_hash.replace('sync-tx:', '0x')
                    base_url = 'https://rinkeby-api.zksync.io/api/v0.1' if network == 'rinkeby' else 'https://api.zksync.io/api/v0.1'
                    r = requests.get(f"{base_url}/transactions_all/{tx_hash}")
                    r.raise_for_status()
                    tx_data = r.json() # zkSync transaction data
                    if not tx_data:
                        print(f'Skipping, zkSync receipt not found for transaction {subscription.split_tx_id}')
                        continue
                    from_address = tx_data['from']
                elif len(tx_hash) == 66:
                    # Standard L1 transaction
                    receipt = w3.eth.getTransactionReceipt(tx_hash)
                    if not receipt:
                        print(f'Skipping, L1 receipt not found for transaction {subscription.split_tx_id}')
                        continue
                    from_address = receipt['from']
                else:
                    print(f'Skipping unknown transaction hash format, could not parse {subscription.split_tx_id}')
                    continue

                if not from_address:
                    print(f'Skipping invalid from address {from_address} for transaction hash {subscription.split_tx_id}')

                # Note: This approach does not guarantee the correct contributor address. Because we are using the sender
                # of the transaction as the contributor, we get the wrong address for users with wallet's that use
                # a relayer or meta-transactions, such as Argent. In those cases, the relayer address is incorrectly
                # listed as the sender. A more robust approach would take a non-trivial amount of work since it
                # requires recognizing relayed transaction and parsing them to find the wallet address, and there's no
                # universal standard for relayed transaction format
                from_address = Web3.toChecksumAddress(from_address)
                subscription.contributor_address = from_address
                subscription.save()
            except Exception as e:
                print(f'Skipping: Error when fetching from_address for transaction hash {subscription.split_tx_id}')
                print(e)
                print("\n")
Example #11
0
    def handle(self, *args, **options):
        w3 = get_web3('mainnet')
        monitored_accounts = [settings.KUDOS_OWNER_ACCOUNT]
        for account in monitored_accounts:
            balance_eth_threshold = 0.1
            if account == settings.KUDOS_OWNER_ACCOUNT:
                balance_eth_threshold = 0.4

            balance_wei = w3.eth.getBalance(account)
            balance_eth = balance_wei / 10**18

            if balance_eth < balance_eth_threshold:
                warn_account_out_of_eth(account, balance_eth, 'ETH')
Example #12
0
    def get_debug_info(self):
        """Return grants contract."""
        from dashboard.utils import get_web3
        from dashboard.abi import erc20_abi
        from dashboard.tokens import addr_to_token
        try:
            web3 = get_web3(self.network)
            if not self.token_address:
                return "This subscription has no token_address"
            token_contract = web3.eth.contract(Web3.toChecksumAddress(
                self.token_address),
                                               abi=erc20_abi)
            balance = token_contract.functions.balanceOf(
                Web3.toChecksumAddress(self.contributor_address)).call()
            allowance = token_contract.functions.allowance(
                Web3.toChecksumAddress(self.contributor_address),
                Web3.toChecksumAddress(self.grant.contract_address)).call()
            gasPrice = self.gas_price
            is_active = self.get_is_active_from_web3()
            token = addr_to_token(self.token_address, self.network)
            next_valid_timestamp = self.get_next_valid_timestamp()
            decimals = token.get('decimals', 0)
            balance = balance / 10**decimals
            allowance = allowance / 10**decimals
            error_reason = "unknown"
            if not is_active:
                error_reason = 'not_active'
            if timezone.now().timestamp() < next_valid_timestamp:
                error_reason = 'before_next_valid_timestamp'
            if (float(balance) + float(gasPrice)) < float(
                    self.amount_per_period):
                error_reason = "insufficient_balance"
            if allowance < self.amount_per_period:
                error_reason = "insufficient_allowance"

            debug_info = f"""
error_reason: {error_reason}
==============================
is_active: {is_active}
decimals: {decimals}
balance: {balance}
allowance: {allowance}
amount_per_period: {self.amount_per_period}
next_valid_timestamp: {next_valid_timestamp}
"""
        except Exception as e:
            return str(e)
        return debug_info
Example #13
0
    def handle(self, *args, **options):
        networks = ['xdai', 'mainnet']
        for network in networks:
            denomination = 'ETH' if network == 'mainnet' else 'xdai'
            w3 = get_web3(network)
            monitored_accounts = [settings.KUDOS_OWNER_ACCOUNT]
            for account in monitored_accounts:
                balance_eth_threshold = 0.1
                if account == settings.KUDOS_OWNER_ACCOUNT:
                    balance_eth_threshold = 0.4

                balance_wei = w3.eth.getBalance(account)
                balance_eth = balance_wei / 10**18

                if balance_eth < balance_eth_threshold:
                    warn_account_out_of_eth(account, balance_eth, 'ETH')
Example #14
0
def get_tx_status_and_details(txid, network, created_on):
    from django.utils import timezone
    from dashboard.utils import get_web3
    import pytz

    DROPPED_DAYS = 4

    # get status
    tx = {}
    status = None
    if txid == 'override':
        return 'success', None  #overridden by admin
    try:
        web3 = get_web3(network)
        tx = web3.eth.getTransactionReceipt(txid)
        if not tx:
            drop_dead_date = created_on + timezone.timedelta(days=DROPPED_DAYS)
            if timezone.now() > drop_dead_date:
                status = 'dropped'
            else:
                status = 'pending'
        elif tx and 'status' not in tx.keys():
            if bool(tx['blockNumber']) and bool(tx['blockHash']):
                status = 'success'
            else:
                raise Exception("got a tx but no blockNumber or blockHash")
        elif tx.status == 1:
            status = 'success'
        elif tx.status == 0:
            status = 'error'
        else:
            status = 'unknown'
    except Exception as e:
        logger.debug(f'Failure in get_tx_status for {txid} - ({e})')
        status = 'unknown'

    # get timestamp
    timestamp = None
    try:
        if tx:
            block = web3.eth.getBlock(tx['blockNumber'])
            timestamp = block.timestamp
            timestamp = timezone.datetime.fromtimestamp(timestamp).replace(
                tzinfo=pytz.UTC)
    except:
        pass
    return status, timestamp, tx
Example #15
0
File: utils.py Project: ezaruba/web
    def __init__(self, network='localhost', sockets=False):
        """Initialize the KudosContract.

        Args:
            network (str, optional): The blockchain network (localhost, rinkeby, ropsten, mainnet)
            sockets (bool, optional): Use web socket provider if set to True, otherwise use Http provider.

        """
        network = 'localhost' if network == 'custom network' else network
        self.network = network

        self._w3 = get_web3(self.network, sockets=sockets)

        ipfsConnectionString = f'/dns/{settings.IPFS_HOST}/tcp/{settings.IPFS_API_PORT}/{settings.IPFS_API_SCHEME}'
        self._ipfs = ipfshttpclient.connect(ipfsConnectionString)
        self._contract = self._get_contract()

        self.address = self._get_contract_address()
Example #16
0
 def _do_helper_via_web3(self, fn, minutes_to_confirm_within=1):
     """Call the specified function fn"""
     from dashboard.utils import get_web3
     args = self.get_subscription_hash_arguments()
     tx = fn(
         args['from'],
         args['to'],
         args['tokenAddress'],
         args['tokenAmount'],
         args['periodSeconds'],
         args['gasPrice'],
         args['nonce'],
         args['signature'],
     ).buildTransaction(self.helper_tx_dict(minutes_to_confirm_within))
     web3 = get_web3(self.grant.network)
     signed_txn = web3.eth.account.signTransaction(
         tx, private_key=settings.GRANTS_PRIVATE_KEY)
     return web3.eth.sendRawTransaction(signed_txn.rawTransaction).hex()
Example #17
0
    def handle(self, *args, **options):
        # config
        block = 'latest'

        # setup
        network = options['network']
        web3 = get_web3(network)
        contract_address = getStandardBountiesContractAddresss(network)
        contract = getBountyContract(network)
        last_block_hash = None

        while True:
            # wait for a new block
            block = web3.eth.getBlock('latest')
            block_hash = block['hash']

            if last_block_hash == block_hash:
                time.sleep(1)
                continue

            print('got new block %s' % web3.toHex(block_hash))

            # get txs
            transactions = block['transactions']
            for tx in transactions:
                tx = web3.eth.getTransaction(tx)
                if not tx or tx['to'] != contract_address:
                    continue

                print('found a stdbounties tx')
                data = tx['input']
                method_id = data[:10]
                if method_id == '0x7e9e511d':
                    # issueAndActivateBounty
                    bounty_id = contract.functions.getNumBounties().call() - 1
                else:
                    # any other method
                    bounty_id = int(data[10:74], 16)
                print('process_bounty %d' % bounty_id)
                process_bounty(bounty_id, network)
                print('done process_bounty %d' % bounty_id)

            last_block_hash = block_hash
Example #18
0
    def update_tx_status(self):
        self.tx_status, self.tx_time = get_tx_status(self.txid, self.network, self.created_on)

        # Exit if transaction not mined, otherwise continue
        if (self.tx_status != 'success'):
            return bool(self.tx_status)

        # Get token address from event logs
        if (self.token_address == "0x0"):
            web3 = get_web3(self.network)
            receipt = web3.eth.getTransactionReceipt(self.txid)
            contract = web3.eth.contract(Web3.toChecksumAddress(FACTORY_ADDRESS), abi=ptoken_factory_abi)
            logs = contract.events.NewPToken().processReceipt(receipt)
            self.token_address = logs[0].args.token

            record_ptoken_activity('create_ptoken', self, self.token_owner_profile)
            send_personal_token_created(self.token_owner_profile, self)

        self.update_token_status()
Example #19
0
 def do_execute_subscription_via_web3(self, minutes_to_confirm_within = 5):
     """.Executes the subscription on the blockchain"""
     from dashboard.utils import get_web3
     args = self.get_subscription_hash_arguments()
     tx = self.grant.contract.functions.executeSubscription(
         args['from'],
         args['to'],
         args['tokenAddress'],
         args['tokenAmount'],
         args['periodSeconds'],
         args['gasPrice'],
         args['nonce'],
         args['signature'],
     ).buildTransaction(
         self.helper_tx_dict(minutes_to_confirm_within)
     )
     web3 = get_web3(self.grant.network)
     signed_txn = web3.eth.account.signTransaction(tx, private_key=settings.GRANTS_PRIVATE_KEY)
     return web3.eth.sendRawTransaction(signed_txn.rawTransaction).hex()
Example #20
0
    def update_token_status(self):
        if PTOKEN_ABI and self.token_address:
            web3 = get_web3(self.network, sockets=True)
            contract = web3.eth.contract(Web3.toChecksumAddress(
                self.token_address),
                                         abi=PTOKEN_ABI)
            decimals = 10**contract.functions.decimals().call()
            self.total_minted = contract.functions.totalSupply().call(
            ) // decimals
            self.value = contract.functions.price().call() // decimals

            if self.tx_status == 'success' and self.txid:
                latest = web3.eth.blockNumber
                tx = web3.eth.getTransaction(self.txid)
                if self.last_block == 0:
                    self.last_block = tx['blockNumber']

                redeem_filter = contract.events.Redeemed.createFilter(
                    fromBlock=self.last_block, toBlock=latest)
                purchase_filter = contract.events.Purchased.createFilter(
                    fromBlock=self.last_block, toBlock=latest)
                redeemed = 0
                purchased = 0
                for redeem in redeem_filter.get_all_entries():
                    redeemed += redeem['args']['amountRedeemed']

                for purchase in purchase_filter.get_all_entries():
                    purchased += purchase['args']['amountReceived']

                redeemed = redeemed // decimals
                purchased = purchased // decimals

                self.total_purchased = purchased
                self.total_redeemed = redeemed
                self.total_available = self.total_minted - (
                    self.total_purchased - self.total_redeemed)
                self.redemptions = len(redeem_filter.get_all_entries())
                self.purchases = len(purchase_filter.get_all_entries())

                print(f'REDEEMED: {self.total_redeemed}')
                print(f'PURCHASED: {self.total_purchased}')
                print(f'AVAILABLE: {self.total_available}')
            self.save()
Example #21
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:redeem_bulk_kudos:%s" % kt_id,
                    timeout=LOCK_TIMEOUT):
        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()
            pass
        except Exception as e:
            self.retry(30)
Example #22
0
def forwards_func(apps, schema_editor):
    return  #run me manually
    try:
        Profile = apps.get_model('dashboard', 'Profile')
        print('bounty')
        Bounty = apps.get_model('dashboard', 'Bounty')
        for bounty in Bounty.objects.filter(network='mainnet',
                                            current_bounty=True):
            try_to_link_address_to_profile(Profile,
                                           bounty.bounty_owner_github_username,
                                           bounty.bounty_owner_address)
            for fulfillment in bounty.fulfillments.all():
                try_to_link_address_to_profile(Profile,
                                               fulfillment.fulfiller_address,
                                               fulfillment.fulfiller_address)
        print('fr')
        FaucetRequest = apps.get_model('faucet', 'FaucetRequest')
        for faucet in FaucetRequest.objects.all():
            try_to_link_address_to_profile(Profile, faucet.github_username,
                                           faucet.address)
        print('tip')
        Tip = apps.get_model('dashboard', 'Tip')
        for tip in Tip.objects.filter(network='mainnet').all():
            try:
                try_to_link_address_to_profile(Profile, tip.from_username,
                                               tip.from_address)
                w3 = get_web3(tip.network)
                tx = w3.eth.getTransaction(tip.receive_txid)
                if tx:
                    to = tx['to']
                    try_to_link_address_to_profile(Profile, tip.username, to)
            except:
                pass
        print('ens')
        ENSSubdomainRegistration = apps.get_model('enssubdomain',
                                                  'ENSSubdomainRegistration')
        for ens in ENSSubdomainRegistration.objects.all():
            if ens.profile:
                try_to_link_address_to_profile(Profile, ens.profile.handle,
                                               ens.subdomain_wallet_address)
    except Exception as e:
        print(e)
Example #23
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)
Example #24
0
def get_token_recipient_senders(network, recipient_address, token_address):
    w3 = get_web3(network)

    contract = w3.eth.contract(
        address=token_address,
        abi=erc20_abi,
    )

    # TODO: This can be made less brittle/opaque
    # see usage of contract.events.Transfer.getLogs in
    # commit 99a44cd3036ace8fcd886ed1e96747528f105d10
    # after migrating to web3 >= 5.
    filter_params = _construct_transfer_filter_params(
        recipient_address,
        token_address,
    )

    logs = w3.eth.getLogs(filter_params)

    process_log = compose(_trim_null_address, _extract_sender_address_from_log)

    return [process_log(log) for log in logs]
Example #25
0
    def handle(self, *args, **options):
        # config
        network = options['network']
        _filter = options['kudos_filter']
        live = options['live']
        multiplier = options['multiplier']

        tokens = Token.objects.filter(
            owner_address=settings.KUDOS_OWNER_ACCOUNT,
            contract__network=network)
        if _filter:
            tokens = tokens.filter(name__contains=_filter)
        kudos_contract = KudosContract(network=network)._get_contract()
        w3 = get_web3(network)

        for token in tokens:
            if token.gen != 1:
                continue
            print(token)
            if live:
                _tokenId = token.token_id
                _newPriceFinney = token.price_finney * multiplier
                tx = kudos_contract.functions.setPrice(
                    _tokenId, _newPriceFinney).buildTransaction({
                        'nonce':
                        get_nonce(network, settings.KUDOS_OWNER_ACCOUNT),
                        'gas':
                        47000,
                        'gasPrice':
                        int(
                            recommend_min_gas_price_to_confirm_in_time(5) *
                            10**9),
                        'value':
                        0,
                    })
                signed = w3.eth.account.signTransaction(
                    tx, settings.KUDOS_PRIVATE_KEY)
                txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex()
                print(txid)
Example #26
0
    def handle(self, *args, **kwargs):

        api = twitter.Api(
            consumer_key=settings.TWITTER_CONSUMER_KEY,
            consumer_secret=settings.TWITTER_CONSUMER_SECRET,
            access_token_key=settings.TWITTER_ACCESS_TOKEN,
            access_token_secret=settings.TWITTER_ACCESS_SECRET,
        )

        for grant in Grant.objects.all():
            try:
                if grant.twitter_handle_1:
                    user = api.GetUser(
                        screen_name=grant.twitter_handle_1.replace('@', ''))
                    grant.twitter_handle_1_follower_count = user.followers_count
                    grant.save()
            except Exception as e:
                print(e)
            try:
                if grant.twitter_handle_2:
                    user = api.GetUser(
                        screen_name=grant.twitter_handle_2.replace('@', ''))
                    grant.twitter_handle_2_follower_count = user.followers_count
                    grant.save()
            except Exception as e:
                print(e)

            try:
                if not grant.contract_owner_address:
                    w3 = get_web3('mainnet')
                    grant.contract_owner_address = w3.eth.getTransaction(
                        grant.deploy_tx_id)['from']
                    grant.save()

            except Exception as e:
                print(e)
Example #27
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")
Example #28
0
def receive_tip_v3(request, key, txid, network):
    """Handle the receiving of a tip (the POST).

    Returns:
        TemplateResponse: the UI with the tip confirmed.

    """
    these_tips = Tip.objects.filter(web3_type='v3', txid=txid, network=network)
    tips = these_tips.filter(metadata__reference_hash_for_receipient=key) | these_tips.filter(metadata__reference_hash_for_funder=key)
    tip = tips.first()
    is_authed = request.user.username.lower() == tip.username.lower() or request.user.username.lower() == tip.from_username.lower() or not tip.username
    not_mined_yet = get_web3(tip.network).eth.getBalance(Web3.toChecksumAddress(tip.metadata['address'])) == 0
    did_fail = False
    if not_mined_yet:
        tip.update_tx_status()
        did_fail = tip.tx_status in ['dropped', 'unknown', 'na', 'error']

    if not request.user.is_authenticated or request.user.is_authenticated and not getattr(
        request.user, 'profile', None
    ):
        login_redirect = redirect('/login/github?next=' + request.get_full_path())
        return login_redirect
    num_redemptions = tip.metadata.get("num_redemptions", 0)
    max_redemptions = tip.metadata.get("max_redemptions", 0)
    is_redeemable = not (tip.receive_txid and (num_redemptions >= max_redemptions)) and is_authed
    has_this_user_redeemed = request.user.profile.tip_payouts.filter(tip=tip).count()
    if has_this_user_redeemed:
        is_redeemable = False
    if not is_redeemable:
        messages.info(request, 'This tip has been received already')
    elif not is_authed:
        messages.error(request, f'This tip is for @{tip.username} but you are logged in as @{request.user.username}.  Please logout and log back in as {tip.username}.')
    elif did_fail:
        messages.info(request, f'This tx {tip.txid}, failed.  Please contact the sender and ask them to send the tx again.')
    elif not_mined_yet:
        messages.info(request, f'This tx {tip.txid}, is still mining.  Please wait a moment before submitting the receive form.')
    elif request.POST.get('receive_txid') and is_redeemable:
        params = request.POST

        # db mutations
        try:
            profile = get_profile(tip.username)
            eth_address = params['forwarding_address']
            if not is_valid_eth_address(eth_address):
                eth_address = profile.preferred_payout_address
            if params['save_addr']:
                if profile:
                    profile.preferred_payout_address = eth_address
                    profile.save()
            tip.receive_txid = params['receive_txid']
            tip.receive_tx_status = 'pending'
            tip.receive_address = eth_address
            tip.received_on = timezone.now()
            num_redemptions = tip.metadata.get("num_redemptions", 0)
            # note to future self: to create a tip like this in the future set
            # tip.username
            # tip.metadata.max_redemptions
            # tip.metadata.override_send_amount
            # tip.amount to the amount you want to send 
            # ,"override_send_amount":1,"max_redemptions":29

            num_redemptions += 1
            tip.metadata["num_redemptions"] = num_redemptions
            tip.save()
            record_user_action(tip.from_username, 'receive_tip', tip)
            record_tip_activity(tip, tip.username, 'receive_tip')
            TipPayout.objects.create(
                txid=tip.receive_txid,
                profile=request.user.profile,
                tip=tip,
                )
            messages.success(request, 'This tip has been received')
            is_redeemable = False
            has_this_user_redeemed = True
        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(120), 1),
        'tip': tip,
        'has_this_user_redeemed': has_this_user_redeemed,
        'key': key,
        'is_redeemable': is_redeemable,
        'is_authed': is_authed,
        'disable_inputs': not is_redeemable or not is_authed,
    }

    return TemplateResponse(request, 'onepager/receive.html', params)
Example #29
0
def receive_bulk(request, secret):

    coupons = BulkTransferCoupon.objects.filter(secret=secret)
    if not coupons.exists():
        raise Http404

    coupon = coupons.first()

    if coupon.num_uses_remaining <= 0:
        messages.info(request, f'Sorry but the coupon for a free kudos has has expired.  Contact the person who sent you the coupon link, or you can still purchase one on this page.')
        return redirect(coupon.token.url)

    kudos_transfer = None
    if request.user.is_authenticated:
        redemptions = BulkTransferRedemption.objects.filter(redeemed_by=request.user.profile, coupon=coupon)
        if redemptions.exists():
            kudos_transfer = redemptions.first().kudostransfer

    error = False
    if request.POST:
        try:
            address = Web3.toChecksumAddress(request.POST.get('forwarding_address'))
        except:
            error = "You must enter a valid Ethereum address (so we know where to send your Kudos). Please try again."
        if request.user.is_anonymous:
            error = "You must login."

        if not error:
            user = request.user
            profile = user.profile
            save_addr = request.POST.get('save_addr')
            ip_address = get_ip(request)

            # handle form submission
            if save_addr:
                profile.preferred_payout_address = address
                profile.save()

            kudos_contract_address = Web3.toChecksumAddress(settings.KUDOS_CONTRACT_MAINNET)
            kudos_owner_address = Web3.toChecksumAddress(settings.KUDOS_OWNER_ACCOUNT)
            w3 = get_web3(coupon.token.contract.network)
            contract = w3.eth.contract(Web3.toChecksumAddress(kudos_contract_address), abi=kudos_abi())
            nonce = w3.eth.getTransactionCount(kudos_owner_address)
            tx = contract.functions.clone(address, coupon.token.token_id, 1).buildTransaction({
                'nonce': nonce,
                'gas': 500000,
                'gasPrice': int(recommend_min_gas_price_to_confirm_in_time(2) * 10**9),
                'value': int(coupon.token.price_finney / 1000.0 * 10**18),
            })

            if not profile.trust_profile and profile.github_created_on > (timezone.now() - timezone.timedelta(days=7)):
                messages.error(request, f'Your github profile is too new.  Cannot receive kudos.')
            else:

                signed = w3.eth.account.signTransaction(tx, settings.KUDOS_PRIVATE_KEY)
                txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex()

                with transaction.atomic():
                    kudos_transfer = KudosTransfer.objects.create(
                        emails=[request.user.email],
                        # For kudos, `token` is a kudos.models.Token instance.
                        kudos_token_cloned_from=coupon.token,
                        amount=0,
                        comments_public=coupon.comments_to_put_in_kudos_transfer,
                        ip=ip_address,
                        github_url='',
                        from_name=coupon.sender_profile.handle,
                        from_email='',
                        from_username=coupon.sender_profile.handle,
                        username=profile.handle,
                        network=coupon.token.contract.network,
                        from_address=settings.KUDOS_OWNER_ACCOUNT,
                        is_for_bounty_fulfiller=False,
                        metadata={'coupon_redemption': True, 'nonce': nonce},
                        recipient_profile=profile,
                        sender_profile=coupon.sender_profile,
                        txid=txid,
                        receive_txid=txid,
                        tx_status='pending',
                        receive_tx_status='pending',
                    )

                    # save to DB
                    BulkTransferRedemption.objects.create(
                        coupon=coupon,
                        redeemed_by=profile,
                        ip_address=ip_address,
                        kudostransfer=kudos_transfer,
                        )

                    coupon.num_uses_remaining -= 1
                    coupon.current_uses += 1
                    coupon.save()

                    # send email
                    maybe_market_kudos_to_email(kudos_transfer)


    title = f"Redeem {coupon.token.humanized_name} Kudos from @{coupon.sender_profile.handle}"
    desc = f"This Kudos has been AirDropped to you.  About this Kudos: {coupon.token.description}"
    params = {
        'title': title,
        'card_title': title,
        'card_desc': desc,
        'error': error,
        'avatar_url': coupon.token.img_url,
        'coupon': coupon,
        'user': request.user,
        'is_authed': request.user.is_authenticated,
        'kudos_transfer': kudos_transfer,
        'tweet_text': urllib.parse.quote_plus(f"I just got a {coupon.token.humanized_name} Kudos on @GetGitcoin.  ")
    }
    return TemplateResponse(request, 'transaction/receive_bulk.html', params)
Example #30
0
def receive(request, key, txid, network):
    """Handle the receiving of a kudos (the POST).

    Returns:
        TemplateResponse: the UI with the kudos confirmed

    """
    these_kudos_transfers = KudosTransfer.objects.filter(web3_type='v3', txid=txid, network=network)
    kudos_transfers = these_kudos_transfers.filter(
        Q(metadata__reference_hash_for_receipient=key) |
        Q(metadata__reference_hash_for_funder=key)
    )
    kudos_transfer = kudos_transfers.first()
    if not kudos_transfer:
        raise Http404

    is_authed = kudos_transfer.trust_url or request.user.username.replace('@', '') in [
        kudos_transfer.username.replace('@', ''),
        kudos_transfer.from_username.replace('@', '')
    ]
    not_mined_yet = get_web3(kudos_transfer.network).eth.getBalance(
        Web3.toChecksumAddress(kudos_transfer.metadata['address'])) == 0
    did_fail = False
    if not_mined_yet:
        kudos_transfer.update_tx_status()
        did_fail = kudos_transfer.tx_status in ['dropped', 'unknown', 'na', 'error']

    if not kudos_transfer.trust_url:
        if not request.user.is_authenticated or request.user.is_authenticated and not getattr(
            request.user, 'profile', None
        ):
            login_redirect = redirect('/login/github?next=' + request.get_full_path())
            return login_redirect

    if kudos_transfer.receive_txid:
        messages.info(request, _('This kudos has been received'))
    elif not is_authed:
        messages.error(
            request, f'This kudos is for {kudos_transfer.username} but you are logged in as {request.user.username}.  Please logout and log back in as {kudos_transfer.username}.')
    elif did_fail:
        messages.info(request, f'This tx {kudos_transfer.txid}, failed.  Please contact the sender and ask them to send the tx again.')
    elif not_mined_yet and not request.GET.get('receive_txid'):
        message = mark_safe(
            f'The <a href="https://etherscan.io/tx/{txid}">transaction</a> is still mining.  '
            'Please wait a moment before submitting the receive form.'
        )
        messages.info(request, message)
    elif request.GET.get('receive_txid') and not kudos_transfer.receive_txid:
        params = request.GET

        # db mutations
        try:
            if params['save_addr']:
                profile = get_profile(kudos_transfer.username.replace('@', ''))
                if profile:
                    # TODO: Does this mean that the address the user enters in the receive form
                    # Will overwrite an already existing preferred_payout_address?  Should we
                    # ask the user to confirm this?
                    profile.preferred_payout_address = params['forwarding_address']
                    profile.save()
            kudos_transfer.receive_txid = params['receive_txid']
            kudos_transfer.receive_address = params['forwarding_address']
            kudos_transfer.received_on = timezone.now()
            if request.user.is_authenticated:
                kudos_transfer.recipient_profile = request.user.profile
            kudos_transfer.save()
            record_user_action(kudos_transfer.from_username, 'receive_kudos', kudos_transfer)
            record_kudos_email_activity(kudos_transfer, kudos_transfer.username, 'receive_kudos')
            record_kudos_activity(
                kudos_transfer,
                kudos_transfer.from_username,
                'new_kudos' if kudos_transfer.username else 'new_crowdfund'
            )
            messages.success(request, _('This kudos has been received'))
        except Exception as e:
            messages.error(request, str(e))
            logger.exception(e)

    params = {
        'issueURL': request.GET.get('source'),
        'class': 'receive',
        'gas_price': round(recommend_min_gas_price_to_confirm_in_time(120), 1),
        'kudos_transfer': kudos_transfer,
        'title': f"Receive {kudos_transfer.kudos_token_cloned_from.humanized_name} Kudos" if kudos_transfer and kudos_transfer.kudos_token_cloned_from else _('Receive Kudos'),
        'avatar_url': kudos_transfer.kudos_token_cloned_from.img_url if kudos_transfer and kudos_transfer.kudos_token_cloned_from else None,
        'card_desc': f"You've received a {kudos_transfer.kudos_token_cloned_from.humanized_name} kudos!" if kudos_transfer and kudos_transfer.kudos_token_cloned_from else _('You\'ve received a kudos'),
        'key': key,
        'is_authed': is_authed,
        'disable_inputs': kudos_transfer.receive_txid or not_mined_yet or not is_authed,
        'tweet_text': urllib.parse.quote_plus(f"I just got a {kudos_transfer.kudos_token_cloned_from.humanized_name} Kudos on @GetGitcoin.  ")
    }

    return TemplateResponse(request, 'transaction/receive.html', params)