Merge branch 'ranchimall:master' into master
This commit is contained in:
commit
0f579c5d15
@ -871,6 +871,7 @@ theme-toggle {
|
|||||||
.page > h3.heading {
|
.page > h3.heading {
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.balance-card {
|
.balance-card {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -1059,7 +1060,7 @@ theme-toggle {
|
|||||||
|
|
||||||
.info-row {
|
.info-row {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#participant_container,
|
#participant_container,
|
||||||
|
|||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -964,7 +964,7 @@ theme-toggle {
|
|||||||
}
|
}
|
||||||
.info-row {
|
.info-row {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1.3rem;
|
||||||
}
|
}
|
||||||
#participant_container,
|
#participant_container,
|
||||||
#deposits_container {
|
#deposits_container {
|
||||||
|
|||||||
96
index.html
96
index.html
@ -10,11 +10,13 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
|
||||||
<script src="https://unpkg.com/uhtml@3.0.1/es.js"></script>
|
<script src="https://unpkg.com/uhtml@3.0.1/es.js"></script>
|
||||||
<script src="components.min.js"></script>
|
<script src="scripts/components.min.js"></script>
|
||||||
|
<script src="scripts/lib.js" defer></script>
|
||||||
|
<script src="scripts/floCrypto.js" defer></script>
|
||||||
<link rel="shortcut icon" href="floscout.svg" type="image/x-icon">
|
<link rel="shortcut icon" href="floscout.svg" type="image/x-icon">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body data-theme="light" class="hidden">
|
<body class="hidden">
|
||||||
<sm-notifications id="notification_drawer"></sm-notifications>
|
<sm-notifications id="notification_drawer"></sm-notifications>
|
||||||
<div id="loading">
|
<div id="loading">
|
||||||
<sm-spinner></sm-spinner>
|
<sm-spinner></sm-spinner>
|
||||||
@ -189,7 +191,6 @@
|
|||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// window.addEventListener('hashchange', e => routeTo(window.location.hash))
|
|
||||||
window.addEventListener("load", () => {
|
window.addEventListener("load", () => {
|
||||||
document.body.classList.remove('hidden')
|
document.body.classList.remove('hidden')
|
||||||
document.addEventListener("pointerdown", (e) => {
|
document.addEventListener("pointerdown", (e) => {
|
||||||
@ -336,9 +337,9 @@
|
|||||||
const renderedBlocks = latestBlocks.map(block => render.blockCard(block))
|
const renderedBlocks = latestBlocks.map(block => render.blockCard(block))
|
||||||
renderElem(document.getElementById('top_blocks_container'), html`${renderedBlocks}`)
|
renderElem(document.getElementById('top_blocks_container'), html`${renderedBlocks}`)
|
||||||
}
|
}
|
||||||
router.addRoute('', (state) => {
|
router.addRoute('', async (state) => {
|
||||||
history.replaceState({}, '', '#/home')
|
history.replaceState({}, '', '#/home')
|
||||||
renderHome(state)
|
await renderHome(state)
|
||||||
})
|
})
|
||||||
router.addRoute('home', renderHome)
|
router.addRoute('home', renderHome)
|
||||||
router.addRoute('address', async state => {
|
router.addRoute('address', async state => {
|
||||||
@ -378,7 +379,7 @@
|
|||||||
if (!contractId) return;
|
if (!contractId) return;
|
||||||
const contract = splitContractNameAddress(contractId);
|
const contract = splitContractNameAddress(contractId);
|
||||||
const contractInfo = await getContractInfo(contract)
|
const contractInfo = await getContractInfo(contract)
|
||||||
const { contractType, contractSubtype, accepting_token, selling_token } = contractInfo
|
const { contractType, contractSubtype, acceptingToken, sellingToken } = contractInfo
|
||||||
const detailsToFetch = [getContractTransactions(contract), getContractParticipants(contract)]
|
const detailsToFetch = [getContractTransactions(contract), getContractParticipants(contract)]
|
||||||
if (contractType === 'continuos-event' && contractSubtype === 'tokenswap')
|
if (contractType === 'continuos-event' && contractSubtype === 'tokenswap')
|
||||||
detailsToFetch.push(getContractDeposits(contract))
|
detailsToFetch.push(getContractDeposits(contract))
|
||||||
@ -426,8 +427,8 @@
|
|||||||
document.getElementById('participant_container'),
|
document.getElementById('participant_container'),
|
||||||
html`${Object.keys(contractParticipants)
|
html`${Object.keys(contractParticipants)
|
||||||
.map(participant => render.participantCard({
|
.map(participant => render.participantCard({
|
||||||
accepting_token: accepting_token,
|
acceptingToken: acceptingToken,
|
||||||
selling_token: selling_token,
|
sellingToken: sellingToken,
|
||||||
...contractParticipants[participant]
|
...contractParticipants[participant]
|
||||||
}))
|
}))
|
||||||
}`
|
}`
|
||||||
@ -442,7 +443,7 @@
|
|||||||
document.getElementById('deposits_container'),
|
document.getElementById('deposits_container'),
|
||||||
html`${contractDeposits.map(deposit => render.depositCard({
|
html`${contractDeposits.map(deposit => render.depositCard({
|
||||||
...deposit,
|
...deposit,
|
||||||
accepting_token: accepting_token,
|
acceptingToken: acceptingToken,
|
||||||
}))}`
|
}))}`
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@ -697,22 +698,27 @@
|
|||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
addressPage(obj) {
|
addressPage(obj) {
|
||||||
const { floBalance, floAddress, ownedTokens = {} } = obj;
|
let { floBalance, floAddress, ownedTokens = {} } = obj;
|
||||||
console.log(obj)
|
for (const token in ownedTokens) {
|
||||||
|
if (!ownedTokens[token].balance)
|
||||||
|
ownedTokens[token].balance = 0
|
||||||
|
}
|
||||||
|
if (!ownedTokens)
|
||||||
|
ownedTokens = {}
|
||||||
return html`
|
return html`
|
||||||
<div id="address_page" class="page">
|
<div id="address_page" class="page">
|
||||||
<div class="balance-card">
|
<div class="balance-card">
|
||||||
<h2 class="wrap-around margin-bottom-2">${floAddress}</h2>
|
<h2 class="wrap-around margin-bottom-2">${floAddress}</h2>
|
||||||
<h5 class="label">FLO Balance</h5>
|
<h5 class="label">FLO Balance</h5>
|
||||||
<h3 class="margin-bottom-2">${floBalance} FLO</h3>
|
<h3 class="margin-bottom-2">${floBalance} FLO</h3>
|
||||||
<div class="grid gap-0-5">
|
${Object.keys(ownedTokens).length ? html`
|
||||||
<h5>Tokens</h5>
|
<div class="grid gap-0-5">
|
||||||
<ul id="token_balance_list">
|
<h5>Tokens</h5>
|
||||||
${Object.keys(ownedTokens)
|
<ul id="token_balance_list">
|
||||||
.filter(token => ownedTokens[token].balance > 0)
|
${Object.keys(ownedTokens).map(token => render.tokenBalanceCard(token, ownedTokens[token].balance))}
|
||||||
.map(token => render.tokenBalanceCard(token, ownedTokens[token].balance))}
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
`: ''}
|
||||||
</div>
|
</div>
|
||||||
<h4>Transactions</h4>
|
<h4>Transactions</h4>
|
||||||
<ul id="address_transaction_container" class="transaction-container"></ul>
|
<ul id="address_transaction_container" class="transaction-container"></ul>
|
||||||
@ -845,8 +851,8 @@
|
|||||||
payeeAddress,
|
payeeAddress,
|
||||||
minAmount,
|
minAmount,
|
||||||
maxAmount,
|
maxAmount,
|
||||||
accepting_token,
|
acceptingToken,
|
||||||
selling_token,
|
sellingToken,
|
||||||
numberOfDeposits,
|
numberOfDeposits,
|
||||||
numberOfParticipants,
|
numberOfParticipants,
|
||||||
totalHonorAmount,
|
totalHonorAmount,
|
||||||
@ -918,15 +924,15 @@
|
|||||||
${contractType === 'continuos-event' && contractSubtype === 'tokenswap' ? html`
|
${contractType === 'continuos-event' && contractSubtype === 'tokenswap' ? html`
|
||||||
<div class="flex info-row">
|
<div class="flex info-row">
|
||||||
<h5 class="label">Input token</h5>
|
<h5 class="label">Input token</h5>
|
||||||
<h4>${accepting_token}</h4>
|
<h4>${acceptingToken}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex info-row">
|
<div class="flex info-row">
|
||||||
<h5 class="label">Output token</h5>
|
<h5 class="label">Output token</h5>
|
||||||
<h4>${selling_token}</h4>
|
<h4>${sellingToken}</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex info-row">
|
<div class="flex info-row">
|
||||||
<h5 class="label">Exchange rate (${priceType === 'dynamic' ? 'Dynamic' : 'Fixed'})</h5>
|
<h5 class="label">Exchange rate (${priceType === 'dynamic' ? 'Dynamic' : 'Fixed'})</h5>
|
||||||
<h4>1 ${selling_token} = ${price} ${accepting_token}</h4>
|
<h4>1 ${sellingToken} = ${price} ${acceptingToken}</h4>
|
||||||
</div>
|
</div>
|
||||||
`: ''}
|
`: ''}
|
||||||
${numberOfDeposits ? html`
|
${numberOfDeposits ? html`
|
||||||
@ -950,13 +956,13 @@
|
|||||||
${totalParticipationAmount ? html`
|
${totalParticipationAmount ? html`
|
||||||
<div class="flex info-row">
|
<div class="flex info-row">
|
||||||
<h5 class="label">Total participation amount</h5>
|
<h5 class="label">Total participation amount</h5>
|
||||||
<h4>${formatAmount(totalParticipationAmount, 'usd')} ${accepting_token}</h4>
|
<h4>${formatAmount(totalParticipationAmount, 'usd')} ${acceptingToken}</h4>
|
||||||
</div>
|
</div>
|
||||||
`: ''}
|
`: ''}
|
||||||
${totalHonorAmount ? html`
|
${totalHonorAmount ? html`
|
||||||
<div class="flex info-row">
|
<div class="flex info-row">
|
||||||
<h5 class="label">Total output amount</h5>
|
<h5 class="label">Total output amount</h5>
|
||||||
<h4>${formatAmount(totalHonorAmount, 'usd')} ${selling_token}</h4>
|
<h4>${formatAmount(totalHonorAmount, 'usd')} ${sellingToken}</h4>
|
||||||
</div>
|
</div>
|
||||||
`: ''}
|
`: ''}
|
||||||
</div>
|
</div>
|
||||||
@ -984,7 +990,7 @@
|
|||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
participantCard(details) {
|
participantCard(details) {
|
||||||
const { participantFloAddress, participationAmount, swapAmount, swapPrice, transactionHash, accepting_token, selling_token } = details;
|
const { participantFloAddress, participationAmount, swapAmount, swapPrice, transactionHash, acceptingToken, sellingToken } = details;
|
||||||
return html`
|
return html`
|
||||||
<li class="flex participant">
|
<li class="flex participant">
|
||||||
<div class="grid gap-0-5 flex-1">
|
<div class="grid gap-0-5 flex-1">
|
||||||
@ -997,22 +1003,22 @@
|
|||||||
<div class="grid align-center gap-1 flex-1" style="grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr))">
|
<div class="grid align-center gap-1 flex-1" style="grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr))">
|
||||||
<div>
|
<div>
|
||||||
<h5 class="label">Input amount</h5>
|
<h5 class="label">Input amount</h5>
|
||||||
<b>${formatAmount(participationAmount, 'usd')} ${accepting_token}</b>
|
<b>${formatAmount(participationAmount, 'usd')} ${acceptingToken}</b>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h5 class="label">Output amount</h5>
|
<h5 class="label">Output amount</h5>
|
||||||
<b>${formatAmount(swapAmount, 'usd')} ${selling_token}</b>
|
<b>${formatAmount(swapAmount, 'usd')} ${sellingToken}</b>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h5 class="label">Exchange rate</h5>
|
<h5 class="label">Exchange rate</h5>
|
||||||
<b>${formatAmount(swapPrice, 'usd')} ${accepting_token}</b>
|
<b>${formatAmount(swapPrice, 'usd')} ${acceptingToken}</b>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
depositCard(details) {
|
depositCard(details) {
|
||||||
const { currentBalance, depositorAddress, originalBalance, status, time, transactionHash, accepting_token } = details
|
const { currentBalance, depositorAddress, originalBalance, status, time, transactionHash, acceptingToken } = details
|
||||||
return html`
|
return html`
|
||||||
<li class="flex deposit-card">
|
<li class="flex deposit-card">
|
||||||
<div class="grid gap-0-5 flex-1">
|
<div class="grid gap-0-5 flex-1">
|
||||||
@ -1022,11 +1028,11 @@
|
|||||||
<div class="grid align-center gap-1 flex-1" style="grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr))">
|
<div class="grid align-center gap-1 flex-1" style="grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr))">
|
||||||
<div>
|
<div>
|
||||||
<h5 class="label">Deposited</h5>
|
<h5 class="label">Deposited</h5>
|
||||||
<b>${formatAmount(originalBalance, 'usd')} ${accepting_token}</b>
|
<b>${formatAmount(originalBalance, 'usd')} ${acceptingToken}</b>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h5 class="label">Current balance</h5>
|
<h5 class="label">Current balance</h5>
|
||||||
<b>${formatAmount(currentBalance, 'usd')} ${accepting_token}</b>
|
<b>${formatAmount(currentBalance, 'usd')} ${acceptingToken}</b>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h5 class="label">Status</h5>
|
<h5 class="label">Status</h5>
|
||||||
@ -1084,7 +1090,6 @@
|
|||||||
tokenTransferCard(obj) {
|
tokenTransferCard(obj) {
|
||||||
const { hash, blockHeight, token, sender, receiver, amount, type, time } = obj;
|
const { hash, blockHeight, token, sender, receiver, amount, type, time } = obj;
|
||||||
let title = 'Token transfer';
|
let title = 'Token transfer';
|
||||||
console.log(type)
|
|
||||||
if (type === 'nfttransfer')
|
if (type === 'nfttransfer')
|
||||||
title = 'NFT transfer';
|
title = 'NFT transfer';
|
||||||
return html`
|
return html`
|
||||||
@ -1406,10 +1411,10 @@
|
|||||||
status,
|
status,
|
||||||
expiryTime,
|
expiryTime,
|
||||||
payeeAddress,
|
payeeAddress,
|
||||||
userChoice,
|
userChoices,
|
||||||
tokenIdentification,
|
tokenIdentification,
|
||||||
accepting_token,
|
acceptingToken,
|
||||||
selling_token,
|
sellingToken,
|
||||||
contractAmount,
|
contractAmount,
|
||||||
minimumsubscriptionamount,
|
minimumsubscriptionamount,
|
||||||
maximumsubscriptionamount,
|
maximumsubscriptionamount,
|
||||||
@ -1427,10 +1432,10 @@
|
|||||||
status,
|
status,
|
||||||
expiration: expiryTime,
|
expiration: expiryTime,
|
||||||
payeeAddress,
|
payeeAddress,
|
||||||
userChoices: userChoice,
|
userChoices,
|
||||||
token: tokenIdentification,
|
token: tokenIdentification,
|
||||||
accepting_token,
|
acceptingToken,
|
||||||
selling_token,
|
sellingToken,
|
||||||
participationFees: contractAmount,
|
participationFees: contractAmount,
|
||||||
minAmount: minimumsubscriptionamount,
|
minAmount: minimumsubscriptionamount,
|
||||||
maxAmount: maximumsubscriptionamount,
|
maxAmount: maximumsubscriptionamount,
|
||||||
@ -1465,11 +1470,6 @@
|
|||||||
txList = Object.values(txList)
|
txList = Object.values(txList)
|
||||||
let latestTxArray = [];
|
let latestTxArray = [];
|
||||||
txList.forEach(tx => {
|
txList.forEach(tx => {
|
||||||
// console.log(transactionKey)
|
|
||||||
// if(transactionKey == '11571ce7e5eed0bce30e24de89bb1ba6cc432df7b5b40bbc9f0225b98968cb47'){
|
|
||||||
// //debugger
|
|
||||||
// }
|
|
||||||
console.log(tx)
|
|
||||||
const {
|
const {
|
||||||
transactionDetails: {
|
transactionDetails: {
|
||||||
txid, blockHeight, vin, vout, time },
|
txid, blockHeight, vin, vout, time },
|
||||||
@ -1700,7 +1700,7 @@
|
|||||||
//console.log('this is a block number');
|
//console.log('this is a block number');
|
||||||
location.href = `#/block/${text}`
|
location.href = `#/block/${text}`
|
||||||
resolve('block')
|
resolve('block')
|
||||||
} else if (text.length == 34 && text[0] == 'F') {
|
} else if (text.length == 34 && floCrypto.validateFloID(text)) {
|
||||||
//console.log('data entered is a FLO address');
|
//console.log('data entered is a FLO address');
|
||||||
location.href = `#/address/${text}`
|
location.href = `#/address/${text}`
|
||||||
resolve('address')
|
resolve('address')
|
||||||
|
|||||||
530
scripts/floCrypto.js
Normal file
530
scripts/floCrypto.js
Normal file
@ -0,0 +1,530 @@
|
|||||||
|
(function (EXPORTS) { //floCrypto v2.3.6a
|
||||||
|
/* FLO Crypto Operators */
|
||||||
|
'use strict';
|
||||||
|
const floCrypto = EXPORTS;
|
||||||
|
|
||||||
|
const p = BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16);
|
||||||
|
const ecparams = EllipticCurve.getSECCurveByName("secp256k1");
|
||||||
|
const ascii_alternatives = `‘ '\n’ '\n“ "\n” "\n– --\n— ---\n≥ >=\n≤ <=\n≠ !=\n× *\n÷ /\n← <-\n→ ->\n↔ <->\n⇒ =>\n⇐ <=\n⇔ <=>`;
|
||||||
|
const exponent1 = () => p.add(BigInteger.ONE).divide(BigInteger("4"));
|
||||||
|
coinjs.compressed = true; //defaulting coinjs compressed to true;
|
||||||
|
|
||||||
|
function calculateY(x) {
|
||||||
|
let exp = exponent1();
|
||||||
|
// x is x value of public key in BigInteger format without 02 or 03 or 04 prefix
|
||||||
|
return x.modPow(BigInteger("3"), p).add(BigInteger("7")).mod(p).modPow(exp, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUncompressedPublicKey(compressedPublicKey) {
|
||||||
|
// Fetch x from compressedPublicKey
|
||||||
|
let pubKeyBytes = Crypto.util.hexToBytes(compressedPublicKey);
|
||||||
|
const prefix = pubKeyBytes.shift() // remove prefix
|
||||||
|
let prefix_modulus = prefix % 2;
|
||||||
|
pubKeyBytes.unshift(0) // add prefix 0
|
||||||
|
let x = new BigInteger(pubKeyBytes)
|
||||||
|
let xDecimalValue = x.toString()
|
||||||
|
// Fetch y
|
||||||
|
let y = calculateY(x);
|
||||||
|
let yDecimalValue = y.toString();
|
||||||
|
// verify y value
|
||||||
|
let resultBigInt = y.mod(BigInteger("2"));
|
||||||
|
let check = resultBigInt.toString() % 2;
|
||||||
|
if (prefix_modulus !== check)
|
||||||
|
yDecimalValue = y.negate().mod(p).toString();
|
||||||
|
return {
|
||||||
|
x: xDecimalValue,
|
||||||
|
y: yDecimalValue
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSenderPublicKeyString() {
|
||||||
|
let privateKey = ellipticCurveEncryption.senderRandom();
|
||||||
|
var senderPublicKeyString = ellipticCurveEncryption.senderPublicString(privateKey);
|
||||||
|
return {
|
||||||
|
privateKey: privateKey,
|
||||||
|
senderPublicKeyString: senderPublicKeyString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function deriveSharedKeySender(receiverPublicKeyHex, senderPrivateKey) {
|
||||||
|
let receiverPublicKeyString = getUncompressedPublicKey(receiverPublicKeyHex);
|
||||||
|
var senderDerivedKey = ellipticCurveEncryption.senderSharedKeyDerivation(
|
||||||
|
receiverPublicKeyString.x, receiverPublicKeyString.y, senderPrivateKey);
|
||||||
|
return senderDerivedKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
function deriveSharedKeyReceiver(senderPublicKeyString, receiverPrivateKey) {
|
||||||
|
return ellipticCurveEncryption.receiverSharedKeyDerivation(
|
||||||
|
senderPublicKeyString.XValuePublicString, senderPublicKeyString.YValuePublicString, receiverPrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getReceiverPublicKeyString(privateKey) {
|
||||||
|
return ellipticCurveEncryption.receiverPublicString(privateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wifToDecimal(pk_wif, isPubKeyCompressed = false) {
|
||||||
|
let pk = Bitcoin.Base58.decode(pk_wif)
|
||||||
|
pk.shift()
|
||||||
|
pk.splice(-4, 4)
|
||||||
|
//If the private key corresponded to a compressed public key, also drop the last byte (it should be 0x01).
|
||||||
|
if (isPubKeyCompressed == true) pk.pop()
|
||||||
|
pk.unshift(0)
|
||||||
|
let privateKeyDecimal = BigInteger(pk).toString()
|
||||||
|
let privateKeyHex = Crypto.util.bytesToHex(pk)
|
||||||
|
return {
|
||||||
|
privateKeyDecimal: privateKeyDecimal,
|
||||||
|
privateKeyHex: privateKeyHex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate a random Interger within range
|
||||||
|
floCrypto.randInt = function (min, max) {
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(securedMathRandom() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
//generate a random String within length (options : alphaNumeric chars only)
|
||||||
|
floCrypto.randString = function (length, alphaNumeric = true) {
|
||||||
|
var result = '';
|
||||||
|
var characters = alphaNumeric ? 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' :
|
||||||
|
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_+-./*?@#&$<>=[]{}():';
|
||||||
|
for (var i = 0; i < length; i++)
|
||||||
|
result += characters.charAt(Math.floor(securedMathRandom() * characters.length));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Encrypt Data using public-key
|
||||||
|
floCrypto.encryptData = function (data, receiverPublicKeyHex) {
|
||||||
|
var senderECKeyData = getSenderPublicKeyString();
|
||||||
|
var senderDerivedKey = deriveSharedKeySender(receiverPublicKeyHex, senderECKeyData.privateKey);
|
||||||
|
let senderKey = senderDerivedKey.XValue + senderDerivedKey.YValue;
|
||||||
|
let secret = Crypto.AES.encrypt(data, senderKey);
|
||||||
|
return {
|
||||||
|
secret: secret,
|
||||||
|
senderPublicKeyString: senderECKeyData.senderPublicKeyString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//Decrypt Data using private-key
|
||||||
|
floCrypto.decryptData = function (data, privateKeyHex) {
|
||||||
|
var receiverECKeyData = {};
|
||||||
|
if (typeof privateKeyHex !== "string") throw new Error("No private key found.");
|
||||||
|
let privateKey = wifToDecimal(privateKeyHex, true);
|
||||||
|
if (typeof privateKey.privateKeyDecimal !== "string") throw new Error("Failed to detremine your private key.");
|
||||||
|
receiverECKeyData.privateKey = privateKey.privateKeyDecimal;
|
||||||
|
var receiverDerivedKey = deriveSharedKeyReceiver(data.senderPublicKeyString, receiverECKeyData.privateKey);
|
||||||
|
let receiverKey = receiverDerivedKey.XValue + receiverDerivedKey.YValue;
|
||||||
|
let decryptMsg = Crypto.AES.decrypt(data.secret, receiverKey);
|
||||||
|
return decryptMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Sign data using private-key
|
||||||
|
floCrypto.signData = function (data, privateKeyHex) {
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
var messageHash = Crypto.SHA256(data);
|
||||||
|
var messageSign = Bitcoin.ECDSA.sign(messageHash, key.priv);
|
||||||
|
var sighex = Crypto.util.bytesToHex(messageSign);
|
||||||
|
return sighex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Verify signatue of the data using public-key
|
||||||
|
floCrypto.verifySign = function (data, signatureHex, publicKeyHex) {
|
||||||
|
var msgHash = Crypto.SHA256(data);
|
||||||
|
var sigBytes = Crypto.util.hexToBytes(signatureHex);
|
||||||
|
var publicKeyPoint = ecparams.getCurve().decodePointHex(publicKeyHex);
|
||||||
|
var verify = Bitcoin.ECDSA.verify(msgHash, sigBytes, publicKeyPoint);
|
||||||
|
return verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generates a new flo ID and returns private-key, public-key and floID
|
||||||
|
const generateNewID = floCrypto.generateNewID = function () {
|
||||||
|
var key = new Bitcoin.ECKey(false);
|
||||||
|
key.setCompressed(true);
|
||||||
|
return {
|
||||||
|
floID: key.getBitcoinAddress(),
|
||||||
|
pubKey: key.getPubKeyHex(),
|
||||||
|
privKey: key.getBitcoinWalletImportFormat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperties(floCrypto, {
|
||||||
|
newID: {
|
||||||
|
get: () => generateNewID()
|
||||||
|
},
|
||||||
|
hashID: {
|
||||||
|
value: (str) => {
|
||||||
|
let bytes = ripemd160(Crypto.SHA256(str, { asBytes: true }), { asBytes: true });
|
||||||
|
bytes.unshift(bitjs.pub);
|
||||||
|
var hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
var checksum = hash.slice(0, 4);
|
||||||
|
return bitjs.Base58.encode(bytes.concat(checksum));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tmpID: {
|
||||||
|
get: () => {
|
||||||
|
let bytes = Crypto.util.randomBytes(20);
|
||||||
|
bytes.unshift(bitjs.pub);
|
||||||
|
var hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
var checksum = hash.slice(0, 4);
|
||||||
|
return bitjs.Base58.encode(bytes.concat(checksum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Returns public-key from private-key
|
||||||
|
floCrypto.getPubKeyHex = function (privateKeyHex) {
|
||||||
|
if (!privateKeyHex)
|
||||||
|
return null;
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
return null;
|
||||||
|
key.setCompressed(true);
|
||||||
|
return key.getPubKeyHex();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns flo-ID from public-key or private-key
|
||||||
|
floCrypto.getFloID = function (keyHex) {
|
||||||
|
if (!keyHex)
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
var key = new Bitcoin.ECKey(keyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
key.setPub(keyHex);
|
||||||
|
return key.getBitcoinAddress();
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.getAddress = function (privateKeyHex, strict = false) {
|
||||||
|
if (!privateKeyHex)
|
||||||
|
return;
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
return null;
|
||||||
|
key.setCompressed(true);
|
||||||
|
let pubKey = key.getPubKeyHex(),
|
||||||
|
version = bitjs.Base58.decode(privateKeyHex)[0];
|
||||||
|
switch (version) {
|
||||||
|
case coinjs.priv: //BTC
|
||||||
|
return coinjs.bech32Address(pubKey).address;
|
||||||
|
case bitjs.priv: //FLO
|
||||||
|
return bitjs.pubkey2address(pubKey);
|
||||||
|
default:
|
||||||
|
return strict ? false : bitjs.pubkey2address(pubKey); //default to FLO address (if strict=false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Verify the private-key for the given public-key or flo-ID
|
||||||
|
floCrypto.verifyPrivKey = function (privateKeyHex, pubKey_floID, isfloID = true) {
|
||||||
|
if (!privateKeyHex || !pubKey_floID)
|
||||||
|
return false;
|
||||||
|
try {
|
||||||
|
var key = new Bitcoin.ECKey(privateKeyHex);
|
||||||
|
if (key.priv == null)
|
||||||
|
return false;
|
||||||
|
key.setCompressed(true);
|
||||||
|
if (isfloID && pubKey_floID == key.getBitcoinAddress())
|
||||||
|
return true;
|
||||||
|
else if (!isfloID && pubKey_floID.toUpperCase() == key.getPubKeyHex().toUpperCase())
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.getMultisigAddress = function (publicKeyList, requiredSignatures) {
|
||||||
|
if (!Array.isArray(publicKeyList) || !publicKeyList.length)
|
||||||
|
return null;
|
||||||
|
if (!Number.isInteger(requiredSignatures) || requiredSignatures < 1 || requiredSignatures > publicKeyList.length)
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
var multisig = bitjs.pubkeys2multisig(publicKeyList, requiredSignatures);
|
||||||
|
return multisig;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.decodeRedeemScript = function (redeemScript) {
|
||||||
|
try {
|
||||||
|
var decoded = bitjs.transaction().decodeRedeemScript(redeemScript);
|
||||||
|
return decoded;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the given flo-id is valid or not
|
||||||
|
floCrypto.validateFloID = function (floID, regularOnly = false) {
|
||||||
|
if (!floID)
|
||||||
|
return false;
|
||||||
|
try {
|
||||||
|
let addr = new Bitcoin.Address(floID);
|
||||||
|
if (regularOnly && addr.version != Bitcoin.Address.standardVersion)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the given address (any blockchain) is valid or not
|
||||||
|
floCrypto.validateAddr = function (address, std = true, bech = true) {
|
||||||
|
let raw = decodeAddress(address);
|
||||||
|
if (!raw)
|
||||||
|
return false;
|
||||||
|
if (typeof raw.version !== 'undefined') { //legacy or segwit
|
||||||
|
if (std == false)
|
||||||
|
return false;
|
||||||
|
else if (std === true || (!Array.isArray(std) && std === raw.version) || (Array.isArray(std) && std.includes(raw.version)))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else if (typeof raw.bech_version !== 'undefined') { //bech32
|
||||||
|
if (bech === false)
|
||||||
|
return false;
|
||||||
|
else if (bech === true || (!Array.isArray(bech) && bech === raw.bech_version) || (Array.isArray(bech) && bech.includes(raw.bech_version)))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else //unknown
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check the public-key (or redeem-script) for the address (any blockchain)
|
||||||
|
floCrypto.verifyPubKey = function (pubKeyHex, address) {
|
||||||
|
let raw = decodeAddress(address);
|
||||||
|
if (!raw)
|
||||||
|
return;
|
||||||
|
let pub_hash = Crypto.util.bytesToHex(ripemd160(Crypto.SHA256(Crypto.util.hexToBytes(pubKeyHex), { asBytes: true })));
|
||||||
|
if (typeof raw.bech_version !== 'undefined' && raw.bytes.length == 32) //bech32-multisig
|
||||||
|
raw.hex = Crypto.util.bytesToHex(ripemd160(raw.bytes, { asBytes: true }));
|
||||||
|
return pub_hash === raw.hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert the given address (any blockchain) to equivalent floID
|
||||||
|
floCrypto.toFloID = function (address, options = null) {
|
||||||
|
if (!address)
|
||||||
|
return;
|
||||||
|
let raw = decodeAddress(address);
|
||||||
|
if (!raw)
|
||||||
|
return;
|
||||||
|
else if (options) { //if (optional) version check is passed
|
||||||
|
if (typeof raw.version !== 'undefined' && (!options.std || !options.std.includes(raw.version)))
|
||||||
|
return;
|
||||||
|
if (typeof raw.bech_version !== 'undefined' && (!options.bech || !options.bech.includes(raw.bech_version)))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
raw.bytes.unshift(bitjs.pub);
|
||||||
|
let hash = Crypto.SHA256(Crypto.SHA256(raw.bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0, 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert raw address bytes to floID
|
||||||
|
floCrypto.rawToFloID = function (raw_bytes) {
|
||||||
|
if (typeof raw_bytes === 'string')
|
||||||
|
raw_bytes = Crypto.util.hexToBytes(raw_bytes);
|
||||||
|
if (raw_bytes.length != 20)
|
||||||
|
return null;
|
||||||
|
raw_bytes.unshift(bitjs.pub);
|
||||||
|
let hash = Crypto.SHA256(Crypto.SHA256(raw_bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return bitjs.Base58.encode(raw_bytes.concat(hash.slice(0, 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert the given multisig address (any blockchain) to equivalent multisig floID
|
||||||
|
floCrypto.toMultisigFloID = function (address, options = null) {
|
||||||
|
if (!address)
|
||||||
|
return;
|
||||||
|
let raw = decodeAddress(address);
|
||||||
|
if (!raw)
|
||||||
|
return;
|
||||||
|
else if (options) { //if (optional) version check is passed
|
||||||
|
if (typeof raw.version !== 'undefined' && (!options.std || !options.std.includes(raw.version)))
|
||||||
|
return;
|
||||||
|
if (typeof raw.bech_version !== 'undefined' && (!options.bech || !options.bech.includes(raw.bech_version)))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof raw.bech_version !== 'undefined') {
|
||||||
|
if (raw.bytes.length != 32) return; //multisig bech address have 32 bytes
|
||||||
|
//multisig-bech:hash=SHA256 whereas multisig:hash=r160(SHA265), thus ripemd160 the bytes from multisig-bech
|
||||||
|
raw.bytes = ripemd160(raw.bytes, {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
raw.bytes.unshift(bitjs.multisig);
|
||||||
|
let hash = Crypto.SHA256(Crypto.SHA256(raw.bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return bitjs.Base58.encode(raw.bytes.concat(hash.slice(0, 4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Checks if the given addresses (any blockchain) are same (w.r.t keys)
|
||||||
|
floCrypto.isSameAddr = function (addr1, addr2) {
|
||||||
|
if (!addr1 || !addr2)
|
||||||
|
return;
|
||||||
|
let raw1 = decodeAddress(addr1),
|
||||||
|
raw2 = decodeAddress(addr2);
|
||||||
|
if (!raw1 || !raw2)
|
||||||
|
return false;
|
||||||
|
else {
|
||||||
|
if (typeof raw1.bech_version !== 'undefined' && raw1.bytes.length == 32) //bech32-multisig
|
||||||
|
raw1.hex = Crypto.util.bytesToHex(ripemd160(raw1.bytes, { asBytes: true }));
|
||||||
|
if (typeof raw2.bech_version !== 'undefined' && raw2.bytes.length == 32) //bech32-multisig
|
||||||
|
raw2.hex = Crypto.util.bytesToHex(ripemd160(raw2.bytes, { asBytes: true }));
|
||||||
|
return raw1.hex === raw2.hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const decodeAddress = floCrypto.decodeAddr = function (address) {
|
||||||
|
if (!address)
|
||||||
|
return;
|
||||||
|
else if (address.length == 33 || address.length == 34) { //legacy encoding
|
||||||
|
let decode = bitjs.Base58.decode(address);
|
||||||
|
let bytes = decode.slice(0, decode.length - 4);
|
||||||
|
let checksum = decode.slice(decode.length - 4),
|
||||||
|
hash = Crypto.SHA256(Crypto.SHA256(bytes, {
|
||||||
|
asBytes: true
|
||||||
|
}), {
|
||||||
|
asBytes: true
|
||||||
|
});
|
||||||
|
return (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3]) ? null : {
|
||||||
|
version: bytes.shift(),
|
||||||
|
hex: Crypto.util.bytesToHex(bytes),
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
} else if (address.length == 42 || address.length == 62) { //bech encoding
|
||||||
|
let decode = coinjs.bech32_decode(address);
|
||||||
|
if (decode) {
|
||||||
|
let bytes = decode.data;
|
||||||
|
let bech_version = bytes.shift();
|
||||||
|
bytes = coinjs.bech32_convert(bytes, 5, 8, false);
|
||||||
|
return {
|
||||||
|
bech_version,
|
||||||
|
hrp: decode.hrp,
|
||||||
|
hex: Crypto.util.bytesToHex(bytes),
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Split the str using shamir's Secret and Returns the shares
|
||||||
|
floCrypto.createShamirsSecretShares = function (str, total_shares, threshold_limit) {
|
||||||
|
try {
|
||||||
|
if (str.length > 0) {
|
||||||
|
var strHex = shamirSecretShare.str2hex(str);
|
||||||
|
var shares = shamirSecretShare.share(strHex, total_shares, threshold_limit);
|
||||||
|
return shares;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Returns the retrived secret by combining the shamirs shares
|
||||||
|
const retrieveShamirSecret = floCrypto.retrieveShamirSecret = function (sharesArray) {
|
||||||
|
try {
|
||||||
|
if (sharesArray.length > 0) {
|
||||||
|
var comb = shamirSecretShare.combine(sharesArray.slice(0, sharesArray.length));
|
||||||
|
comb = shamirSecretShare.hex2str(comb);
|
||||||
|
return comb;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Verifies the shares and str
|
||||||
|
floCrypto.verifyShamirsSecret = function (sharesArray, str) {
|
||||||
|
if (!str)
|
||||||
|
return null;
|
||||||
|
else if (retrieveShamirSecret(sharesArray) === str)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateASCII = floCrypto.validateASCII = function (string, bool = true) {
|
||||||
|
if (typeof string !== "string")
|
||||||
|
return null;
|
||||||
|
if (bool) {
|
||||||
|
let x;
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
x = string.charCodeAt(i);
|
||||||
|
if (x < 32 || x > 127)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
let x, invalids = {};
|
||||||
|
for (let i = 0; i < string.length; i++) {
|
||||||
|
x = string.charCodeAt(i);
|
||||||
|
if (x < 32 || x > 127)
|
||||||
|
if (x in invalids)
|
||||||
|
invalids[string[i]].push(i)
|
||||||
|
else
|
||||||
|
invalids[string[i]] = [i];
|
||||||
|
}
|
||||||
|
if (Object.keys(invalids).length)
|
||||||
|
return invalids;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.convertToASCII = function (string, mode = 'soft-remove') {
|
||||||
|
let chars = validateASCII(string, false);
|
||||||
|
if (chars === true)
|
||||||
|
return string;
|
||||||
|
else if (chars === null)
|
||||||
|
return null;
|
||||||
|
let convertor, result = string,
|
||||||
|
refAlt = {};
|
||||||
|
ascii_alternatives.split('\n').forEach(a => refAlt[a[0]] = a.slice(2));
|
||||||
|
mode = mode.toLowerCase();
|
||||||
|
if (mode === "hard-unicode")
|
||||||
|
convertor = (c) => `\\u${('000' + c.charCodeAt().toString(16)).slice(-4)}`;
|
||||||
|
else if (mode === "soft-unicode")
|
||||||
|
convertor = (c) => refAlt[c] || `\\u${('000' + c.charCodeAt().toString(16)).slice(-4)}`;
|
||||||
|
else if (mode === "hard-remove")
|
||||||
|
convertor = c => "";
|
||||||
|
else if (mode === "soft-remove")
|
||||||
|
convertor = c => refAlt[c] || "";
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
for (let c in chars)
|
||||||
|
result = result.replaceAll(c, convertor(c));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
floCrypto.revertUnicode = function (string) {
|
||||||
|
return string.replace(/\\u[\dA-F]{4}/gi,
|
||||||
|
m => String.fromCharCode(parseInt(m.replace(/\\u/g, ''), 16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
})('object' === typeof module ? module.exports : window.floCrypto = {});
|
||||||
9975
scripts/lib.js
Normal file
9975
scripts/lib.js
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user