Skip to content

Commit

Permalink
feat(binance): integrate BUSD for bounties and hackathons (#8121)
Browse files Browse the repository at this point in the history
* feat: include BUSD case in bounty detail

* process BUSD token transfer

* refactor utils + token balance checks

- add util to get token balance

- enforce sufficient balance for transfer

* litte refactor

* use only jsonRpcRequest util

* fix: amount comparison for insufficient balance

* add util to get selected account

* use only getSelectedAccount util

* autofill funderAddress with selected account
  • Loading branch information
chibie authored Dec 22, 2020
1 parent 0cc7ce5 commit 78d5ba7
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 41 deletions.
164 changes: 125 additions & 39 deletions app/assets/v2/js/lib/binance/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ binance_utils.getChainVerbose = chainId => {
}
}

async function jsonRpcRequest(method, params) {
return new Promise(async (resolve, reject) => {
BinanceChain
.request({ method, params })
.then(result => {
resolve(result);
})
.catch(error => {
reject(error);
});
});
}

/**
* Returns wallet's balance on the connected binance network
Expand All @@ -24,17 +36,45 @@ binance_utils.getAddressBalance = async address => {
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));
const result = await jsonRpcRequest('eth_getBalance', [address, 'latest']);

// convert hex balance to integer
const bnbBalance = BigInt(result).toString(10);

return Promise.resolve(bnbBalance);
};

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

if (!isConnected || !address || !tokenContractAddress)
return;

const methodSignature = await jsonRpcRequest(
'web3_sha3',
['balanceOf(address)']
);
const method_id = methodSignature.substr(0, 10);
const address = address.substr(2).padStart(64, '0'); // remove 0x and pad with zeroes

const params = [
{
to: tokenContractAddress,
data: method_id + address
},
'latest'
]
const result = await jsonRpcRequest('eth_call', params);

// convert hex balance to integer
const tokenBalance = BigInt(result).toString(10);

return Promise.resolve(tokenBalance);
};


Expand All @@ -53,15 +93,27 @@ binance_utils.getExtensionConnectedAccounts = async () => {
};


/**
* Get selected account connected in extension
*/
binance_utils.getSelectedAccount = async () => {
const chainVerbose = binance_utils.getChainVerbose(BinanceChain.chainId);
const accounts = await binance_utils.getExtensionConnectedAccounts();
address = accounts && accounts[0]['addresses'].find(address => address.type === chainVerbose.addressType).address;
return address
}


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

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

const isConnected = await BinanceChain.isConnected();

Expand All @@ -76,40 +128,74 @@ binance_utils.transferViaExtension = async (amount, to_address, from_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;
from_address = await binance_utils.getSelectedAccount();
}

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 (!token_name) {
token_name = 'BNB';
}

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 => {
if (token_name === 'BNB') {

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
},
];

try {
const txHash = await jsonRpcRequest('eth_sendTransaction', params)
resolve(txHash)
} catch (error) {
reject('transferViaExtension: something went wrong' + error);
}
}

} else if (token_name === 'BUSD') {

const account_balance = await binance_utils.getAddressTokenBalance(from_address);

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

if (chainVerbose.addressType === 'eth') {
try {
const methodSignature = await jsonRpcRequest(
'web3_sha3',
['transfer(address, uint256)']
);
const method_id = methodSignature.substr(0, 10);
const amount = amount.toString(16).padStart(64, '0'); // convert to hex and pad with zeroes
const to_address = to_address.substr(2).padStart(64, '0'); // remove 0x and pad with zeroes

const params = [
{
from: from_address,
to: '0xe9e7cea3dedca5984780bafc599bd69add087d56', // BUSD token contract address
data: method_id + to_address + amount
},
]
const txHash = await jsonRpcRequest('eth_sendTransaction', params);

resolve(txHash);
})
.catch(error => {
} catch (error) {
reject('transferViaExtension: something went wrong' + error);
});
}
}
}
});
};
Expand Down
3 changes: 2 additions & 1 deletion app/assets/v2/js/pages/bounty_detail/binance_extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const payWithBinanceExtension = (fulfillment_id, to_address, vm, modal) => {
binance_utils.transferViaExtension(
amount * 10 ** vm.decimals,
to_address,
from_address
from_address,
vm.bounty.token_name
).then(txn => {
callback(null, from_address, txn);
}).catch(err => {
Expand Down
3 changes: 3 additions & 0 deletions app/assets/v2/js/pages/bounty_details2.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Vue.mixin({
break;

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

Expand Down Expand Up @@ -126,6 +127,7 @@ Vue.mixin({
break;

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

Expand Down Expand Up @@ -340,6 +342,7 @@ Vue.mixin({
break;

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

Expand Down
9 changes: 9 additions & 0 deletions app/assets/v2/js/pages/new_bounty.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ Vue.mixin({
});

},
getBinanceSelectedAccount: async function() {
let vm = this;

vm.form.funderAddress = await binance_utils.getSelectedAccount();
},
getAmount: function(token) {
let vm = this;

Expand Down Expand Up @@ -680,6 +685,10 @@ Vue.mixin({
await onConnect();
}

if (val === '56') {
this.getBinanceSelectedAccount();
}

this.getTokens();
}
}
Expand Down
2 changes: 1 addition & 1 deletion app/dashboard/templates/bounty/new_bounty.html
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ <h1 class="text-center">Fund Issue</h1>
</div>
</div>

<div class="funder-address-container mt-4" v-show="chainId !== '1'">
<div class="funder-address-container mt-4" v-show="chainId !== '1' && chainId !== '56'">
<label class="font-caption letter-spacing text-black-60 text-uppercase" for="funderAddress">Funder Address</label>
<input name="funderAddress" id="funderAddress" class="form__input" type="text" placeholder="Address with which the bounty will be paid out" v-model="form.funderAddress">
<div class="text-danger" v-if="errors.funderAddress && (!form.funderAddress || chainId === '0')">
Expand Down

0 comments on commit 78d5ba7

Please sign in to comment.