221 lines
8.2 KiB
JavaScript
221 lines
8.2 KiB
JavaScript
|
|
const COLLATERAL_CLAIM_FEE_ATOMIC = 300000000n;
|
||
|
|
let collateralClaimContracts = [];
|
||
|
|
let collateralClaimLoadPromise = null;
|
||
|
|
let collateralClaimContractsKey = "";
|
||
|
|
|
||
|
|
function setCollateralClaimMessage(message, type = "") {
|
||
|
|
setScopedTransactionMessage("Collateral Claim", collateralClaimMessage, message, type);
|
||
|
|
}
|
||
|
|
|
||
|
|
function selectedCollateralClaimContract() {
|
||
|
|
const hash = String(collateralClaimContractSelect?.value || "");
|
||
|
|
return collateralClaimContracts.find((contract) => contract.contract === hash) || null;
|
||
|
|
}
|
||
|
|
|
||
|
|
function claimAssetLabel(asset, amount) {
|
||
|
|
return `${atomicToDecimal(BigInt(amount || "0"))} ${String(asset || "").trim()}`.trim();
|
||
|
|
}
|
||
|
|
|
||
|
|
function collateralClaimOptionLabel(contract) {
|
||
|
|
const role = String(contract.role || "").toLowerCase() === "borrower"
|
||
|
|
? "reclaim"
|
||
|
|
: "claim";
|
||
|
|
return `${role} ${claimAssetLabel(contract.collateral, contract.collateral_amount)} from ${truncateMiddle(contract.contract, 8, 8)}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
function populateCollateralClaimContracts() {
|
||
|
|
if (!collateralClaimContractSelect) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const previous = collateralClaimContractSelect.value;
|
||
|
|
collateralClaimContractSelect.innerHTML = "";
|
||
|
|
if (collateralClaimContracts.length) {
|
||
|
|
const placeholder = document.createElement("option");
|
||
|
|
placeholder.value = "";
|
||
|
|
placeholder.textContent = "Select claimable collateral";
|
||
|
|
collateralClaimContractSelect.appendChild(placeholder);
|
||
|
|
}
|
||
|
|
collateralClaimContracts.forEach((contract) => {
|
||
|
|
const option = document.createElement("option");
|
||
|
|
option.value = contract.contract;
|
||
|
|
option.textContent = collateralClaimOptionLabel(contract);
|
||
|
|
collateralClaimContractSelect.appendChild(option);
|
||
|
|
});
|
||
|
|
if (!collateralClaimContracts.length) {
|
||
|
|
const option = document.createElement("option");
|
||
|
|
option.value = "";
|
||
|
|
option.textContent = "No collateral is currently claimable";
|
||
|
|
collateralClaimContractSelect.appendChild(option);
|
||
|
|
} else if ([...collateralClaimContractSelect.options].some((option) => option.value === previous)) {
|
||
|
|
collateralClaimContractSelect.value = previous;
|
||
|
|
}
|
||
|
|
updateCollateralClaimDetails();
|
||
|
|
}
|
||
|
|
|
||
|
|
async function loadCollateralClaimContracts(force = false) {
|
||
|
|
if (collateralClaimLoadPromise) {
|
||
|
|
return collateralClaimLoadPromise;
|
||
|
|
}
|
||
|
|
const invoke = window.__TAURI__?.core?.invoke;
|
||
|
|
const broadcastNode = activeBroadcastNode();
|
||
|
|
if (!invoke || !broadcastNode || !walletLoaded || !registrationRegistered) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const key = `${activeWalletAddressShort || activeWalletAddressHex}|${broadcastNode}`;
|
||
|
|
if (!force && collateralClaimContractsKey === key) {
|
||
|
|
populateCollateralClaimContracts();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
collateralClaimLoadPromise = (async () => {
|
||
|
|
setCollateralClaimMessage("Loading claimable collateral...");
|
||
|
|
const contracts = await invoke("claimable_collateral_contracts", { broadcastNode });
|
||
|
|
collateralClaimContracts = Array.isArray(contracts) ? contracts : [];
|
||
|
|
collateralClaimContractsKey = key;
|
||
|
|
populateCollateralClaimContracts();
|
||
|
|
setCollateralClaimMessage(
|
||
|
|
collateralClaimContracts.length ? "" : "No collateral is currently claimable."
|
||
|
|
);
|
||
|
|
})().catch((error) => {
|
||
|
|
collateralClaimContracts = [];
|
||
|
|
populateCollateralClaimContracts();
|
||
|
|
setCollateralClaimMessage(String(error), "error");
|
||
|
|
throw error;
|
||
|
|
}).finally(() => {
|
||
|
|
collateralClaimLoadPromise = null;
|
||
|
|
});
|
||
|
|
return collateralClaimLoadPromise;
|
||
|
|
}
|
||
|
|
|
||
|
|
function updateCollateralClaimDetails() {
|
||
|
|
const contract = selectedCollateralClaimContract();
|
||
|
|
if (!contract) {
|
||
|
|
collateralClaimRole.textContent = "--";
|
||
|
|
collateralClaimReason.textContent = "--";
|
||
|
|
collateralClaimLender.textContent = "--";
|
||
|
|
collateralClaimBorrower.textContent = "--";
|
||
|
|
collateralClaimLoan.textContent = "--";
|
||
|
|
collateralClaimCollateral.textContent = "--";
|
||
|
|
collateralClaimConfirmed.textContent = "--";
|
||
|
|
collateralClaimRemaining.textContent = "--";
|
||
|
|
collateralClaimFeeInput.value = atomicToDecimal(COLLATERAL_CLAIM_FEE_ATOMIC);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
collateralClaimRole.textContent = contract.role === "borrower" ? "Borrower reclaim" : "Lender claim";
|
||
|
|
collateralClaimReason.textContent = contract.reason || "Collateral claim is currently allowed.";
|
||
|
|
collateralClaimLender.textContent = contract.lender;
|
||
|
|
collateralClaimBorrower.textContent = contract.borrower;
|
||
|
|
collateralClaimLoan.textContent = claimAssetLabel(contract.loan_asset, contract.loan_amount);
|
||
|
|
collateralClaimCollateral.textContent = claimAssetLabel(contract.collateral, contract.collateral_amount);
|
||
|
|
collateralClaimConfirmed.textContent = claimAssetLabel(contract.loan_asset, contract.confirmed_paid);
|
||
|
|
collateralClaimRemaining.textContent = claimAssetLabel(contract.loan_asset, contract.remaining_balance);
|
||
|
|
collateralClaimFeeInput.value = atomicToDecimal(BigInt(contract.fee || COLLATERAL_CLAIM_FEE_ATOMIC));
|
||
|
|
}
|
||
|
|
|
||
|
|
function validateCollateralClaimForm() {
|
||
|
|
if (!walletLoaded) {
|
||
|
|
return "Load a wallet before claiming collateral.";
|
||
|
|
}
|
||
|
|
if (!registrationRegistered) {
|
||
|
|
return "Address registration is required before claiming collateral.";
|
||
|
|
}
|
||
|
|
if (!selectedCollateralClaimContract()) {
|
||
|
|
return "Select claimable collateral.";
|
||
|
|
}
|
||
|
|
if (baseCoinBalanceAtomic() < COLLATERAL_CLAIM_FEE_ATOMIC) {
|
||
|
|
return `Claiming collateral requires ${atomicToDecimal(COLLATERAL_CLAIM_FEE_ATOMIC)} ${activeBaseCoin()} for the transaction fee.`;
|
||
|
|
}
|
||
|
|
return "";
|
||
|
|
}
|
||
|
|
|
||
|
|
function collateralClaimPayload() {
|
||
|
|
return {
|
||
|
|
broadcastNode: activeBroadcastNode(),
|
||
|
|
contractHash: selectedCollateralClaimContract().contract
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function setCollateralClaimButtonsDisabled(disabled) {
|
||
|
|
document.querySelector("[data-collateral-claim-save]")?.toggleAttribute("disabled", disabled);
|
||
|
|
document.querySelector("[data-collateral-claim-broadcast]")?.toggleAttribute("disabled", disabled);
|
||
|
|
}
|
||
|
|
|
||
|
|
function clearCollateralClaimForm() {
|
||
|
|
collateralClaimContractSelect.value = "";
|
||
|
|
updateCollateralClaimDetails();
|
||
|
|
}
|
||
|
|
|
||
|
|
async function handleCollateralClaimAction(action) {
|
||
|
|
const validationError = validateCollateralClaimForm();
|
||
|
|
if (validationError) {
|
||
|
|
setCollateralClaimMessage(validationError, "error");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const invoke = window.__TAURI__?.core?.invoke;
|
||
|
|
if (!invoke) {
|
||
|
|
setCollateralClaimMessage("Wallet bridge is not available.", "error");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const walletKey = await requestSigningWalletKey();
|
||
|
|
if (guiRuntimeSettings.require_key_before_signing !== false && !walletKey) {
|
||
|
|
setCollateralClaimMessage("Signing cancelled.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
setCollateralClaimButtonsDisabled(true);
|
||
|
|
try {
|
||
|
|
if (action === "save") {
|
||
|
|
setCollateralClaimMessage("Saving collateral claim transaction...");
|
||
|
|
const review = await invoke("save_collateral_claim_transaction", {
|
||
|
|
...collateralClaimPayload(),
|
||
|
|
walletKey
|
||
|
|
});
|
||
|
|
clearCollateralClaimForm();
|
||
|
|
setCollateralClaimMessage(`Collateral claim saved: ${review.file_name}`, "success");
|
||
|
|
if (typeof refreshUnbroadcastTransactions === "function") {
|
||
|
|
refreshUnbroadcastTransactions();
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
setCollateralClaimMessage("Broadcasting collateral claim...");
|
||
|
|
const result = await invoke("broadcast_collateral_claim_transaction", {
|
||
|
|
...collateralClaimPayload(),
|
||
|
|
walletKey
|
||
|
|
});
|
||
|
|
await loadCollateralClaimContracts(true);
|
||
|
|
clearCollateralClaimForm();
|
||
|
|
setCollateralClaimMessage(result.response || "Collateral claim broadcast.", "success");
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
setCollateralClaimMessage(String(error), "error");
|
||
|
|
await loadCollateralClaimContracts(true).catch(() => {});
|
||
|
|
} finally {
|
||
|
|
setCollateralClaimButtonsDisabled(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function prepareCollateralClaimForm() {
|
||
|
|
setCollateralClaimMessage("");
|
||
|
|
loadCollateralClaimContracts(false).catch(() => {});
|
||
|
|
}
|
||
|
|
|
||
|
|
function resetCollateralClaimSession() {
|
||
|
|
collateralClaimContracts = [];
|
||
|
|
collateralClaimLoadPromise = null;
|
||
|
|
collateralClaimContractsKey = "";
|
||
|
|
collateralClaimContractSelect.innerHTML = "";
|
||
|
|
updateCollateralClaimDetails();
|
||
|
|
setCollateralClaimMessage("");
|
||
|
|
}
|
||
|
|
|
||
|
|
collateralClaimContractSelect?.addEventListener("change", () => {
|
||
|
|
setCollateralClaimMessage("");
|
||
|
|
updateCollateralClaimDetails();
|
||
|
|
});
|
||
|
|
document
|
||
|
|
.querySelector("[data-collateral-claim-save]")
|
||
|
|
?.addEventListener("click", () => handleCollateralClaimAction("save"));
|
||
|
|
document
|
||
|
|
.querySelector("[data-collateral-claim-broadcast]")
|
||
|
|
?.addEventListener("click", () => handleCollateralClaimAction("broadcast"));
|