Skip to content

Commit

Permalink
feat: better mobile feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
Keyrxng committed Apr 17, 2024
1 parent 941d461 commit 15a70bd
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 37 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
script: |
const { owner, repo } = context.repo;
const sha = "${{ github.event.workflow_run.head_sha }}";
const response = await github.rest.search.issuesAndPullRequests({
q: `repo:${owner}/${repo} is:pr sha:${sha}`,
per_page: 1,
Expand All @@ -82,11 +82,11 @@ jobs:
repo,
issue_number,
});
// Find the comment to update or create a new one if not found
let existingComment = comments.data.find(comment => comment.user.login === 'github-actions[bot]');
let body = '| Preview Deployment |\n| ------------------ |\n';
// If the comment exists, update its body
if (existingComment) {
// Check if the SHA already exists in the comment body to avoid duplicates
Expand Down
2 changes: 1 addition & 1 deletion .knip.jsonc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"entry": ["static/scripts/rewards/init.ts"],
"ignore": ["lib/**"]
"ignore": ["lib/**"],
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Value } from "@sinclair/typebox/value";
import { createClient } from "@supabase/supabase-js";
import { AppState, app } from "../app-state";
import { useFastestRpc } from "../rpc-optimization/get-optimal-provider";
import { buttonController, toaster } from "../toaster";
import { toaster } from "../toaster";
import { connectWallet } from "../web3/connect-wallet";
import { checkRenderInvalidatePermitAdminControl, checkRenderMakeClaimControl } from "../web3/erc20-permit";
import { verifyCurrentNetwork } from "../web3/verify-current-network";
Expand Down Expand Up @@ -31,25 +31,32 @@ export async function readClaimDataFromUrl(app: AppState) {

app.claims = decodeClaimData(base64encodedTxData).flat();
app.claimTxs = await getClaimedTxs(app);

try {
app.provider = await useFastestRpc(app);
} catch (e) {
toaster.create("error", `${e}`);
}
if (window.ethereum) {
try {
app.signer = await connectWallet();
} catch (error) {
/* empty */
}
window.ethereum.on("accountsChanged", () => {

try {
app.signer = await connectWallet();
} catch (error) {
/* empty */
}

try {
// this would throw on mobile browsers & non-web3 browsers
window?.ethereum.on("accountsChanged", () => {
checkRenderMakeClaimControl(app).catch(console.error);
checkRenderInvalidatePermitAdminControl(app).catch(console.error);
});
} else {
buttonController.hideAll();
toaster.create("info", "Please use a web3 enabled browser to collect this reward.");
} catch (err) {
/*
* handled feedback upstream already
* buttons are hidden and non-web3 infinite toast exists
*/
}

displayRewardDetails();
displayRewardPagination();

Expand Down
10 changes: 6 additions & 4 deletions static/scripts/rewards/toaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ export const viewClaimButton = document.getElementById("view-claim") as HTMLButt
const notifications = document.querySelector(".notifications") as HTMLUListElement;
export const buttonController = new ButtonController(controls);

function createToast(meaning: keyof typeof toaster.icons, text: string) {
function createToast(meaning: keyof typeof toaster.icons, text: string, timeout: number = 5000) {
if (meaning != "info") buttonController.hideLoader();
const toastDetails = {
timer: 5000,
timer: timeout,
} as {
timer: number;
timeoutId?: NodeJS.Timeout;
Expand All @@ -43,8 +43,10 @@ function createToast(meaning: keyof typeof toaster.icons, text: string) {

notifications.appendChild(toastContent); // Append the toast to the notification ul

// Setting a timeout to remove the toast after the specified duration
toastDetails.timeoutId = setTimeout(() => removeToast(toastContent, toastDetails.timeoutId), toastDetails.timer);
if (timeout !== Infinity) {
// Setting a timeout to remove the toast after the specified duration
toastDetails.timeoutId = setTimeout(() => removeToast(toastContent, toastDetails.timeoutId), toastDetails.timer);
}
}

function removeToast(toast: HTMLElement, timeoutId?: NodeJS.Timeout) {
Expand Down
28 changes: 21 additions & 7 deletions static/scripts/rewards/web3/connect-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,28 @@ export async function connectWallet(): Promise<JsonRpcSigner | null> {

return signer;
} catch (error: unknown) {
if (error instanceof Error) {
console.error(error);
if (error?.message?.includes("missing provider")) {
toaster.create("info", "Please use a web3 enabled browser to collect this reward.");
} else {
toaster.create("info", "Please connect your wallet to collect this reward.");
connectErrorHandler(error);
}
return null;
}

function connectErrorHandler(error: unknown) {
if (error instanceof Error) {
console.error(error);
if (error?.message?.includes("missing provider")) {
// mobile browsers don't really support window.ethereum
const mediaQuery = window.matchMedia("(max-width: 768px)");

if (mediaQuery.matches) {
toaster.create("warning", "Please use a mobile-friendly Web3 browser such as MetaMask to collect this reward", Infinity);
} else if (!window.ethereum) {
toaster.create("warning", "Please use a web3 enabled browser to collect this reward.", Infinity);
buttonController.hideAll();
}
} else {
toaster.create("error", error.message);
}
return null;
} else {
toaster.create("error", "An unknown error occurred.");
}
}
34 changes: 23 additions & 11 deletions static/scripts/rewards/web3/erc20-permit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { permit2Address } from "../constants";
import { supabase } from "../render-transaction/read-claim-data-from-url";
import { Erc20Permit, Erc721Permit } from "../render-transaction/tx-type";
import { MetaMaskError, buttonController, errorToast, getMakeClaimButton, toaster } from "../toaster";
import { connectWallet } from "./connect-wallet";

export async function fetchTreasury(
permit: Erc20Permit | Erc721Permit
Expand Down Expand Up @@ -60,6 +61,9 @@ async function checkPermitClaimability(app: AppState): Promise<boolean> {

async function transferFromPermit(permit2Contract: Contract, app: AppState) {
const reward = app.reward;
const signer = app.signer;
if (!signer) return null;

try {
const tx = await permit2Contract.permitTransferFrom(reward.permit, reward.transferDetails, reward.owner, reward.signature);
toaster.create("info", `Transaction sent`);
Expand Down Expand Up @@ -91,6 +95,7 @@ async function waitForTransaction(tx: TransactionResponse) {
buttonController.hideLoader();
buttonController.hideMakeClaim();
console.log(receipt.transactionHash);

return receipt;
} catch (error: unknown) {
if (error instanceof Error) {
Expand All @@ -103,21 +108,23 @@ async function waitForTransaction(tx: TransactionResponse) {

export function claimErc20PermitHandlerWrapper(app: AppState) {
return async function claimErc20PermitHandler() {
const signer = await connectWallet();
if (!signer) {
return;
}

buttonController.hideMakeClaim();
buttonController.showLoader();

const isPermitClaimable = await checkPermitClaimability(app);
if (!isPermitClaimable) return;

const permit2Contract = new ethers.Contract(permit2Address, permit2Abi, app.signer);
const permit2Contract = new ethers.Contract(permit2Address, permit2Abi, signer);
if (!permit2Contract) return;

const tx = await transferFromPermit(permit2Contract, app);
if (!tx) return;

// buttonController.showLoader();
// buttonController.hideMakeClaim();

const receipt = await waitForTransaction(tx);
if (!receipt) return;

Expand Down Expand Up @@ -168,9 +175,10 @@ async function checkPermitClaimable(app: AppState): Promise<boolean> {
return false;
}

let user: string;
let user: string | undefined;
try {
user = (await app.signer.getAddress()).toLowerCase();
const address = await app.signer?.getAddress();
user = address?.toLowerCase();
} catch (error: unknown) {
console.error("Error in signer.getAddress: ", error);
return false;
Expand All @@ -188,8 +196,8 @@ async function checkPermitClaimable(app: AppState): Promise<boolean> {

export async function checkRenderMakeClaimControl(app: AppState) {
try {
const address = await app.signer.getAddress();
const user = address.toLowerCase();
const address = await app.signer?.getAddress();
const user = address?.toLowerCase();

if (app.reward) {
const beneficiary = app.reward.transferDetails.to.toLowerCase();
Expand All @@ -207,8 +215,8 @@ export async function checkRenderMakeClaimControl(app: AppState) {

export async function checkRenderInvalidatePermitAdminControl(app: AppState) {
try {
const address = await app.signer.getAddress();
const user = address.toLowerCase();
const address = await app.signer?.getAddress();
const user = address?.toLowerCase();

if (app.reward) {
const owner = app.reward.owner.toLowerCase();
Expand Down Expand Up @@ -266,7 +274,11 @@ async function isNonceClaimed(app: AppState): Promise<boolean> {
return bit.and(flipped).eq(0);
}

async function invalidateNonce(signer: JsonRpcSigner, nonce: BigNumberish): Promise<void> {
async function invalidateNonce(signer: JsonRpcSigner | null, nonce: BigNumberish): Promise<void> {
if (!signer) {
console.error("Signer is null");
return;
}
const permit2Contract = new ethers.Contract(permit2Address, permit2Abi, signer);
const { wordPos, bitPos } = nonceBitmap(nonce);
// mimics https://github.com/ubiquity/pay.ubq.fi/blob/c9e7ed90718fe977fd9f348db27adf31d91d07fb/scripts/solidity/test/Permit2.t.sol#L428
Expand Down

0 comments on commit 15a70bd

Please sign in to comment.