forked from gitcoinco/web
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
xinfin: bounties integration (gitcoinco#8421)
* feat: integrate xinfin/bounties * add mig file * recreate mig
- Loading branch information
1 parent
323271b
commit 1204af8
Showing
19 changed files
with
325 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
const payWithXinfinExtension = async (fulfillment_id, to_address, vm, modal) => { | ||
|
||
const amount = vm.fulfillment_context.amount; | ||
const token_name = vm.bounty.token_name; | ||
|
||
try { | ||
web3.version.getNetwork(async (err, providerNetworkId) => { | ||
// 1. init provider | ||
await ethereum.enable(); | ||
xdc3Client = await new xdc3(web3.currentProvider); | ||
|
||
// 2. check if default account is selected | ||
if (web3.eth.defaultAccount == null) { | ||
modal.closeModal(); | ||
_alert({ message: 'Please unlock XinPay Wallet extension' }, 'error'); | ||
return; | ||
} | ||
|
||
// 3. check if token is XDC | ||
if (token_name == 'XDC') { | ||
|
||
const xdcBalance = await xdc3Client.eth.getBalance(web3.eth.defaultAccount); | ||
|
||
if (Number(xdcBalance) < Number(amount * 10 ** 18)) { | ||
_alert({ message: `Insufficent balance in address ${web3.eth.defaultAccount}` }, 'error'); | ||
return; | ||
} | ||
|
||
let txArgs = { | ||
to: to_address.toLowerCase(), | ||
from: web3.eth.defaultAccount, | ||
value: (amount * 10 ** 18).toString(), | ||
}; | ||
|
||
xdc3Client.eth.sendTransaction( | ||
txArgs, | ||
(error, result) => callback(error, web3.eth.defaultAccount, result) | ||
); | ||
|
||
} else { | ||
modal.closeModal(); | ||
_alert({ message: 'XinPay supports payouts in XDC only.' }, 'error'); | ||
return; | ||
} | ||
}); | ||
|
||
} catch (e) { | ||
modal.closeModal(); | ||
_alert({ message: 'Please download or enable XinPay Wallet extension' }, 'error'); | ||
return; | ||
} | ||
|
||
function callback(error, from_address, txn) { | ||
if (error) { | ||
_alert({ message: gettext('Unable to payout bounty due to: ' + error) }, 'error'); | ||
console.log(error); | ||
} else { | ||
|
||
const payload = { | ||
payout_type: 'xinfin_ext', | ||
tenant: 'XINFIN', | ||
amount: amount, | ||
token_name: token_name, | ||
funder_address: from_address.replace(/^(0x)/,"xdc"), | ||
payout_tx_id: txn | ||
}; | ||
|
||
modal.closeModal(); | ||
const apiUrlBounty = `/api/v1/bounty/payout/${fulfillment_id}`; | ||
|
||
fetchData(apiUrlBounty, 'POST', payload).then(response => { | ||
if (200 <= response.status && response.status <= 204) { | ||
console.log('success', response); | ||
|
||
vm.fetchBounty(); | ||
_alert('Payment Successful'); | ||
|
||
} else { | ||
_alert('Unable to make payout bounty. Please try again later', 'error'); | ||
console.error(`error: bounty payment failed with status: ${response.status} and message: ${response.message}`); | ||
} | ||
}).catch(function(error) { | ||
_alert('Unable to make payout bounty. Please try again later', 'error'); | ||
console.log(error); | ||
}); | ||
} | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Generated by Django 2.2.4 on 2021-03-24 11:40 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('dashboard', '0174_profile_google_user_id'), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterField( | ||
model_name='bounty', | ||
name='web3_type', | ||
field=models.CharField(choices=[('legacy_gitcoin', 'Legacy Bounty'), ('bounties_network', 'Bounties Network'), ('qr', 'QR Code'), ('web3_modal', 'Web3 Modal'), ('polkadot_ext', 'Polkadot Ext'), ('binance_ext', 'Binance Ext'), ('harmony_ext', 'Harmony Ext'), ('rsk_ext', 'RSK Ext'), ('xinfin_ext', 'Xinfin Ext'), ('fiat', 'Fiat'), ('manual', 'Manual')], default='bounties_network', max_length=50), | ||
), | ||
migrations.AlterField( | ||
model_name='bountyfulfillment', | ||
name='payout_type', | ||
field=models.CharField(blank=True, choices=[('bounties_network', 'bounties_network'), ('qr', 'qr'), ('fiat', 'fiat'), ('web3_modal', 'web3_modal'), ('polkadot_ext', 'polkadot_ext'), ('binance_ext', 'binance_ext'), ('harmony_ext', 'harmony_ext'), ('rsk_ext', 'rsk_ext'), ('xinfin_ext', 'xinfin_ext'), ('manual', 'manual')], help_text='payment type used to make the payment', max_length=20, 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'), ('BINANCE', 'BINANCE'), ('HARMONY', 'HARMONY'), ('FILECOIN', 'FILECOIN'), ('RSK', 'RSK'), ('XINFIN', 'XINFIN'), ('OTHERS', 'OTHERS')], help_text='specific tenant type under the payout_type', max_length=10, null=True), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
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 | ||
|
||
API_KEY = settings.XINFIN_API_KEY | ||
|
||
def find_txn_on_xinfin_explorer(fulfillment): | ||
token_name = fulfillment.token_name | ||
|
||
funderAddress = fulfillment.bounty.bounty_owner_address | ||
amount = fulfillment.payout_amount | ||
payeeAddress = fulfillment.fulfiller_address | ||
|
||
if token_name not in ['XDC']: | ||
return None | ||
|
||
url = f'https://xdc.network/publicAPI?module=account&action=txlist&address={funderAddress}&page=0&pageSize=10&apikey={API_KEY}' | ||
response = requests.get(url).json() | ||
|
||
if response['message'] and response['result']: | ||
for txn in response['result']: | ||
to_address_match = txn['to'].lower() == payeeAddress.lower() if token_name == 'XDC' else True | ||
if ( | ||
txn['from'].lower() == funderAddress.lower() and | ||
to_address_match and | ||
float(txn['value']) == float(amount * 10 ** 18) and | ||
not txn_already_used(txn['hash'], token_name) | ||
): | ||
return txn | ||
return None | ||
|
||
|
||
def get_xinfin_txn_status(fulfillment): | ||
|
||
txnid = fulfillment.payout_tx_id | ||
token_name = fulfillment.token_name | ||
funderAddress = fulfillment.bounty.bounty_owner_address | ||
payeeAddress = fulfillment.fulfiller_address | ||
|
||
amount = fulfillment.payout_amount | ||
|
||
|
||
if token_name not in ['XDC']: | ||
return None | ||
|
||
if not txnid or txnid == "0x0": | ||
return None | ||
|
||
url = f'https://explorer.xinfin.network/publicAPI?module=transaction&action=gettxdetails&txhash={txnid}&apikey={API_KEY}' | ||
response = requests.get(url).json() | ||
|
||
if response['status'] == '0': | ||
return 'expired' | ||
elif response['result']: | ||
txn = response['result'] | ||
|
||
to_address_match = txn['to'].lower() == payeeAddress.lower() if token_name == 'XDC' else True | ||
|
||
if ( | ||
txn['from'].lower() == funderAddress.lower() and | ||
to_address_match and | ||
float(float(txn['value'])/ 10**18) == float(amount) and | ||
not txn_already_used(txn['hash'], token_name) | ||
): | ||
return 'success' | ||
|
||
return None | ||
|
||
|
||
def sync_xinfin_payout(fulfillment): | ||
if not fulfillment.payout_tx_id or fulfillment.payout_tx_id == "0x0": | ||
txn = find_txn_on_xinfin_explorer(fulfillment) | ||
if txn: | ||
fulfillment.payout_tx_id = txn['hash'] | ||
fulfillment.save() | ||
|
||
if fulfillment.payout_tx_id and fulfillment.payout_tx_id != "0x0": | ||
txn_status = get_xinfin_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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.