From 4f6ed0f620c144edb66a666029450184a1585920 Mon Sep 17 00:00:00 2001 From: Aditya Anand M C Date: Mon, 12 Oct 2020 13:58:49 +0530 Subject: [PATCH 1/2] remove print --- app/dashboard/models.py | 8 -------- app/dashboard/notifications.py | 4 ---- app/dashboard/views.py | 1 - 3 files changed, 13 deletions(-) diff --git a/app/dashboard/models.py b/app/dashboard/models.py index b3bd88eaa37..ca621ae39fb 100644 --- a/app/dashboard/models.py +++ b/app/dashboard/models.py @@ -1092,21 +1092,13 @@ def is_notification_eligible(self, var_to_check=True): bool: Whether or not the Bounty is eligible for outbound notifications. """ - print(f'### GITCOIN BOT A2 network {self.network}') - print(f'### GITCOIN BOT A2 settings.DEBUG {settings.DEBUG}') - print(f'### GITCOIN BOT A2 settings.ENV {settings.ENV}') if self.network != settings.ENABLE_NOTIFICATIONS_ON_NETWORK: return False - print(f'### GITCOIN BOT A3') - if self.network == 'mainnet' and (settings.DEBUG or settings.ENV != 'prod'): return False - print(f'### GITCOIN BOT A4') - - print(f'### GITCOIN BOT A5 - Is Eligible') return True @property diff --git a/app/dashboard/notifications.py b/app/dashboard/notifications.py index ddda0d8024b..5e02385da3d 100644 --- a/app/dashboard/notifications.py +++ b/app/dashboard/notifications.py @@ -603,12 +603,9 @@ def maybe_market_to_github(bounty, event_name, profile_pairs=None): bool: Whether or not the Github comment was posted successfully. """ - print('### GITCOIN BOT A1') if not bounty.is_notification_eligible(var_to_check=settings.GITHUB_CLIENT_ID): - print(f'### GITCOIN BOT A6 NOT POSTING') return False - print(f'### GITCOIN BOT A6') # Define posting specific variables. comment_id = None url = bounty.github_url @@ -617,7 +614,6 @@ def maybe_market_to_github(bounty, event_name, profile_pairs=None): # Prepare the comment message string. msg = build_github_notification(bounty, event_name, profile_pairs) - print(f'### GITCOIN BOT A7 {msg}') if not msg: return False diff --git a/app/dashboard/views.py b/app/dashboard/views.py index b47ef1a176b..de813c78f93 100644 --- a/app/dashboard/views.py +++ b/app/dashboard/views.py @@ -5417,7 +5417,6 @@ def create_bounty_v1(request): event_name = 'new_bounty' record_bounty_activity(bounty, user, event_name) maybe_market_to_email(bounty, event_name) - print('### GITCOIN BOT A0') maybe_market_to_github(bounty, event_name) response = { From 152424a7a8acdf5eae0ca485b8aa9feeb72ee4e1 Mon Sep 17 00:00:00 2001 From: Aditya Anand M C Date: Mon, 12 Oct 2020 16:48:44 +0530 Subject: [PATCH 2/2] feat: integrate FIL coin --- app/assets/v2/images/chains/filecoin.svg | 1 + app/assets/v2/js/pages/bounty_details2.js | 18 +++ .../v2/js/pages/hackathon_new_bounty.js | 1 + app/assets/v2/js/pages/new_bounty.js | 1 + .../migrations/0154_auto_20201012_1044.py | 33 +++++ app/dashboard/models.py | 7 +- app/dashboard/sync/filecoin.py | 118 ++++++++++++++++++ .../templates/bounty/new_bounty.html | 6 +- .../dashboard/hackathon/new_bounty.html | 6 +- app/dashboard/utils.py | 3 + 10 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 app/assets/v2/images/chains/filecoin.svg create mode 100644 app/dashboard/migrations/0154_auto_20201012_1044.py create mode 100644 app/dashboard/sync/filecoin.py diff --git a/app/assets/v2/images/chains/filecoin.svg b/app/assets/v2/images/chains/filecoin.svg new file mode 100644 index 00000000000..993b711efc4 --- /dev/null +++ b/app/assets/v2/images/chains/filecoin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/v2/js/pages/bounty_details2.js b/app/assets/v2/js/pages/bounty_details2.js index 2f012482586..3143fe71fd6 100644 --- a/app/assets/v2/js/pages/bounty_details2.js +++ b/app/assets/v2/js/pages/bounty_details2.js @@ -74,6 +74,10 @@ Vue.mixin({ url = `https://kusama.subscan.io/extrinsic/${txn}`; break; + case 'FIL': + url = `https://filscan.io/#/tipset/message-detail?cid=${txn}`; + break; + default: url = `https://etherscan.io/tx/${txn}`; @@ -109,6 +113,10 @@ Vue.mixin({ url = `https://kusama.subscan.io/account/${address}`; break; + case 'FIL': + url = `https://filscan.io/#/tipset/address-detail?address=${address}`; + break; + default: url = `https://etherscan.io/address/${address}`; } @@ -144,6 +152,12 @@ Vue.mixin({ `zilliqa://${address}?amount=${value}` : `zilliqa://${address}`; break; + + case 'FIL': + qr_string = value ? + `filecoin://${address}?amount=${value}` : + `filecoin://${address}`; + break; } return qr_string; @@ -305,6 +319,10 @@ Vue.mixin({ tenant = 'POLKADOT'; break; + case 'FIL': + tenant = 'FILECOIN'; + break; + default: tenant = 'ETH'; } diff --git a/app/assets/v2/js/pages/hackathon_new_bounty.js b/app/assets/v2/js/pages/hackathon_new_bounty.js index 3818fb5f68d..3c63949a2af 100644 --- a/app/assets/v2/js/pages/hackathon_new_bounty.js +++ b/app/assets/v2/js/pages/hackathon_new_bounty.js @@ -185,6 +185,7 @@ Vue.mixin({ case '0': // bitcoin case '61': // ethereum classic case '102': // zilliqa + case '600': // filecoin case '42220': // celo mainnet case '44786': // celo alfajores tesnet type = 'qr'; diff --git a/app/assets/v2/js/pages/new_bounty.js b/app/assets/v2/js/pages/new_bounty.js index 1e891ee7433..5ab5bff0ce7 100644 --- a/app/assets/v2/js/pages/new_bounty.js +++ b/app/assets/v2/js/pages/new_bounty.js @@ -198,6 +198,7 @@ Vue.mixin({ case '0': // bitcoin case '61': // ethereum classic case '102': // zilliqa + case '600': // filecoin case '42220': // celo mainnet case '44786': // celo alfajores tesnet case '717171': // other diff --git a/app/dashboard/migrations/0154_auto_20201012_1044.py b/app/dashboard/migrations/0154_auto_20201012_1044.py new file mode 100644 index 00000000000..881b9e2401a --- /dev/null +++ b/app/dashboard/migrations/0154_auto_20201012_1044.py @@ -0,0 +1,33 @@ +# Generated by Django 2.2.4 on 2020-10-12 10:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dashboard', '0153_hackathonevent_use_circle'), + ] + + operations = [ + migrations.AlterField( + model_name='bounty', + name='bounty_owner_address', + field=models.CharField(blank=True, max_length=100, null=True), + ), + migrations.AlterField( + model_name='bountyfulfillment', + name='fulfiller_address', + field=models.CharField(blank=True, help_text='address to which amount is credited', max_length=100, null=True), + ), + migrations.AlterField( + model_name='bountyfulfillment', + name='funder_address', + field=models.CharField(blank=True, help_text='address from which amount is deducted', max_length=100, null=True), + ), + migrations.AlterField( + model_name='bountyfulfillment', + name='tenant', + field=models.CharField(blank=True, choices=[('BTC', 'BTC'), ('ETH', 'ETH'), ('ETC', 'ETC'), ('ZIL', 'ZIL'), ('CELO', 'CELO'), ('PYPL', 'PYPL'), ('POLKADOT', 'POLKADOT'), ('FILECOIN', 'FILECOIN'), ('OTHERS', 'OTHERS')], help_text='specific tenant type under the payout_type', max_length=10, null=True), + ), + ] diff --git a/app/dashboard/models.py b/app/dashboard/models.py index ca621ae39fb..c564cd1ed1f 100644 --- a/app/dashboard/models.py +++ b/app/dashboard/models.py @@ -308,7 +308,7 @@ class Bounty(SuperModel): github_url = models.URLField(db_index=True) github_issue_details = JSONField(default=dict, blank=True, null=True) github_comments = models.IntegerField(default=0) - bounty_owner_address = models.CharField(max_length=50, blank=True, null=True) + bounty_owner_address = models.CharField(max_length=100, blank=True, null=True) bounty_owner_email = models.CharField(max_length=255, blank=True) bounty_owner_github_username = models.CharField(max_length=255, blank=True, db_index=True) bounty_owner_name = models.CharField(max_length=255, blank=True) @@ -1410,6 +1410,7 @@ class BountyFulfillment(SuperModel): ('CELO', 'CELO'), ('PYPL', 'PYPL'), ('POLKADOT', 'POLKADOT'), + ('FILECOIN', 'FILECOIN'), ('OTHERS', 'OTHERS') ] @@ -1421,8 +1422,8 @@ class BountyFulfillment(SuperModel): # TODO: RETIRE fulfiller_metadata = JSONField(default=dict, blank=True) - fulfiller_address = models.CharField(max_length=50, null=True, blank=True, help_text="address to which amount is credited") - funder_address = models.CharField(max_length=50, null=True, blank=True, help_text="address from which amount is deducted") + fulfiller_address = models.CharField(max_length=100, null=True, blank=True, help_text="address to which amount is credited") + funder_address = models.CharField(max_length=100, null=True, blank=True, help_text="address from which amount is deducted") # TODO: rename to fulfiller_profile profile = models.ForeignKey('dashboard.Profile', related_name='fulfilled', on_delete=models.CASCADE, null=True, help_text="fulfillers's profile") diff --git a/app/dashboard/sync/filecoin.py b/app/dashboard/sync/filecoin.py new file mode 100644 index 00000000000..f45084b6cef --- /dev/null +++ b/app/dashboard/sync/filecoin.py @@ -0,0 +1,118 @@ +import json + +from django.conf import settings +from django.utils import timezone + +import requests +from dashboard.sync.helpers import record_payout_activity, txn_already_used + +headers = { + 'Host': 'gitcoin.co' +} + +def find_txn_on_filecoin_explorer(fulfillment): + token_name = fulfillment.token_name + payeeAddress = fulfillment.fulfiller_address + + if token_name != 'FIL': + return None + + url = 'https://api.filscan.io:8700/rpc/v1' + + data = { + "id": 1, + "jsonrpc": "2.0", + "params": [ + { + "address": payeeAddress, + "offset_range": { + "start": 0, + "count": 25 + } + } + ], + "method": "filscan.MessageByAddress" + } + + response = requests.post(url, headers=headers, data=json.dumps(data)).json() + if ( + response and + 'result' in response and + 'data' in response['result'] + ): + for txn in response['result']['data']: + if ( + isValidTxn(fulfillment, txn) == 'success' and + not txn_already_used(txn['cid'], token_name) + ): + return txn + return None + + +def get_filecoin_txn_status(fulfillment): + + txnid = fulfillment.payout_tx_id + token_name = fulfillment.token_name + + if token_name != 'FIL': + return None + + if not txnid or txnid == "0x0": + return None + + url = 'https://api.filscan.io:8700/rpc/v1' + + data = { + "id": 1, + "jsonrpc": "2.0", + "params": [ txnid ], + "method": "filscan.MessageDetails" + } + + filscan_response = requests.post(url, headers=headers, data=json.dumps(data)).json() + if filscan_response and 'result' in filscan_response: + txn = filscan_response['result'] + if 'exit_code' in txn: + return 'expired' + elif isValidTxn(fulfillment, txn): + return 'success' + + return None + + +def sync_filecoin_payout(fulfillment): + if not fulfillment.payout_tx_id or fulfillment.payout_tx_id == "0x0": + txn = find_txn_on_filecoin_explorer(fulfillment) + if txn: + fulfillment.payout_tx_id = txn['cid'] + fulfillment.save() + + if fulfillment.payout_tx_id: + txn_status = get_filecoin_txn_status(fulfillment) + + if txn_status == 'success': + fulfillment.payout_status = 'done' + fulfillment.accepted_on = timezone.now() + fulfillment.accepted = True + record_payout_activity(fulfillment) + + elif txn_status == 'expired': + fulfillment.payout_status = 'expired' + + fulfillment.save() + + +def isValidTxn(fulfillment, txn): + funderAddress = fulfillment.bounty.bounty_owner_address + amount = fulfillment.payout_amount + payeeAddress = fulfillment.fulfiller_address + + if ( + txn['from'] == funderAddress.lower() and + txn['to'] == payeeAddress.lower() and + float(txn['value']) == float(amount) and + txn['method_name'] == 'transfer' + ): + return True + + return False diff --git a/app/dashboard/templates/bounty/new_bounty.html b/app/dashboard/templates/bounty/new_bounty.html index 888f5cbcbef..09297cc599e 100644 --- a/app/dashboard/templates/bounty/new_bounty.html +++ b/app/dashboard/templates/bounty/new_bounty.html @@ -92,7 +92,11 @@

Fund Issue

{% if is_staff %} + +