def send_4(request): """Handle the fourth stage of sending a tip (the POST). Once the metamask transaction is complete, add it to the database. Returns: JsonResponse: response with success state. """ response = { 'status': 'OK', 'message': _('Kudos Sent'), } params = json.loads(request.body) from_username = request.user.username txid = params['txid'] destination_account = params['destinationAccount'] is_direct_to_recipient = params.get('is_direct_to_recipient', False) kudos_transfer = KudosTransfer.objects.get( metadata__address=destination_account, metadata__creation_time=params['creation_time'], metadata__salt=params['salt'], ) # Return Permission Denied if not authenticated is_authenticated_via_login = (kudos_transfer.from_username and kudos_transfer.from_username == from_username) is_authenticated_for_this_via_ip = kudos_transfer.ip == get_ip(request) is_authed = is_authenticated_for_this_via_ip or is_authenticated_via_login if not is_authed: return JsonResponse( { 'status': 'error', 'message': _('Permission Denied') }, status=401) # Save the txid to the database once it has been confirmed in MetaMask. If there is no txid, # it means that the user never went through with the transaction. kudos_transfer.txid = txid kudos_transfer.tx_status = 'pending' if is_direct_to_recipient: kudos_transfer.receive_txid = txid kudos_transfer.receive_tx_status = 'pending' kudos_transfer.save() # notifications maybe_market_kudos_to_email(kudos_transfer) maybe_market_kudos_to_github(kudos_transfer) record_kudos_activity( kudos_transfer, kudos_transfer.from_username, 'new_kudos', ) if is_direct_to_recipient: record_kudos_activity(kudos_transfer, kudos_transfer.username, 'receive_kudos') return JsonResponse(response)
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)
def redeem_bulk_coupon(coupon, profile, address, ip_address, save_addr=False, submit_later=False, exit_after_sending_tx=False, max_gas_price_we_are_willing_to_pay_gwei=15): try: address = Web3.toChecksumAddress(address) except: error = "You must enter a valid Ethereum address (so we know where to send your Kudos). Please try again." return None, error, None # handle form submission kudos_transfer = None if save_addr: profile.preferred_payout_address = address profile.save() private_key = settings.KUDOS_PRIVATE_KEY if not coupon.sender_pk else coupon.sender_pk kudos_owner_address = settings.KUDOS_OWNER_ACCOUNT if not coupon.sender_address else coupon.sender_address gas_price_confirmation_time = 1 if not coupon.sender_address else 60 gas_price_multiplier = 1.3 if not coupon.sender_address else 1 kudos_contract_address = Web3.toChecksumAddress( settings.KUDOS_CONTRACT_MAINNET) kudos_owner_address = Web3.toChecksumAddress(kudos_owner_address) 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) gas_price = int( int( recommend_min_gas_price_to_confirm_in_time( gas_price_confirmation_time) * 10**9) * gas_price_multiplier) tx = contract.functions.clone( address, coupon.token.token_id, 1).buildTransaction({ 'nonce': nonce, 'gas': 500000, 'gasPrice': gas_price, 'value': int(coupon.token.price_finney / 1000.0 * 10**18), }) if not profile.is_brightid_verified and not profile.is_twitter_verified and not profile.trust_profile and profile.github_created_on > ( timezone.now() - timezone.timedelta(days=7)): error = f'Your github profile is too new, so you cannot receive kudos. Please verifiy your profile on BrightID and/or Twitter to proceed.' return None, error, None else: if profile.bulk_transfer_redemptions.filter(coupon=coupon).exists(): error = f'You have already redeemed this kudos.' return None, error, None signed = w3.eth.account.signTransaction(tx, private_key) retry_later = False tx_status = 'pending' if submit_later: txid = '' tx_status = 'not_subed' else: try: # TODO - in the future, override this if the user pays for expediated processing if recommend_min_gas_price_to_confirm_in_time( 1) > max_gas_price_we_are_willing_to_pay_gwei: if coupon.token.contract.network == 'mainnet': raise Exception( "gas price is too high. try again when its not pls" ) txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex() except Exception as e: txid = "pending_celery" retry_later = True if exit_after_sending_tx: return txid, None, None with transaction.atomic(): kudos_transfer = KudosTransfer.objects.create( emails=[profile.email], # For kudos, `token` is a kudos.models.Token instance. kudos_token_cloned_from=coupon.token, amount=coupon.token.price_in_eth, 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=kudos_owner_address, 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=tx_status, receive_tx_status=tx_status, receive_address=address, ) # 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() # user actions record_user_action(kudos_transfer.username, 'new_kudos', kudos_transfer) record_user_action(kudos_transfer.from_username, 'receive_kudos', kudos_transfer) record_kudos_activity(kudos_transfer, kudos_transfer.username, 'receive_kudos') # send email maybe_market_kudos_to_email(kudos_transfer) if retry_later: redeem_bulk_kudos.delay(kudos_transfer.id) return True, None, kudos_transfer
def redeem_bulk_coupon(coupon, profile, address, ip_address, save_addr=False): try: address = Web3.toChecksumAddress(address) except: error = "You must enter a valid Ethereum address (so we know where to send your Kudos). Please try again." return None, error, None # handle form submission kudos_transfer = None if save_addr: profile.preferred_payout_address = address profile.save() private_key = settings.KUDOS_PRIVATE_KEY if not coupon.sender_pk else coupon.sender_pk kudos_owner_address = settings.KUDOS_OWNER_ACCOUNT if not coupon.sender_address else coupon.sender_address gas_price_confirmation_time = 1 if not coupon.sender_address else 60 kudos_contract_address = Web3.toChecksumAddress(settings.KUDOS_CONTRACT_MAINNET) kudos_owner_address = Web3.toChecksumAddress(kudos_owner_address) 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(gas_price_confirmation_time) * 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)): error = f'Your github profile is too new. Cannot receive kudos.' return None, error, None else: signed = w3.eth.account.signTransaction(tx, private_key) retry_later = False try: txid = w3.eth.sendRawTransaction(signed.rawTransaction).hex() except Exception as e: txid = "pending_celery" retry_later = True with transaction.atomic(): kudos_transfer = KudosTransfer.objects.create( emails=[profile.email], # For kudos, `token` is a kudos.models.Token instance. kudos_token_cloned_from=coupon.token, amount=coupon.token.price_in_eth, 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=kudos_owner_address, 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() # user actions record_user_action(kudos_transfer.username, 'new_kudos', kudos_transfer) record_user_action(kudos_transfer.from_username, 'receive_kudos', kudos_transfer) # send email maybe_market_kudos_to_email(kudos_transfer) if retry_later: from kudos.tasks import redeem_bulk_kudos redeem_bulk_kudos.delay(kudos_transfer.id, signed.rawTransaction.hex()) return True, None, kudos_transfer