def test_addr_to_token_valid(self): """Test the dashboard token lookup utility with a valid token.""" token = addr_to_token('0x0000000000000000000000000000000000000000') assert isinstance(token, dict) assert token['addr'] == '0x0000000000000000000000000000000000000000' assert token['name'] == 'ETH' assert token['decimals'] == 18
def amount_per_period_to_gitcoin(self): from dashboard.tokens import addr_to_token token = addr_to_token(self.token_address, self.network) try: decimals = token.get('decimals', 0) return (float(self.gas_price) / 10**decimals) except: return 0
def amount_per_period_to_gitcoin(self): from dashboard.tokens import addr_to_token token = addr_to_token(self.token_address, self.network) # gas prices no longer take this amount times 10**18 decimals if self.created_on > timezone.datetime(2020, 6, 16, 15, 0).replace(tzinfo=pytz.utc): return self.gas_price try: decimals = token.get('decimals', 0) return (float(self.gas_price) / 10**decimals) except: return 0
def get_subscription_hash_arguments(self): """Get the grant subscription hash from web3. Attributes: from (str): Subscription.contributor_address to (str): Grant.admin_address tokenAddress (str): Subscription.token_address tokenAmount (float): Subscription.amount_per_period periodSeconds (int): real_period_seconds in the Subscription model gasPrice (float): Subscription.gas_price nonce (int): The nonce is stored in the Contribution model. its created / managed by sync_geth signature (str): Subscription.contributor_signature Returns: str: The Subscription hash. """ from dashboard.tokens import addr_to_token subs = self grant = subs.grant _from = subs.contributor_address to = grant.admin_address if grant.token_address != '0x0000000000000000000000000000000000000000': tokenAddress = grant.token_address else: tokenAddress = subs.token_address tokenAmount = subs.amount_per_period periodSeconds = subs.real_period_seconds gasPrice = subs.gas_price nonce = subs.get_nonce(_from) signature = subs.contributor_signature # TODO - figure out the number of decimals token = addr_to_token(tokenAddress, subs.grant.network) decimals = token.get('decimals', 0) return { 'from': Web3.toChecksumAddress(_from), 'to': Web3.toChecksumAddress(to), 'tokenAddress': Web3.toChecksumAddress(tokenAddress), 'tokenAmount': int(tokenAmount * 10**decimals), 'periodSeconds': int(periodSeconds), 'gasPrice': int(gasPrice), 'nonce': int(nonce), 'signature': signature, }
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
def get_subscription_hash_arguments(self): """Returns the grants subscription hash (has to get it from web3).""" """ from = Subscription.contributor_address, to = Grant.admin_address, tokenAddress = Subscription.token_address, tokenAmount = Subscription.amount_per_period, periodSeconds = real_period_seconds in the Subscription model gasPrice = Subscription.gas_price, nonce = The nonce is stored in the Contribution model. its created / managed by sync_geth signature = Subscription.contributor_signature """ from dashboard.tokens import addr_to_token subs = self grant = subs.grant _from = subs.contributor_address to = grant.admin_address tokenAddress = subs.token_address tokenAmount = subs.amount_per_period periodSeconds = subs.real_period_seconds gasPrice = subs.gas_price nonce = subs.get_nonce(_from) signature = subs.contributor_signature #TODO - figure out the number of decimals token = addr_to_token(subs.token_address, subs.grant.network) decimals = token.get('decimals', 0) return { 'from': Web3.toChecksumAddress(_from), 'to': Web3.toChecksumAddress(to), 'tokenAddress': Web3.toChecksumAddress(tokenAddress), 'tokenAmount': int(tokenAmount * 10**decimals), 'periodSeconds': int(periodSeconds), 'gasPrice': int(gasPrice * 10**9), 'nonce': int(nonce), 'signature': signature, }
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id): """Handle new Bounty creation in the event of bounty changes. Possible Bounty Stages: 0: Draft 1: Active 2: Dead Returns: dashboard.models.Bounty: The new Bounty object. """ bounty_issuer = bounty_payload.get('issuer', {}) metadata = bounty_payload.get('metadata', {}) # fulfillments metadata will be empty when bounty is first created fulfillments = bounty_details.get('fulfillments', {}) interested_comment_id = None submissions_comment_id = None interested_comment_id = None # start to process out all the bounty data url = bounty_payload.get('webReferenceURL') if url: url = normalize_url(url) else: raise UnsupportedSchemaException( 'No webReferenceURL found. Cannot continue!') # Check if we have any fulfillments. If so, check if they are accepted. # If there are no fulfillments, accepted is automatically False. # Currently we are only considering the latest fulfillment. Std bounties supports multiple. # If any of the fulfillments have been accepted, the bounty is now accepted and complete. accepted = any( [fulfillment.get('accepted') for fulfillment in fulfillments]) with transaction.atomic(): old_bounties = old_bounties.distinct().order_by('created_on') latest_old_bounty = None token_address = bounty_payload.get( 'tokenAddress', '0x0000000000000000000000000000000000000000') token_name = bounty_payload.get('tokenName', '') if not token_name: token = addr_to_token(token_address) if token: token_name = token['name'] for old_bounty in old_bounties: if old_bounty.current_bounty: submissions_comment_id = old_bounty.submissions_comment interested_comment_id = old_bounty.interested_comment old_bounty.current_bounty = False old_bounty.save() latest_old_bounty = old_bounty bounty_kwargs = { 'is_open': True if (bounty_details.get('bountyStage') == 1 and not accepted) else False, 'raw_data': bounty_details, 'metadata': metadata, 'current_bounty': True, 'accepted': accepted, 'interested_comment': interested_comment_id, 'submissions_comment': submissions_comment_id, 'standard_bounties_id': bounty_id, 'num_fulfillments': len(fulfillments), 'value_in_token': bounty_details.get('fulfillmentAmount', Decimal(1.0)) } if not latest_old_bounty: schemes = bounty_payload.get('schemes', {}) bounty_kwargs.update({ # info to xfr over from latest_old_bounty as override fields (this is because sometimes # ppl dont login when they first submit issue and it needs to be overridden) 'web3_created': timezone.make_aware(timezone.datetime.fromtimestamp( bounty_payload.get('created')), timezone=UTC), 'github_url': url, 'token_name': token_name, 'token_address': token_address, 'privacy_preferences': bounty_payload.get('privacy_preferences', {}), 'expires_date': timezone.make_aware(timezone.datetime.fromtimestamp( bounty_details.get('deadline')), timezone=UTC), 'title': bounty_payload.get('title', ''), 'issue_description': bounty_payload.get('description', ' '), 'balance': bounty_details.get('balance'), 'contract_address': bounty_details.get('token'), 'network': bounty_details.get('network'), 'bounty_type': metadata.get('bountyType', ''), 'funding_organisation': metadata.get('fundingOrganisation', ''), 'project_length': metadata.get('projectLength', ''), 'estimated_hours': metadata.get('estimatedHours'), 'experience_level': metadata.get('experienceLevel', ''), 'project_type': schemes.get('project_type', 'traditional'), 'permission_type': schemes.get('permission_type', 'permissionless'), 'attached_job_description': bounty_payload.get('hiring', {}).get('jobDescription', None), 'is_featured': metadata.get('is_featured', False), 'bounty_owner_github_username': bounty_issuer.get('githubUsername', ''), 'bounty_owner_address': bounty_issuer.get('address', ''), 'bounty_owner_email': bounty_issuer.get('email', ''), 'bounty_owner_name': bounty_issuer.get('name', ''), 'admin_override_suspend_auto_approval': not schemes.get('auto_approve_workers', True), }) else: latest_old_bounty_dict = latest_old_bounty.to_standard_dict( fields=[ 'web3_created', 'github_url', 'token_name', 'token_address', 'privacy_preferences', 'expires_date', 'title', 'issue_description', 'balance', 'contract_address', 'network', 'bounty_type', 'project_length', 'experience_level', 'project_type', 'permission_type', 'attached_job_description', 'bounty_owner_github_username', 'bounty_owner_address', 'bounty_owner_email', 'bounty_owner_name', 'github_comments', 'override_status', 'last_comment_date', 'snooze_warnings_for_days', 'admin_override_and_hide', 'admin_override_suspend_auto_approval', 'admin_mark_as_remarket_ready', 'funding_organisation', 'bounty_reserved_for_user', 'is_featured', ], ) if latest_old_bounty_dict['bounty_reserved_for_user']: latest_old_bounty_dict[ 'bounty_reserved_for_user'] = Profile.objects.get( pk=latest_old_bounty_dict['bounty_reserved_for_user']) bounty_kwargs.update(latest_old_bounty_dict) try: new_bounty = Bounty.objects.create(**bounty_kwargs) new_bounty.fetch_issue_item() try: issue_kwargs = get_url_dict(new_bounty.github_url) new_bounty.github_issue_details = get_gh_issue_details( **issue_kwargs) except Exception as e: logger.error(e) # migrate data objects from old bounty if latest_old_bounty: # Pull the interested parties off the last old_bounty for interest in latest_old_bounty.interested.all().nocache(): new_bounty.interested.add(interest) # pull the activities off the last old bounty for activity in latest_old_bounty.activities.all().nocache(): new_bounty.activities.add(activity) bounty_reserved_for_user = metadata.get('reservedFor', '') if bounty_reserved_for_user: new_bounty.reserved_for_user_handle = bounty_reserved_for_user new_bounty.save() if new_bounty.bounty_reserved_for_user: # notify a user that a bounty has been reserved for them new_reserved_issue('*****@*****.**', new_bounty.bounty_reserved_for_user, new_bounty) # set cancel date of this bounty canceled_on = latest_old_bounty.canceled_on if latest_old_bounty and latest_old_bounty.canceled_on else None if not canceled_on and new_bounty.status == 'cancelled': canceled_on = timezone.now() if canceled_on: new_bounty.canceled_on = canceled_on new_bounty.save() except Exception as e: print(e, 'encountered during new bounty creation for:', url) logger.error( f'{e} encountered during new bounty creation for: {url}') new_bounty = None if fulfillments: handle_bounty_fulfillments(fulfillments, new_bounty, latest_old_bounty) for inactive in Bounty.objects.filter( current_bounty=False, github_url=url).nocache().order_by('-created_on'): BountyFulfillment.objects.filter( bounty_id=inactive.id).nocache().delete() return new_bounty
def get_natural_value(self): token = addr_to_token(self.token_address) decimals = token['decimals'] return float(self.value_in_token) / 10**decimals
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id): """Handle new Bounty creation in the event of bounty changes. Possible Bounty Stages: 0: Draft 1: Active 2: Dead Returns: dashboard.models.Bounty: The new Bounty object. """ bounty_issuer = bounty_payload.get('issuer', {}) metadata = bounty_payload.get('metadata', {}) # fulfillments metadata will be empty when bounty is first created fulfillments = bounty_details.get('fulfillments', {}) interested_comment_id = None submissions_comment_id = None interested_comment_id = None # start to process out all the bounty data url = bounty_payload.get('webReferenceURL') if url: url = normalize_url(url) else: raise UnsupportedSchemaException( 'No webReferenceURL found. Cannot continue!') # check conditions for private repos if metadata.get('repo_type', None) == 'private' and \ bounty_payload.get('schemes', {}).get('permission_type', 'permissionless') != 'approval' and \ bounty_payload.get('schemes', {}).get('project_type', 'traditional') != 'traditional': raise UnsupportedSchemaException( 'The project type or permission does not match for private repo') # Check if we have any fulfillments. If so, check if they are accepted. # If there are no fulfillments, accepted is automatically False. # Currently we are only considering the latest fulfillment. Std bounties supports multiple. # If any of the fulfillments have been accepted, the bounty is now accepted and complete. accepted = any( [fulfillment.get('accepted') for fulfillment in fulfillments]) print('create new bounty with payload:{}'.format(bounty_payload)) with transaction.atomic(): old_bounties = old_bounties.distinct().order_by('created_on') latest_old_bounty = None token_address = bounty_payload.get( 'tokenAddress', '0x0000000000000000000000000000000000000000') token_name = bounty_payload.get('tokenName', '') if not token_name: token = addr_to_token(token_address) if token: token_name = token['name'] for old_bounty in old_bounties: if old_bounty.current_bounty: submissions_comment_id = old_bounty.submissions_comment interested_comment_id = old_bounty.interested_comment old_bounty.current_bounty = False old_bounty.save() latest_old_bounty = old_bounty bounty_kwargs = { 'is_open': True if (bounty_details.get('bountyStage') == 1 and not accepted) else False, 'raw_data': bounty_details, 'metadata': metadata, 'current_bounty': True, 'accepted': accepted, 'interested_comment': interested_comment_id, 'submissions_comment': submissions_comment_id, 'standard_bounties_id': bounty_id, 'num_fulfillments': len(fulfillments), 'value_in_token': bounty_details.get('fulfillmentAmount', Decimal(1.0)), 'fee_tx_id': bounty_payload.get('fee_tx_id', '0x0'), 'fee_amount': bounty_payload.get('fee_amount', 0) } coupon_code = bounty_payload.get('coupon_code', None) if coupon_code: coupon = Coupon.objects.filter(code=coupon_code).first() if coupon: bounty_kwargs.update({'coupon_code': coupon}) if not latest_old_bounty: print("no latest old bounty") schemes = bounty_payload.get('schemes', {}) unsigned_nda = None if bounty_payload.get('unsigned_nda', None): unsigned_nda = BountyDocuments.objects.filter( pk=bounty_payload.get('unsigned_nda')).first() bounty_kwargs.update({ # info to xfr over from latest_old_bounty as override fields (this is because sometimes # ppl dont login when they first submit issue and it needs to be overridden) 'web3_created': timezone.make_aware(timezone.datetime.fromtimestamp( bounty_payload.get('created')), timezone=UTC), 'last_remarketed': timezone.make_aware(timezone.datetime.fromtimestamp( bounty_payload.get('created')), timezone=UTC), 'remarketed_count': 0, 'github_url': url, 'token_name': token_name, 'token_address': token_address, 'privacy_preferences': bounty_payload.get('privacy_preferences', {}), 'expires_date': timezone.make_aware(timezone.datetime.fromtimestamp( bounty_details.get('deadline')), timezone=UTC), 'title': bounty_payload.get('title', ''), 'issue_description': bounty_payload.get('description', ' '), 'balance': bounty_details.get('balance'), 'contract_address': bounty_details.get('token'), 'network': bounty_details.get('network'), 'bounty_type': metadata.get('bountyType', ''), 'bounty_categories': metadata.get('bounty_categories', '').split(','), 'funding_organisation': metadata.get('fundingOrganisation', ''), 'project_length': metadata.get('projectLength', ''), 'estimated_hours': metadata.get('estimatedHours'), 'experience_level': metadata.get('experienceLevel', ''), 'project_type': schemes.get('project_type', 'traditional'), 'permission_type': schemes.get('permission_type', 'permissionless'), 'attached_job_description': bounty_payload.get('hiring', {}).get('jobDescription', None), 'is_featured': metadata.get('is_featured', False), 'featuring_date': timezone.make_aware(timezone.datetime.fromtimestamp( metadata.get('featuring_date', 0)), timezone=UTC), 'repo_type': metadata.get('repo_type', 'public'), 'unsigned_nda': unsigned_nda, 'bounty_owner_github_username': bounty_issuer.get('githubUsername', ''), 'bounty_owner_address': bounty_issuer.get('address', ''), 'bounty_owner_email': bounty_issuer.get('email', ''), 'bounty_owner_name': bounty_issuer.get('name', ''), 'admin_override_suspend_auto_approval': not schemes.get('auto_approve_workers', True), 'fee_tx_id': bounty_payload.get('fee_tx_id', '0x0'), 'fee_amount': bounty_payload.get('fee_amount', 0) }) else: # print('latest old bounty found {}'.format(latest_old_bounty)) latest_old_bounty_dict = latest_old_bounty.to_standard_dict( fields=[ 'web3_created', 'github_url', 'token_name', 'token_address', 'privacy_preferences', 'expires_date', 'title', 'issue_description', 'balance', 'contract_address', 'network', 'bounty_type', 'bounty_categories', 'project_length', 'experience_level', 'project_type', 'permission_type', 'attached_job_description', 'bounty_owner_github_username', 'bounty_owner_address', 'bounty_owner_email', 'bounty_owner_name', 'github_comments', 'override_status', 'last_comment_date', 'snooze_warnings_for_days', 'admin_override_and_hide', 'admin_override_suspend_auto_approval', 'admin_mark_as_remarket_ready', 'funding_organisation', 'bounty_reserved_for_user', 'is_featured', 'featuring_date', 'fee_tx_id', 'fee_amount', 'repo_type', 'unsigned_nda', 'coupon_code', 'admin_override_org_name', 'admin_override_org_logo', 'bounty_state' ], ) if latest_old_bounty_dict['bounty_reserved_for_user']: latest_old_bounty_dict[ 'bounty_reserved_for_user'] = Profile.objects.get( pk=latest_old_bounty_dict['bounty_reserved_for_user']) if latest_old_bounty_dict.get('bounty_owner_profile'): latest_old_bounty_dict[ 'bounty_owner_profile'] = Profile.objects.get( pk=latest_old_bounty_dict['bounty_owner_profile']) if latest_old_bounty_dict['unsigned_nda']: latest_old_bounty_dict[ 'unsigned_nda'] = BountyDocuments.objects.filter( pk=latest_old_bounty_dict['unsigned_nda']).first() if latest_old_bounty_dict.get('coupon_code'): latest_old_bounty_dict['coupon_code'] = Coupon.objects.get( pk=latest_old_bounty_dict['coupon_code']) bounty_kwargs.update(latest_old_bounty_dict) try: print('new bounty with kwargs:{}'.format(bounty_kwargs)) new_bounty = Bounty.objects.create(**bounty_kwargs) merge_bounty(latest_old_bounty, new_bounty, metadata, bounty_details) except Exception as e: print(e, 'encountered during new bounty creation for:', url) logger.error( f'{e} encountered during new bounty creation for: {url}') new_bounty = None return new_bounty
def amount_in_wei(tokenAddress, amount): from dashboard.tokens import addr_to_token token = addr_to_token(tokenAddress) decimals = token['decimals'] if token else 18 return float(amount) * 10**decimals
def get_natural_value(self): token = addr_to_token(self.tokenAddress) decimals = token['decimals'] return float(self.amount) / 10**decimals
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id): """Handle new Bounty creation in the event of bounty changes. Possible Bounty Stages: 0: Draft 1: Active 2: Dead Returns: dashboard.models.Bounty: The new Bounty object. """ bounty_issuer = bounty_payload.get('issuer', {}) metadata = bounty_payload.get('metadata', {}) # fulfillments metadata will be empty when bounty is first created fulfillments = bounty_details.get('fulfillments', {}) interested_comment_id = None submissions_comment_id = None interested_comment_id = None # start to process out all the bounty data url = bounty_payload.get('webReferenceURL') if url: url = normalize_url(url) else: raise UnsupportedSchemaException( 'No webReferenceURL found. Cannot continue!') # check conditions for private repos if metadata.get('repo_type', None) == 'private' and \ bounty_payload.get('schemes', {}).get('permission_type', 'permissionless') != 'approval' and \ bounty_payload.get('schemes', {}).get('project_type', 'traditional') != 'traditional': raise UnsupportedSchemaException( 'The project type or permission does not match for private repo') # Check if we have any fulfillments. If so, check if they are accepted. # If there are no fulfillments, accepted is automatically False. # Currently we are only considering the latest fulfillment. Std bounties supports multiple. # If any of the fulfillments have been accepted, the bounty is now accepted and complete. accepted = any( [fulfillment.get('accepted') for fulfillment in fulfillments]) print('create new bounty with payload:{}'.format(bounty_payload)) with transaction.atomic(): old_bounties = old_bounties.distinct().order_by('created_on') latest_old_bounty = None token_address = bounty_payload.get( 'tokenAddress', '0x0000000000000000000000000000000000000000') token_name = bounty_payload.get('tokenName', '') if not token_name: token = addr_to_token(token_address) if token: token_name = token['name'] for old_bounty in old_bounties: if old_bounty.current_bounty: submissions_comment_id = old_bounty.submissions_comment interested_comment_id = old_bounty.interested_comment old_bounty.current_bounty = False old_bounty.save() latest_old_bounty = old_bounty bounty_kwargs = { 'is_open': True if (bounty_details.get('bountyStage') == 1 and not accepted) else False, 'raw_data': bounty_details, 'metadata': metadata, 'current_bounty': True, 'accepted': accepted, 'interested_comment': interested_comment_id, 'submissions_comment': submissions_comment_id, 'standard_bounties_id': bounty_id, 'num_fulfillments': len(fulfillments), 'value_in_token': bounty_details.get('fulfillmentAmount', Decimal(1.0)), 'fee_tx_id': bounty_payload.get('fee_tx_id', '0x0'), 'fee_amount': bounty_payload.get('fee_amount', 0) } if not latest_old_bounty: print("no latest old bounty") schemes = bounty_payload.get('schemes', {}) unsigned_nda = None if bounty_payload.get('unsigned_nda', None): unsigned_nda = BountyDocuments.objects.filter( pk=bounty_payload.get('unsigned_nda')).first() bounty_kwargs.update({ # info to xfr over from latest_old_bounty as override fields (this is because sometimes # ppl dont login when they first submit issue and it needs to be overridden) 'web3_created': timezone.make_aware(timezone.datetime.fromtimestamp( bounty_payload.get('created')), timezone=UTC), 'github_url': url, 'token_name': token_name, 'token_address': token_address, 'privacy_preferences': bounty_payload.get('privacy_preferences', {}), 'expires_date': timezone.make_aware(timezone.datetime.fromtimestamp( bounty_details.get('deadline')), timezone=UTC), 'title': bounty_payload.get('title', ''), 'issue_description': bounty_payload.get('description', ' '), 'balance': bounty_details.get('balance'), 'contract_address': bounty_details.get('token'), 'network': bounty_details.get('network'), 'bounty_type': metadata.get('bountyType', ''), 'funding_organisation': metadata.get('fundingOrganisation', ''), 'project_length': metadata.get('projectLength', ''), 'estimated_hours': metadata.get('estimatedHours'), 'experience_level': metadata.get('experienceLevel', ''), 'project_type': schemes.get('project_type', 'traditional'), 'permission_type': schemes.get('permission_type', 'permissionless'), 'attached_job_description': bounty_payload.get('hiring', {}).get('jobDescription', None), 'is_featured': metadata.get('is_featured', False), 'featuring_date': timezone.make_aware(timezone.datetime.fromtimestamp( metadata.get('featuring_date', 0)), timezone=UTC), 'repo_type': metadata.get('repo_type', 'public'), 'unsigned_nda': unsigned_nda, 'bounty_owner_github_username': bounty_issuer.get('githubUsername', ''), 'bounty_owner_address': bounty_issuer.get('address', ''), 'bounty_owner_email': bounty_issuer.get('email', ''), 'bounty_owner_name': bounty_issuer.get('name', ''), 'admin_override_suspend_auto_approval': not schemes.get('auto_approve_workers', True), 'fee_tx_id': bounty_payload.get('fee_tx_id', '0x0'), 'fee_amount': bounty_payload.get('fee_amount', 0) }) else: print('latest old bounty found {}'.format(latest_old_bounty)) latest_old_bounty_dict = latest_old_bounty.to_standard_dict( fields=[ 'web3_created', 'github_url', 'token_name', 'token_address', 'privacy_preferences', 'expires_date', 'title', 'issue_description', 'balance', 'contract_address', 'network', 'bounty_type', 'project_length', 'experience_level', 'project_type', 'permission_type', 'attached_job_description', 'bounty_owner_github_username', 'bounty_owner_address', 'bounty_owner_email', 'bounty_owner_name', 'github_comments', 'override_status', 'last_comment_date', 'snooze_warnings_for_days', 'admin_override_and_hide', 'admin_override_suspend_auto_approval', 'admin_mark_as_remarket_ready', 'funding_organisation', 'bounty_reserved_for_user', 'is_featured', 'featuring_date', 'fee_tx_id', 'fee_amount', 'repo_type', 'unsigned_nda' ], ) if latest_old_bounty_dict['bounty_reserved_for_user']: latest_old_bounty_dict[ 'bounty_reserved_for_user'] = Profile.objects.get( pk=latest_old_bounty_dict['bounty_reserved_for_user']) if latest_old_bounty_dict.get('bounty_owner_profile'): latest_old_bounty_dict[ 'bounty_owner_profile'] = Profile.objects.get( pk=latest_old_bounty_dict['bounty_owner_profile']) if latest_old_bounty_dict['unsigned_nda']: latest_old_bounty_dict[ 'unsigned_nda'] = BountyDocuments.objects.filter( pk=latest_old_bounty_dict['unsigned_nda']).first() bounty_kwargs.update(latest_old_bounty_dict) try: print('new bounty with kwargs:{}'.format(bounty_kwargs)) new_bounty = Bounty.objects.create(**bounty_kwargs) print('new bounty is:{}'.format(new_bounty.to_standard_dict())) new_bounty.fetch_issue_item() try: issue_kwargs = get_url_dict(new_bounty.github_url) new_bounty.github_issue_details = get_gh_issue_details( **issue_kwargs) except Exception as e: logger.error(e) event_tag = metadata.get('eventTag', '') if event_tag: try: evt = HackathonEvent.objects.filter( name__iexact=event_tag).latest('id') new_bounty.event = evt new_bounty.save() except Exception as e: logger.error(e) bounty_invitees = metadata.get('invite', '') if bounty_invitees and not latest_old_bounty: from marketing.mails import share_bounty from dashboard.utils import get_bounty_invite_url emails = [] inviter = Profile.objects.get( handle=new_bounty.bounty_owner_github_username) invite_url = get_bounty_invite_url(inviter, new_bounty.id) msg = "Check out this bounty that pays out " + \ str(new_bounty.get_value_true) + new_bounty.token_name + invite_url for keyword in new_bounty.keywords_list: msg += " #" + keyword for user_id in bounty_invitees: profile = Profile.objects.get(id=int(user_id)) bounty_invite = BountyInvites.objects.create( status='pending') bounty_invite.bounty.add(new_bounty) bounty_invite.inviter.add(inviter.user) bounty_invite.invitee.add(profile.user) emails.append(profile.email) try: share_bounty(emails, msg, inviter, invite_url, False) response = { 'status': 200, 'msg': 'email_sent', } except Exception as e: logging.exception(e) response = { 'status': 500, 'msg': 'Email not sent', } # migrate data objects from old bounty if latest_old_bounty: # Pull the interested parties off the last old_bounty for interest in latest_old_bounty.interested.all().nocache(): new_bounty.interested.add(interest) # pull the activities off the last old bounty for activity in latest_old_bounty.activities.all().nocache(): new_bounty.activities.add(activity) bounty_reserved_for_user = metadata.get('reservedFor', '') if bounty_reserved_for_user: new_bounty.reserved_for_user_handle = bounty_reserved_for_user new_bounty.save() if new_bounty.bounty_reserved_for_user: # notify a user that a bounty has been reserved for them new_reserved_issue('*****@*****.**', new_bounty.bounty_reserved_for_user, new_bounty) # set cancel date of this bounty canceled_on = latest_old_bounty.canceled_on if latest_old_bounty and latest_old_bounty.canceled_on else None if not canceled_on and new_bounty.status == 'cancelled': canceled_on = timezone.now() if canceled_on: new_bounty.canceled_on = canceled_on new_bounty.save() # preserve featured status for bounties where it was set manually new_bounty.is_featured = True if latest_old_bounty and latest_old_bounty.is_featured is True else False if new_bounty.is_featured == True: new_bounty.save() except Exception as e: print(e, 'encountered during new bounty creation for:', url) logger.error( f'{e} encountered during new bounty creation for: {url}') new_bounty = None if fulfillments: handle_bounty_fulfillments(fulfillments, new_bounty, latest_old_bounty) for inactive in Bounty.objects.filter( current_bounty=False, github_url=url).nocache().order_by('-created_on'): BountyFulfillment.objects.filter( bounty_id=inactive.id).nocache().delete() return new_bounty
def get_natural_value(self): token = addr_to_token(self.token_address) if not token: return 0 decimals = token.get('decimals', 0) return float(self.value_in_token) / 10**decimals
def create_new_bounty(old_bounties, bounty_payload, bounty_details, bounty_id): """Handle new Bounty creation in the event of bounty changes. Possible Bounty Stages: 0: Draft 1: Active 2: Dead Returns: dashboard.models.Bounty: The new Bounty object. """ bounty_issuer = bounty_payload.get('issuer', {}) metadata = bounty_payload.get('metadata', {}) # fulfillments metadata will be empty when bounty is first created fulfillments = bounty_details.get('fulfillments', {}) interested_comment_id = None submissions_comment_id = None interested_comment_id = None # start to process out all the bounty data url = bounty_payload.get('webReferenceURL') if url: url = normalize_url(url) else: raise UnsupportedSchemaException( 'No webReferenceURL found. Cannot continue!') # Check if we have any fulfillments. If so, check if they are accepted. # If there are no fulfillments, accepted is automatically False. # Currently we are only considering the latest fulfillment. Std bounties supports multiple. # If any of the fulfillments have been accepted, the bounty is now accepted and complete. accepted = any( [fulfillment.get('accepted') for fulfillment in fulfillments]) with transaction.atomic(): old_bounties = old_bounties.distinct().order_by('created_on') latest_old_bounty = None token_address = bounty_payload.get( 'tokenAddress', '0x0000000000000000000000000000000000000000') token_name = bounty_payload.get('tokenName', '') if not token_name: token = addr_to_token(token_address) if token: token_name = token['name'] for old_bounty in old_bounties: if old_bounty.current_bounty: submissions_comment_id = old_bounty.submissions_comment interested_comment_id = old_bounty.interested_comment old_bounty.current_bounty = False old_bounty.save() latest_old_bounty = old_bounty try: new_bounty = Bounty.objects.create( title=bounty_payload.get('title', ''), issue_description=bounty_payload.get('description', ' '), web3_created=timezone.make_aware( timezone.datetime.fromtimestamp( bounty_payload.get('created')), timezone=UTC), value_in_token=bounty_details.get('fulfillmentAmount'), token_name=token_name, token_address=token_address, bounty_type=metadata.get('bountyType', ''), project_length=metadata.get('projectLength', ''), experience_level=metadata.get('experienceLevel', ''), github_url=url, # Could also use payload.get('webReferenceURL') bounty_owner_address=bounty_issuer.get('address', ''), bounty_owner_email=bounty_issuer.get('email', ''), bounty_owner_github_username=bounty_issuer.get( 'githubUsername', ''), bounty_owner_name=bounty_issuer.get('name', ''), is_open=True if (bounty_details.get('bountyStage') == 1 and not accepted) else False, raw_data=bounty_details, metadata=metadata, current_bounty=True, contract_address=bounty_details.get('token'), network=bounty_details.get('network'), accepted=accepted, interested_comment=interested_comment_id, submissions_comment=submissions_comment_id, project_type=bounty_payload.get('schemes', {}).get( 'project_type', 'traditional'), permission_type=bounty_payload.get('schemes', {}).get( 'permission_type', 'permissionless'), privacy_preferences=bounty_payload.get('privacy_preferences', {}), # These fields are after initial bounty creation, in bounty_details.js expires_date=timezone.make_aware( timezone.datetime.fromtimestamp( bounty_details.get('deadline')), timezone=UTC), standard_bounties_id=bounty_id, balance=bounty_details.get('balance'), num_fulfillments=len(fulfillments), # info to xfr over from latest_old_bounty github_comments=latest_old_bounty.github_comments if latest_old_bounty else 0, override_status=latest_old_bounty.override_status if latest_old_bounty else '', last_comment_date=latest_old_bounty.last_comment_date if latest_old_bounty else None, snooze_warnings_for_days=latest_old_bounty. snooze_warnings_for_days if latest_old_bounty else 0, admin_override_and_hide=latest_old_bounty. admin_override_and_hide if latest_old_bounty else 0, ) new_bounty.fetch_issue_item() # Pull the interested parties off the last old_bounty if latest_old_bounty: for interest in latest_old_bounty.interested.all(): new_bounty.interested.add(interest) # set cancel date of this bounty canceled_on = latest_old_bounty.canceled_on if latest_old_bounty and latest_old_bounty.canceled_on else None if not canceled_on and new_bounty.status == 'cancelled': canceled_on = timezone.now() if canceled_on: new_bounty.canceled_on = canceled_on new_bounty.save() except Exception as e: print(e, 'encountered during new bounty creation for:', url) logging.error( f'{e} encountered during new bounty creation for: {url}') new_bounty = None if fulfillments: handle_bounty_fulfillments(fulfillments, new_bounty, latest_old_bounty) for inactive in Bounty.objects.filter( current_bounty=False, github_url=url).order_by('-created_on'): BountyFulfillment.objects.filter( bounty_id=inactive.id).delete() return new_bounty
def test_addr_to_token_invalid(self): """Test the dashboard token lookup utility with an invalid token.""" token = addr_to_token('0xGITCOIN') assert isinstance(token, bool) assert token is False