btcmortgage/scripts/btcMortgage.js

186 lines
6.7 KiB
JavaScript

(function (EXPORTS) {
const btcMortgage = EXPORTS;
//USERS: B: Borrower, L: Lender, C: Collateral provider, T: Trusted banker (us)
var BankerPubKey = "0257a9c47462fe89b159daa204ddb964c9b098a020641cc8090a9cad4f6dd2172a";
const CURRENCY = "USD";
const PERIOD_REGEX = /^\d{1,5}(Y|M|D)$/,
TXID_REGEX = /^[0-9a-f]{64}$/i,
VALUE_REGEX = /^\d+(.\d{1,8})?$/;
const POLICIES = {}
const toFixedDecimal = value => parseFloat((value).toFixed(8));
function encodePeriod(str) {
if (typeof str != 'string')
throw "passed value must be string";
if (PERIOD_REGEX.test(str)) //already in format
return str;
let P = '', n = 0;
str.toLowerCase().replace(/,/g, '').split(" ").forEach(s => {
if (!isNaN(s))
n = parseInt(s);
else switch (s) {
case "year(s)": case "year": case "years": P += (n + 'Y'); n = 0; break;
case "month(s)": case "month": case "months": P += (n + 'M'); n = 0; break;
case "day(s)": case "day": case "days": P += (n + 'D'); n = 0; break;
}
});
if (!PERIOD_REGEX.test(P)) {//not in format: something wrong
console.error(`encodePeriod('${str}') failed`, P)
throw "Invalid period";
}
return P;
}
function decodePeriod(str) {
if (typeof str != 'string')
throw "passed value must be string";
else if (!PERIOD_REGEX.test(str)) //not in format
throw "Invalid period";
let n = parseInt(str);
let v = str[str.length - 1];
switch (v) {
case 'Y': return n + (n == 1 ? "year" : "years");
case 'M': return n + (n == 1 ? "month" : "months");
case "D": return n + (n == 1 ? "day" : "days");
}
}
const dateFormat = (date = null) => {
let d = (date ? new Date(date) : new Date()).toDateString();
return [d.substring(8, 10), d.substring(4, 7), d.substring(11, 15)].join(" ");
}
const yearDiff = (d1 = null, d2 = null) => {
d1 = d1 ? new Date(d1) : new Date();
d2 = d2 ? new Date(d2) : new Date();
let y = d1.getYear() - d2.getYear(),
m = d1.getMonth() - d2.getMonth(),
d = d1.getDate() - d2.getDate()
return y + m / 12 + d / 365;
}
const dateAdder = function (start_date, duration) {
let date = new Date(start_date);
let y = parseInt(duration.match(/\d+Y/)),
m = parseInt(duration.match(/\d+M/)),
d = parseInt(duration.match(/\d+D/));
if (!isNaN(y))
date.setFullYear(date.getFullYear() + y);
if (!isNaN(m))
date.setMonth(date.getMonth() + m);
if (!isNaN(d))
date.setDate(date.getDate() + d);
return date;
}
function calcAllowedLoan(collateralQuantity, security_percent) {
return collateralQuantity * security_percent;
}
function calcRequiredCollateral(loanEquivalent, security_percent) {
let inverse_security_percent = 1 / security_percent;
return loanEquivalent * inverse_security_percent;
}
function findLocker(coborrower_pubKey, lender_pubKey) {
return btcOperator.multiSigAddress([coborrower_pubKey, lender_pubKey, BankerPubKey], 2);
}
function extractPubKeyFromSign(sign) {
return sign.split('.')[0];
}
btcMortgage.util = {
toFixedDecimal,
encodePeriod, decodePeriod,
calcAllowedLoan, calcRequiredCollateral,
findLocker, extractPubKeyFromSign
}
//get BTC rates
const getRate = btcMortgage.getRate = {};
getRate["BTC"] = function () {
return new Promise((resolve, reject) => {
fetch('https://api.coinlore.net/api/ticker/?id=90').then(response => {
if (response.ok) {
response.json()
.then(result => resolve(result[0].price_usd))
.catch(error => reject(error));
} else
reject(response.status);
}).catch(error => reject(error));
});
}
//Loan details on FLO blockchain
const LOAN_DETAILS_IDENTIFIER = "BTC Mortage: Loan details";
function stringifyLoanOpenData(
borrower, loan_amount, policy_id,
coborrower, collateral_value, collateral_lock_id,
lender, loan_transfer_id,
borrower_sign, coborrower_sign, lender_sign
) {
return [
LOAN_DETAILS_IDENTIFIER,
"Borrower:" + floCrypto.toFloID(borrower),
"Amount:" + loan_amount,
"Policy:" + policy_id,
"CoBorrower:" + floCrypto.toFloID(coborrower),
"CollateralValue:" + collateral_value + "BTC",
"CollateralLock:" + collateral_lock_id,
"Lender:" + floCrypto.toFloID(lender),
"TokenTransfer:" + loan_transfer_id,
"Signature-B:" + borrower_sign,
"Signature-C:" + coborrower_sign,
"Signature-L:" + lender_sign
].join('|');
/*MAYDO: Maybe make it a worded sentence?
BTC Mortage:
L#${lender_floid} is lending ${loan_amount}USD (ref#${loan_transfer_id}) to B#${borrower_floid}
inaccoradance with policy#${policy_id}
as mortage on collateral#${collateral_id} (${btc_amount}BTC) provided by C#${coborrower_floid}.
Signed by B'${borrower_sign} , C'{coborrower_sign} and L'${lender_sign}
*/
}
function parseLoanOpenData(str, tx_time) {
let splits = str.split('|');
if (splits[0] !== LOAN_DETAILS_IDENTIFIER)
throw "Invalid Loan blockchain data";
var details = { open_time: tx_time };
splits.forEach(s => {
let d = s.split(':');
switch (d[0]) {
case "Borrower": details.borrower = d[1]; break;
case "Amount": details.loan_amount = parseFloat(d[1]); break;
case "Policy": details.policy_id = d[1]; break;
case "CoBorrower": details.coborrower = d[1]; break;
case "CollateralValue": details.collateral_value = parseFloat(d[1]); break;
case "CollateralLock": details.collateral_lock_id = d[1]; break;
case "Lender": details.lender = d[1]; break;
case "TokenTransfer": details.loan_transfer_id = d[1]; break;
case "Signature-B": details.borrower_sign = d[1]; break;
case "Signature-C": details.coborrower_sign = d[1]; break;
case "Signature-L": details.lender_sign = d[1]; break;
}
});
return details;
}
})(window.btcMortgage = {})