Skip to content

Commit

Permalink
feat: add error modal
Browse files Browse the repository at this point in the history
  • Loading branch information
zugdev committed Nov 6, 2024
1 parent 449168e commit ea7cbff
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 48 deletions.
23 changes: 23 additions & 0 deletions src/common/display-popup-modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export function renderErrorInModal(error: Error) {
const modal = document.getElementById("modal");
const closeButton = document.getElementsByClassName("close-modal");
if (closeButton) {
closeButton[0].addEventListener("click", closeErrorModal);
}
const errorMessageElement = document.getElementById("error-message");

if (errorMessageElement) {
errorMessageElement.textContent = `${error.message}\n\n${error.stack || ""}`;
}

if (modal) {
modal.style.display = "flex";
}
}

export function closeErrorModal() {
const modal = document.getElementById("modal");
if (modal) {
modal.style.display = "none";
}
}
20 changes: 14 additions & 6 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import "./router";
import { createAppKit } from "@reown/appkit";
import { Ethers5Adapter } from "@reown/appkit-adapter-ethers5";
import { mainnet } from "@reown/appkit/networks";
import { ethers } from "ethers";
import "./router";
import { setupContracts } from "./contracts";
import { handleRouting } from "./router";
import { renderErrorInModal } from "./common/display-popup-modal";

// All unhandled errors are caught and displayed in a modal
window.addEventListener("error", (event: ErrorEvent) => renderErrorInModal(event.error));

// All unhandled promise rejections are caught and displayed in a modal
window.addEventListener("unhandledrejection", (event: PromiseRejectionEvent) => {
renderErrorInModal(event.reason as Error);
event.preventDefault();
});

const projectId = "415760038f8e330de4868120be3205b8";

Expand All @@ -17,7 +27,7 @@ const metadata = {

// create provider & signer for Ethereum mainnet
export const provider = new ethers.providers.JsonRpcProvider("https://eth.llamarpc.com");
export let userSigner : ethers.Signer;
export let userSigner: ethers.Signer;

// setup contract instances
export const { dollarContract, governanceContract, diamondContract, twapOracleContract } = setupContracts(provider);
Expand Down Expand Up @@ -50,7 +60,7 @@ async function waitForConnection() {

// global dollar and governance prices
export let dollarSpotPrice: string | null = null;
export let dollarTwapPrice: string | null = null;
export const dollarTwapPrice: string | null = null;
export let governanceSpotPrice: string | null = null;

async function updatePrices() {
Expand All @@ -60,7 +70,6 @@ async function updatePrices() {

dollarSpotPrice = ethers.utils.formatUnits(dollarSpotPriceRaw, 6);
governanceSpotPrice = ethers.utils.formatUnits(governanceSpotPriceRaw, 6);

} catch (error) {
console.error("Error getting prices:", error);
}
Expand All @@ -72,7 +81,6 @@ export async function mainModule() {

console.log("Waiting for user connection...");
void waitForConnection();

await updatePrices();

handleRouting();
Expand All @@ -83,4 +91,4 @@ export async function mainModule() {

mainModule().catch((error) => {
console.error("Unhandled error:", error);
});
});
39 changes: 18 additions & 21 deletions src/pages/mint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { appState, diamondContract, dollarSpotPrice, governanceSpotPrice, userSi
import { debounce } from "../utils";
import { CollateralOption, fetchCollateralOptions, populateCollateralDropdown } from "../common/collateral";
import { toggleSlippageSettings } from "../common/render-slippage-toggle";
import { renderErrorInModal } from "../common/display-popup-modal";

let currentOutput: {
totalDollarMint: ethers.BigNumber;
Expand Down Expand Up @@ -37,7 +38,7 @@ export async function loadMintPage() {
handleSlippageInput();

// link mint button
linkMintButton();
await linkMintButton();
} catch (error) {
console.error("Error loading mint page:", error);
}
Expand All @@ -47,7 +48,7 @@ export async function loadMintPage() {
async function calculateMintOutput(
selectedCollateral: CollateralOption,
dollarAmount: ethers.BigNumber,
forceCollateralOnlyChecked: boolean
isForceCollateralOnlyChecked: boolean
): Promise<{
totalDollarMint: ethers.BigNumber;
collateralNeeded: ethers.BigNumber;
Expand All @@ -61,7 +62,7 @@ async function calculateMintOutput(
let collateralNeeded: ethers.BigNumber;
let governanceNeeded: ethers.BigNumber;

if (forceCollateralOnlyChecked || collateralRatio.gte(poolPricePrecision)) {
if (isForceCollateralOnlyChecked || collateralRatio.gte(poolPricePrecision)) {
collateralNeeded = await diamondContract.getDollarInCollateral(selectedCollateral.index, dollarAmount);
governanceNeeded = ethers.BigNumber.from(0);
} else if (collateralRatio.isZero()) {
Expand All @@ -77,10 +78,7 @@ async function calculateMintOutput(

const mintingFee = ethers.utils.parseUnits(selectedCollateral.mintingFee.toString(), 6);
// Calculate the dollar value of the minting fee
const mintingFeeInDollar = await diamondContract.getDollarInCollateral(
selectedCollateral.index,
dollarAmount.mul(mintingFee).div(poolPricePrecision)
);
const mintingFeeInDollar = await diamondContract.getDollarInCollateral(selectedCollateral.index, dollarAmount.mul(mintingFee).div(poolPricePrecision));

const totalDollarMint = dollarAmount.mul(poolPricePrecision.sub(mintingFee)).div(poolPricePrecision);

Expand All @@ -96,12 +94,12 @@ function handleCollateralInput(collateralOptions: CollateralOption[]) {
const selectedCollateralIndex = collateralSelect.value;
const dollarAmountRaw = dollarAmountInput.value;
const dollarAmount = ethers.utils.parseUnits(dollarAmountRaw || "0", 18);
const forceCollateralOnlyChecked = forceCollateralOnly.checked;
const isForceCollateralOnlyChecked = forceCollateralOnly.checked;

const selectedCollateral = collateralOptions.find((option) => option.index.toString() === selectedCollateralIndex);

if (selectedCollateral) {
currentOutput = await calculateMintOutput(selectedCollateral, dollarAmount, forceCollateralOnlyChecked);
currentOutput = await calculateMintOutput(selectedCollateral, dollarAmount, isForceCollateralOnlyChecked);
displayMintOutput(currentOutput, selectedCollateral);
}
}, 300); // 300ms debounce
Expand Down Expand Up @@ -153,13 +151,9 @@ function displayMintOutput(
const mintingFeeElement = document.getElementById("mintingFee");

const formattedTotalDollarMint = parseFloat(ethers.utils.formatUnits(output.totalDollarMint, 18)).toFixed(2);
const formattedCollateralNeeded = parseFloat(
ethers.utils.formatUnits(output.collateralNeeded, 18 - selectedCollateral.missingDecimals)
).toFixed(2);
const formattedCollateralNeeded = parseFloat(ethers.utils.formatUnits(output.collateralNeeded, 18 - selectedCollateral.missingDecimals)).toFixed(2);
const formattedGovernanceNeeded = parseFloat(ethers.utils.formatUnits(output.governanceNeeded, 18)).toFixed(2);
const formattedmintingFeeInDollar = parseFloat(
ethers.utils.formatUnits(output.mintingFeeInDollar, 18 - selectedCollateral.missingDecimals)
).toFixed(2);
const formattedmintingFeeInDollar = parseFloat(ethers.utils.formatUnits(output.mintingFeeInDollar, 18 - selectedCollateral.missingDecimals)).toFixed(2);

// Calculate the dollar value of totalDollarMint and governanceNeeded using spot prices
const totalDollarMintValue = output.totalDollarMint.mul(ethers.utils.parseUnits(dollarSpotPrice as string, 18)).div(ethers.constants.WeiPerEther);
Expand All @@ -182,7 +176,7 @@ function displayMintOutput(
}
}

function linkMintButton() {
async function linkMintButton() {
const mintButton = document.getElementById("mintButton") as HTMLButtonElement;
const collateralSelect = document.getElementById("collateralSelect") as HTMLSelectElement;
const dollarAmountInput = document.getElementById("dollarAmount") as HTMLInputElement;
Expand All @@ -192,7 +186,7 @@ function linkMintButton() {
const selectedCollateralIndex = collateralSelect.value;
const dollarAmountRaw = dollarAmountInput.value;
const dollarAmount = dollarAmountRaw ? ethers.utils.parseUnits(dollarAmountRaw, 18) : null;

mintButton.disabled = !appState.getIsConnectedState() || !selectedCollateralIndex || !dollarAmount || dollarAmount.isZero();
};

Expand All @@ -209,26 +203,29 @@ function linkMintButton() {
const dollarOutMin = ethers.BigNumber.from("0");
const maxCollateralIn = ethers.constants.MaxUint256;
const maxGovernanceIn = ethers.constants.MaxUint256;
const forceCollateralOnlyChecked = forceCollateralOnly.checked;
const isForceCollateralOnlyChecked = forceCollateralOnly.checked;

try {
const signerDiamondContract = diamondContract.connect(userSigner);

console.log("Minting", parseInt(selectedCollateralIndex), dollarAmount, dollarOutMin, maxCollateralIn, maxGovernanceIn, isForceCollateralOnlyChecked);

await signerDiamondContract.mintDollar(
parseInt(selectedCollateralIndex),
dollarAmount,
dollarOutMin,
maxCollateralIn,
maxGovernanceIn,
forceCollateralOnlyChecked
isForceCollateralOnlyChecked
);

alert("Minting transaction sent successfully!");
} catch (error) {
console.error("Minting transaction failed:", error);
renderErrorInModal(error instanceof Error ? error : new Error(String(error)));
}
});

// Initialize the button state on page load
updateButtonState();
}
await updateButtonState();
}
33 changes: 12 additions & 21 deletions src/pages/redeem.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ethers } from "ethers";
import { appState, diamondContract, dollarSpotPrice, governanceSpotPrice, userSigner } from "../main";
import { appState, diamondContract, governanceSpotPrice, userSigner } from "../main";
import { debounce } from "../utils";
import { CollateralOption, fetchCollateralOptions, populateCollateralDropdown } from "../common/collateral";
import { toggleSlippageSettings } from "../common/render-slippage-toggle";
import { renderErrorInModal } from "../common/display-popup-modal";

let currentOutput: {
collateralRedeemed: ethers.BigNumber;
Expand Down Expand Up @@ -36,7 +37,7 @@ export async function loadRedeemPage() {
handleSlippageInput();

// link redeem button
linkRedeemButton();
await linkRedeemButton();
} catch (error) {
console.error("Error loading redeem page:", error);
}
Expand Down Expand Up @@ -68,7 +69,7 @@ async function calculateRedeemOutput(
collateralRedeemed = ethers.BigNumber.from(0);
governanceRedeemed = dollarAfterFee.mul(poolPricePrecision).div(governancePrice);
} else {
const collateralOut = await diamondContract.getDollarInCollateral(selectedCollateral.index, dollarAfterFee)
const collateralOut = await diamondContract.getDollarInCollateral(selectedCollateral.index, dollarAfterFee);
collateralRedeemed = collateralOut.mul(collateralRatio).div(poolPricePrecision);
governanceRedeemed = dollarAfterFee.mul(poolPricePrecision.sub(collateralRatio)).div(governancePrice);
}
Expand Down Expand Up @@ -129,14 +130,10 @@ function displayRedeemOutput(
const governanceRedeemedElement = document.getElementById("governanceRedeemed");
const redemptionFeeElement = document.getElementById("redemptionFee");

const formattedCollateralRedeemed = parseFloat(
ethers.utils.formatUnits(output.collateralRedeemed, 18 - selectedCollateral.missingDecimals)
).toFixed(2);
const formattedCollateralRedeemed = parseFloat(ethers.utils.formatUnits(output.collateralRedeemed, 18 - selectedCollateral.missingDecimals)).toFixed(2);

const formattedGovernanceRedeemed = parseFloat(ethers.utils.formatUnits(output.governanceRedeemed, 18)).toFixed(2);
const formattedRedemptionFeeInDollar = parseFloat(
ethers.utils.formatUnits(output.redemptionFeeInDollar, 18)
).toFixed(2);
const formattedRedemptionFeeInDollar = parseFloat(ethers.utils.formatUnits(output.redemptionFeeInDollar, 18)).toFixed(2);

// Calculate dollar value of governance redeemed
const governanceDollarValue = output.governanceRedeemed.mul(ethers.utils.parseUnits(governanceSpotPrice as string, 18)).div(ethers.constants.WeiPerEther);
Expand All @@ -153,7 +150,7 @@ function displayRedeemOutput(
}
}

function linkRedeemButton() {
async function linkRedeemButton() {
const redeemButton = document.getElementById("redeemButton") as HTMLButtonElement;
const collateralSelect = document.getElementById("collateralSelect") as HTMLSelectElement;
const dollarAmountInput = document.getElementById("dollarAmount") as HTMLInputElement;
Expand All @@ -179,24 +176,18 @@ function linkRedeemButton() {
try {
const signerDiamondContract = diamondContract.connect(userSigner);

await signerDiamondContract.redeemDollar(
parseInt(selectedCollateralIndex),
dollarAmount,
governanceOutMin,
collateralOutMin
);
await signerDiamondContract.redeemDollar(parseInt(selectedCollateralIndex), dollarAmount, governanceOutMin, collateralOutMin);

// After redeemDollar succeeds, initiate the collection
await signerDiamondContract.collectRedemption(parseInt(selectedCollateralIndex));

alert("Redemption collected successfully!");

alert("Redemption collected successfully!");
} catch (error) {
console.error("Redemption transaction or collection failed:", error);
alert("Redemption transaction or collection failed. Please try again.");
renderErrorInModal(error instanceof Error ? error : new Error(String(error)));
}
});

// Initialize the button state on page load
updateButtonState();
}
await updateButtonState();
}
16 changes: 16 additions & 0 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@
<w3m-button></w3m-button>
</header>

<div id="modal" class="error-modal">
<div class="error-modal-content">
<div class="error-modal-header">
<button class="close-modal">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960">
<path d="m336-280-56-56 144-144-144-143 56-56 144 144 143-144 56 56-144 143 144 144-56 56-143-144-144 144Z"></path>
</svg>
</button>
<h1 class="error-title">Error</h1>
</div>
<div class="error-modal-body">
<div id="error-message" class="error-message"></div>
</div>
</div>
</div>

<div id="content-area"></div>

<script type="module" src="dist/src/main.js"></script>
Expand Down
63 changes: 63 additions & 0 deletions static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,69 @@ w3m-network-button {
margin-left: 10px;
}

/* Error Modal */

.error-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
justify-content: center;
align-items: center;
z-index: 1000;
}

.error-modal-content {
background-color: white;
padding: 20px;
border-radius: 8px;
width: 90%;
max-width: 500px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.error-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
}

.error-title {
font-size: 1.5rem;
margin: 0;
color: #d9534f;
}

.close-modal {
background: none;
border: none;
cursor: pointer;
color: #333;
}

.close-modal svg {
width: 24px;
height: 24px;
}

.error-modal-body {
margin-top: 10px;
color: #333;
font-size: 1rem;
line-height: 1.5;
}

.error-message {
max-height: 600px;
white-space: pre-wrap;
text-overflow: ellipsis;
overflow: hidden;
word-break: break-word;
}

/* Content Area Styles */

#content-area {
Expand Down

0 comments on commit ea7cbff

Please sign in to comment.