Fixes and improvements in validation
This commit is contained in:
parent
eb7513663f
commit
b169ee7d61
@ -116,10 +116,9 @@
|
||||
return loanEquivalent * inverse_security_percent;
|
||||
}
|
||||
|
||||
function calcDueAmount(loan_amount, policy_id, open_time) {
|
||||
function calcDueAmount(loan_amount, policy_id, open_time, close_time = Date.now()) {
|
||||
let policy = POLICIES[policy_id],
|
||||
current_time = Date.now(),
|
||||
duration = yearDiff(current_time, open_time);
|
||||
duration = yearDiff(close_time, open_time);
|
||||
let interest_amount = loan_amount * policy.interest * duration;
|
||||
let due_amount = loan_amount + interest_amount;
|
||||
return due_amount;
|
||||
@ -257,11 +256,11 @@
|
||||
*/
|
||||
}
|
||||
|
||||
function parseLoanOpenData(str, tx_time) {
|
||||
function parseLoanOpenData(str, txid, tx_time) {
|
||||
let splits = str.split('|');
|
||||
if (splits[0] !== LOAN_DETAILS_IDENTIFIER)
|
||||
throw "Invalid Loan blockchain data";
|
||||
var details = { open_time: tx_time };
|
||||
var details = { loan_id: txid, open_time: tx_time };
|
||||
splits.forEach(s => {
|
||||
let d = s.split(':');
|
||||
switch (d[0]) {
|
||||
@ -285,7 +284,7 @@
|
||||
const getLoanDetails = btcMortgage.getLoanDetails = function (loan_id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
floBlockchainAPI.getTx(loan_id).then(tx => {
|
||||
let parsed_loan_details = parseLoanOpenData(tx.floData, tx.time);
|
||||
let parsed_loan_details = parseLoanOpenData(tx.floData, tx.txid, tx.time);
|
||||
validateLoanDetails(parsed_loan_details)
|
||||
.then(_ => resolve(parsed_loan_details))
|
||||
.catch(error => reject(error))
|
||||
@ -312,7 +311,45 @@
|
||||
return reject("Invalid coborrower signature");
|
||||
if (!verify_lenderSign(loan_details.lender_sign, loan_details.lender, loan_details.coborrower_sign, loan_details.loan_transfer_id))
|
||||
return reject("Invalid lender signature");
|
||||
resolve(true)
|
||||
validateCollateralLock(loan_details.collateral_lock_id, extractPubKeyFromSign(loan_details.coborrower_sign), extractPubKeyFromSign(loan_details.lender_sign), loan_details.collateral_value).then(result => {
|
||||
validateLoanOpenTokenTransfer(loan_details.loan_transfer_id, loan_details.borrower, loan_details.lender, loan_details.loan_amount)
|
||||
.then(result => resolve(true))
|
||||
.catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
const validateCollateralLock = btcMortgage.validateCollateralLock = function (collateral_lock_id, coborrower_pubKey, lender_pubKey, collateral_value) {
|
||||
return new Promise((resolve, reject) => {
|
||||
btcOperator.getTx(collateral_lock_id).then(collateral_tx => {
|
||||
if (!collateral_tx.confirmations)
|
||||
return reject("Collateral lock transaction not confirmed yet");
|
||||
let locker_id = findLocker(coborrower_pubKey, lender_pubKey).address;
|
||||
let locked_amt = collateral_tx.outputs.filter(o => o.address == locker_id).reduce((a, o) => a += o.value, 0);
|
||||
if (locked_amt < collateral_value)
|
||||
return reject("Insufficient Collateral locked");
|
||||
resolve(true);
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
const validateLoanOpenTokenTransfer = btcMortgage.validateLoanOpenTokenTransfer = function (loan_transfer_id, borrower, lender, loan_amount) {
|
||||
return new Promise((resolve, reject) => {
|
||||
floTokenAPI.getTx(loan_transfer_id).then(token_tx => {
|
||||
if (token_tx.parsedFloData.type != "transfer" || token_tx.parsedFloData.transferType != "token")
|
||||
return reject("Transaction is not a token transfer");
|
||||
if (token_tx.parsedFloData.tokenIdentification != CURRENCY)
|
||||
return reject("Transfered token is not " + CURRENCY);
|
||||
if (token_tx.transactionDetails.confirmations == 0)
|
||||
return reject("Transaction not yet confirmed");
|
||||
if (token_tx.transactionDetails.receiverAddress != floCrypto.toFloID(borrower))
|
||||
return reject("Receiver is not borrower");
|
||||
if (token_tx.transactionDetails.senderAddress != floCrypto.toFloID(lender))
|
||||
return reject("Sender is not lender");
|
||||
if (token_tx.parsedFloData.tokenAmount !== loan_amount)
|
||||
return reject("Token amount doesnot match the loan amount");
|
||||
resolve(true);
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
@ -326,11 +363,11 @@
|
||||
].join('|');
|
||||
}
|
||||
|
||||
function parseLoanCloseData(str, tx_time) {
|
||||
function parseLoanCloseData(str, txid, tx_time) {
|
||||
let splits = str.split('|');
|
||||
if (splits[0] !== LOAN_CLOSING_IDENTIFIER)
|
||||
if (splits[1] !== LOAN_CLOSING_IDENTIFIER) //splits[0] will be token transfer
|
||||
throw "Invalid Loan closing data";
|
||||
var details = { close_time: tx_time };
|
||||
var details = { close_time: tx_time, close_id: txid };
|
||||
splits.forEach(s => {
|
||||
let d = s.split(':');
|
||||
switch (d[0]) {
|
||||
@ -342,19 +379,54 @@
|
||||
return details;
|
||||
}
|
||||
|
||||
const getLoanClosing = btcMortgage.getLoanClosing = function (loan_id, closing_txid) {
|
||||
const getLoanClosing = btcMortgage.getLoanClosing = function (closing_txid) {
|
||||
return new Promise((resolve, reject) => {
|
||||
floBlockchainAPI.getTx(closing_txid).then(tx => {
|
||||
let parsed_loan_closing = parseLoanCloseData(tx.floData, tx.time);
|
||||
validateLoanClosing(parsed_loan_closing)
|
||||
.then(_ => resolve(parsed_loan_closing))
|
||||
.catch(error => reject(error))
|
||||
let closing_details = parseLoanCloseData(tx.floData, tx.time);
|
||||
getLoanDetails(closing_details.loan_id).then(loan_details => {
|
||||
validateLoanClosing(loan_details, closing_details)
|
||||
.then(result => resolve(Object.assign(loan_details, closing_details)))
|
||||
.catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
const validateLoanClosing = btcMortgage.validateLoanClosing = function (loan_id, closing_txid) {
|
||||
//TODO
|
||||
const validateLoanClosing = btcMortgage.validateLoanClosing = function (loan_details, closing_details) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (closing_details.loan_id !== loan_details.loan_id)
|
||||
return reject("Closing doesnot belong to this loan")
|
||||
if (!floCrypto.validateFloID(closing_details.borrower))
|
||||
return reject("Invalid borrower floID");
|
||||
if (closing_details.borrower != loan_details.borrower)
|
||||
return reject("Borrower ID is different");
|
||||
if (verify_closingSign(closing_details.closing_sign, closing_details.borrower, closing_details.loan_id, loan_details.lender_sign))
|
||||
return reject("Invalid closing signature");
|
||||
validateLoanCloseTokenTransfer(closing_details.close_id, loan_details.borrower, loan_details.lender, loan_details.loan_amount, loan_details.policy_id, loan_details.open_time, closing_details.close_time)
|
||||
.then(result => resolve(true))
|
||||
.catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
const validateLoanCloseTokenTransfer = btcMortgage.validateLoanCloseTokenTransfer = function (close_id, borrower, lender, loan_amount, policy_id, open_time, close_time) {
|
||||
return new Promise((resolve, reject) => {
|
||||
floTokenAPI.getTx(close_id).then(token_tx => {
|
||||
if (token_tx.parsedFloData.type != "transfer" || token_tx.parsedFloData.transferType != "token")
|
||||
return reject("Transaction is not a token transfer");
|
||||
if (token_tx.parsedFloData.tokenIdentification != CURRENCY)
|
||||
return reject("Transfered token is not " + CURRENCY);
|
||||
if (token_tx.transactionDetails.confirmations == 0)
|
||||
return reject("Transaction not yet confirmed");
|
||||
if (token_tx.transactionDetails.receiverAddress != floCrypto.toFloID(lender))
|
||||
return reject("Receiver is not lender");
|
||||
if (token_tx.transactionDetails.senderAddress != floCrypto.toFloID(borrower))
|
||||
return reject("Sender is not borrower");
|
||||
let repay_amount = calcDueAmount(loan_amount, policy_id, open_time, close_time);
|
||||
if (token_tx.parsedFloData.tokenAmount < repay_amount)
|
||||
return reject("Token amount is less than loan repayment amount");
|
||||
resolve(true);
|
||||
}).catch(error => reject(error))
|
||||
})
|
||||
}
|
||||
|
||||
/*Signature and verification */
|
||||
@ -877,7 +949,7 @@
|
||||
//repay and close the loan
|
||||
let closing_sign = sign_closing(privKey, loan_id, loan_details.lender_sign);
|
||||
var closing_data = stringifyLoanCloseData(loan_id, loan_details.borrower, closing_sign);
|
||||
floTokenAPI.sendToken(privKey, due_amount, loan_details.lender, closing_data, CURRENCY).then(closing_txid => {
|
||||
floTokenAPI.sendToken(privKey, due_amount, loan_details.lender, "|" + closing_data, CURRENCY).then(closing_txid => {
|
||||
//send message to coborrower as reminder to unlock collateral
|
||||
floCloudAPI.sendApplicationData({ loan_id, closing_txid }, TYPE_LOAN_CLOSED_ACK, { receiverID: loan_details.coborrower })
|
||||
.then(result => {
|
||||
@ -1312,7 +1384,10 @@
|
||||
//check output
|
||||
let return_amount = total_collateral_value - due_amount;
|
||||
if (return_amount > 0) {
|
||||
//TODO: check if the return amount and receiver is correct
|
||||
let return_outpts_amount = tx.outs.filter(o => spendScriptToAddress(o.script) == coborrower_btcID).reduce((a, o) => a += o.value, 0)
|
||||
return_outpts_amount = btcOperator.util.Sat_to_BTC(return_outpts_amount);
|
||||
if (return_outpts_amount < return_amount)
|
||||
return reject("Return value after liquidation is lower")
|
||||
}
|
||||
//sign the tx hex
|
||||
tx.sign(privKey, 1 /*sighashtype*/);
|
||||
@ -1322,6 +1397,21 @@
|
||||
})
|
||||
}
|
||||
|
||||
function spendScriptToAddress(script) {
|
||||
var address;
|
||||
switch (script.chunks[0]) {
|
||||
case 0: //bech32, multisig-bech32
|
||||
address = btcOperator.util.encodeBech32(Crypto.util.bytesToHex(script.chunks[1]), coinjs.bech32.version, coinjs.bech32.hrp);
|
||||
break;
|
||||
case 169: //segwit, multisig-segwit
|
||||
address = btcOperator.util.encodeLegacy(Crypto.util.bytesToHex(script.chunks[1]), coinjs.multisig);
|
||||
break;
|
||||
case 118: //legacy
|
||||
address = btcOperator.util.encodeLegacy(Crypto.util.bytesToHex(script.chunks[2]), coinjs.pub);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
function checkIfLoanClosed(loan_id, borrower, lender) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var query_options = { sentOnly: true, tx: true, receivers: [floCrypto.toFloID(lender)] };
|
||||
|
||||
Loading…
Reference in New Issue
Block a user