Skip to content

Commit

Permalink
Feature/binance chain integration (#7738)
Browse files Browse the repository at this point in the history
* include binance_ext in models
* update bounty web3_type
* update bountyfulfillment payout_type
* new migration

* feat(sync): get binance tx status; sync payout

* feat(binance): sync payouts via management command

* remove handling of replaced tx

* fix(sync): optimize use of .get

* feat(views): + binance_ext in bounty payout/fulfill

* fix(sync): some optimizations
* .get usage
* save fulfillment on required txn status changes

* fix typo

* fix(binance): set host to gitcoin.co in headers

* feat: update bounty details

- add url for BNB tx
- add url for BNB address
- include BNB tenant

* add placeholders for binance wallet connections

* fix(bounty): fix active class for polkadot selection

* Add BNB svg icon and include BNB token in bounties payable coins.

* fix active class for polkadot selection

* setup binance sync test

* Change to Binance coin

* feat(binance): add util to get wallet address balance

* feat(binance): handle chainChanged and connection events

* feat(binance): fetch connected accounts

* feat(binance): add util to transfer token via extension

* feat(binance): add binance_extension.js; refactor

* fix(model): add binance tenant

* feat(binance): add missing svg

* feat(binance): select binance in hackathon new bounty

- restrict binance to staff only

* feat(sync): save pending transactions; celo/etc

* remove binance init comment

* compress binance.svg with svgo

Co-authored-by: aamustapha <[email protected]>
  • Loading branch information
chibie and amustapha authored Dec 7, 2020
1 parent ae66622 commit e405899
Show file tree
Hide file tree
Showing 21 changed files with 434 additions and 29 deletions.
1 change: 1 addition & 0 deletions app/assets/v2/images/chains/binance.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
126 changes: 126 additions & 0 deletions app/assets/v2/js/lib/binance/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
var binance_utils = {};

binance_utils.getChainVerbose = chainId => {
switch (chainId) {
case 'Binance-Chain-Tigris':
return { name: 'Binance Chain Network', addressType: 'bbc-mainnet' };
case 'Binance-Chain-Ganges':
return { name: 'Binance Chain Test Network', addressType: 'bbc-testnet' };
case '0x38':
return { name: 'Binance Smart Chain Network', addressType: 'eth' };
case '0x61':
return { name: 'Binance Smart Chain Test Network', addressType: 'eth' };
}
}


/**
* Returns wallet's balance on the connected binance network
* @param {String} address
*/
binance_utils.getAddressBalance = async address => {
const isConnected = await BinanceChain.isConnected();

if (!isConnected || !address)
return;

data = {
method: 'eth_getBalance',
params: [address, 'latest']
};

const result = await BinanceChain.request(data);

// convert hex balance to integer and account for decimal points
const bnbBalance = BigInt(result).toString(10) * 10 ** -18;

return Promise.resolve(bnbBalance.toFixed(4));
};


/**
* Get accounts connected in extension
*/
binance_utils.getExtensionConnectedAccounts = async () => {
const isConnected = await BinanceChain.isConnected();

if (!isConnected)
return;

const accounts = await BinanceChain.requestAccounts();

return Promise.resolve(accounts);
};


/**
* Sign and transfer token to another address via extension and returns txn hash
* @param {Number} amount
* @param {String} to_address
* @param {String} from_address : optional, if not passed takes account first account from getExtensionConnectedAccounts
*/
binance_utils.transferViaExtension = async (amount, to_address, from_address) => {

return new Promise(async(resolve, reject) => {

const isConnected = await BinanceChain.isConnected();

if (!isConnected) {
reject(`transferViaExtension: binance hasn't connected to the network ${binance_utils.getChainVerbose(BinanceChain.chainId).name}`);
} else if (!amount) {
reject('transferViaExtension: missing param amount');
} else if (!to_address) {
reject('transferViaExtension: missing param to_address');
}

const chainVerbose = binance_utils.getChainVerbose(BinanceChain.chainId);

if (!from_address) {
const accounts = await binance_utils.getExtensionConnectedAccounts();
from_address = accounts && accounts[0]['addresses'].find(address => address.type === chainVerbose.addressType).address;
}

if (!from_address) {
reject('transferViaExtension: missing param from_address');
}

const account_balance = await binance_utils.getAddressBalance(from_address);

if (Number(account_balance) < amount) {
reject(`transferViaExtension: insufficent balance in address ${from_address}`);
}

if (chainVerbose.addressType === 'eth') {
const params = [
{
from: from_address,
to: to_address,
value: '0x' + amount.toString(16) // convert amount to hex
},
];

BinanceChain
.request({
method: 'eth_sendTransaction',
params
})
.then(txHash => {
resolve(txHash);
})
.catch(error => {
reject('transferViaExtension: something went wrong' + error);
});
}
});
};


/* EVENTS */
BinanceChain.on('connect', info => {
console.log(`connected to ${binance_utils.getChainVerbose(info.chainId).name}!`);
});

BinanceChain.on('chainChanged', chainId => {
console.log(`connected to ${binance_utils.getChainVerbose(chainId).name}!`);
window.location.reload(); // reload page when chain changes
});
52 changes: 52 additions & 0 deletions app/assets/v2/js/pages/bounty_detail/binance_extension.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const payWithBinanceExtension = (fulfillment_id, to_address, vm, modal) => {

const amount = vm.fulfillment_context.amount;
const token_name = vm.bounty.token_name;
const from_address = vm.bounty.bounty_owner_address;

binance_utils.transferViaExtension(
amount * 10 ** vm.decimals,
to_address,
from_address
).then(txn => {
callback(null, from_address, txn);
}).catch(err => {
callback(err);
});

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: 'binance_ext',
tenant: 'BINANCE',
amount: amount,
token_name: token_name,
funder_address: from_address,
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);
});
}
}
}
22 changes: 21 additions & 1 deletion app/assets/v2/js/pages/bounty_details2.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ Vue.mixin({
url = `https://filscan.io/#/tipset/message-detail?cid=${txn}`;
break;

case 'BNB':
url = `https://bscscan.com/tx/${txn}`;
break;

case 'ONE':
url = `https://explorer.harmony.one/#/tx/${txn}`;
break;
Expand Down Expand Up @@ -121,6 +125,10 @@ Vue.mixin({
url = `https://filscan.io/#/tipset/address-detail?address=${address}`;
break;

case 'BNB':
url = `https://bscscan.com/address/${address}`;
break;

case 'ONE':
url = `https://explorer.harmony.one/#/address/${address}`;
break;
Expand Down Expand Up @@ -331,6 +339,10 @@ Vue.mixin({
tenant = 'FILECOIN';
break;

case 'BNB':
tenant = 'BINANCE';
break;

case 'ONE':
tenant = 'HARMONY';
break;
Expand Down Expand Up @@ -410,11 +422,14 @@ Vue.mixin({
payWithPolkadotExtension(fulfillment_id, fulfiller_address, vm, modal);
break;

case 'binance_ext':
payWithBinanceExtension(fulfillment_id, fulfiller_address, vm, modal);
break;

case 'harmony_ext':
payWithHarmonyExtension(fulfillment_id, fulfiller_address, vm, modal);
break;
}

},
closeBounty: function() {

Expand Down Expand Up @@ -622,6 +637,11 @@ Vue.mixin({
break;
}

case 'binance_ext': {
vm.fulfillment_context.active_step = 'payout_amount';
break;
}

case 'harmony_ext':
vm.fulfillment_context.active_step = 'payout_amount';
break;
Expand Down
4 changes: 4 additions & 0 deletions app/assets/v2/js/pages/hackathon_new_bounty.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ Vue.mixin({
// polkadot
type = 'polkadot_ext';
break;
case '56':
// binance
type = 'binance_ext';
break;
case '1000':
// harmony
type = 'harmony_ext';
Expand Down
5 changes: 5 additions & 0 deletions app/assets/v2/js/pages/new_bounty.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ Vue.mixin({
break;
}


default:
break;
}
Expand Down Expand Up @@ -211,6 +212,10 @@ Vue.mixin({
// polkadot
type = 'polkadot_ext';
break;
case '56':
// binance
type = 'binance_ext';
break;
case '1000':
// harmony
type = 'harmony_ext';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,18 @@ def handle(self, *args, **options):
for fulfillment in polkadot_pending_fulfillments.all():
sync_payout(fulfillment)

# binance extension
binance_pending_fulfillments = pending_fulfillments.filter(payout_type='binance_ext')
if binance_pending_fulfillments:
for fulfillment in binance_pending_fulfillments.all():
sync_payout(fulfillment)

# harmony extension
harmony_pending_fulfillments = pending_fulfillments.filter(payout_type='harmony_ext')
if harmony_pending_fulfillments:
for fulfillment in harmony_pending_fulfillments.all():
sync_payout(fulfillment)


# QR
qr_pending_fulfillments = pending_fulfillments.filter(payout_type='qr')
if qr_pending_fulfillments:
Expand Down
23 changes: 23 additions & 0 deletions app/dashboard/migrations/0157_auto_20201021_2319.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 2.2.4 on 2020-10-21 23:19

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dashboard', '0156_auto_20201015_1742'),
]

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'), ('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'), ('manual', 'manual')], help_text='payment type used to make the payment', max_length=20, null=True),
),
]
3 changes: 3 additions & 0 deletions app/dashboard/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ class Bounty(SuperModel):
('qr', 'QR Code'),
('web3_modal', 'Web3 Modal'),
('polkadot_ext', 'Polkadot Ext'),
('binance_ext', 'Binance Ext'),
('harmony_ext', 'Harmony Ext'),
('fiat', 'Fiat'),
('manual', 'Manual')
Expand Down Expand Up @@ -1406,6 +1407,7 @@ class BountyFulfillment(SuperModel):
('fiat', 'fiat'),
('web3_modal', 'web3_modal'),
('polkadot_ext', 'polkadot_ext'),
('binance_ext', 'binance_ext'),
('harmony_ext', 'harmony_ext'),
('manual', 'manual')
]
Expand All @@ -1418,6 +1420,7 @@ class BountyFulfillment(SuperModel):
('CELO', 'CELO'),
('PYPL', 'PYPL'),
('POLKADOT', 'POLKADOT'),
('BINANCE', 'BINANCE'),
('HARMONY', 'HARMONY'),
('FILECOIN', 'FILECOIN'),
('OTHERS', 'OTHERS')
Expand Down
Loading

0 comments on commit e405899

Please sign in to comment.