diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml
index 6b3066e5..a6bba39b 100644
--- a/.github/workflows/conventional-commits.yml
+++ b/.github/workflows/conventional-commits.yml
@@ -2,11 +2,12 @@ name: Conventional Commits
on:
push:
+ pull_request:
jobs:
conventional-commits:
name: Conventional Commits
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: ubiquity/action-conventional-commits@master
diff --git a/static/scripts/rewards/app-state.ts b/static/scripts/rewards/app-state.ts
index 002b0ee6..4d5d7ebd 100644
--- a/static/scripts/rewards/app-state.ts
+++ b/static/scripts/rewards/app-state.ts
@@ -1,14 +1,23 @@
import { JsonRpcProvider } from "@ethersproject/providers";
import { networkExplorers } from "./constants";
-import { ClaimTx } from "./render-transaction/tx-type";
+import { RewardPermit } from "./render-transaction/tx-type";
export class AppState {
- public claims: ClaimTx[] = [];
+ public claims: RewardPermit[] = [];
private _provider!: JsonRpcProvider;
private _currentIndex = 0;
+ private _signer;
+
+ get signer() {
+ return this._signer;
+ }
+
+ set signer(value) {
+ this._signer = value;
+ }
get networkId(): number | null {
- return this.transaction?.networkId || null;
+ return this.permit?.networkId || null;
}
get provider(): JsonRpcProvider {
@@ -19,33 +28,33 @@ export class AppState {
this._provider = value;
}
- get transactionIndex(): number {
+ get permitIndex(): number {
return this._currentIndex;
}
- get transaction(): ClaimTx | null {
- return this.transactionIndex < this.claims.length ? this.claims[this.transactionIndex] : null;
+ get permit(): RewardPermit {
+ return this.permitIndex < this.claims.length ? this.claims[this.permitIndex] : this.claims[0];
}
- get transactionNetworkId() {
- return this.transaction?.networkId;
+ get permitNetworkId() {
+ return this.permit?.networkId;
}
get currentExplorerUrl(): string {
- if (!this.transaction) {
+ if (!this.permit) {
return "https://etherscan.io";
}
- return networkExplorers[this.transaction.networkId] || "https://etherscan.io";
+ return networkExplorers[this.permit.networkId] || "https://etherscan.io";
}
- nextTx(): ClaimTx | null {
+ nextPermit(): RewardPermit | null {
this._currentIndex = Math.min(this.claims.length - 1, this._currentIndex + 1);
- return this.transaction;
+ return this.permit;
}
- previousTx(): ClaimTx | null {
+ previousPermit(): RewardPermit | null {
this._currentIndex = Math.max(0, this._currentIndex - 1);
- return this.transaction;
+ return this.permit;
}
}
diff --git a/static/scripts/rewards/init.ts b/static/scripts/rewards/init.ts
index 8fd646ea..07141cf3 100644
--- a/static/scripts/rewards/init.ts
+++ b/static/scripts/rewards/init.ts
@@ -1,10 +1,11 @@
+import { app } from "./app-state";
import { readClaimDataFromUrl } from "./render-transaction/read-claim-data-from-url";
import { grid } from "./the-grid";
displayCommitHash(); // @DEV: display commit hash in footer
grid(document.getElementById("grid") as HTMLElement); // @DEV: display grid background
-readClaimDataFromUrl().catch(console.error); // @DEV: read claim data from URL
+readClaimDataFromUrl(app).catch(console.error); // @DEV: read claim data from URL
declare const commitHash: string; // @DEV: passed in at build time check build/esbuild-build.ts
function displayCommitHash() {
diff --git a/static/scripts/rewards/render-transaction/claim-rewards-pagination.ts b/static/scripts/rewards/render-transaction/claim-rewards-pagination.ts
index 60f6d9c1..1559a1c9 100644
--- a/static/scripts/rewards/render-transaction/claim-rewards-pagination.ts
+++ b/static/scripts/rewards/render-transaction/claim-rewards-pagination.ts
@@ -6,15 +6,15 @@ import { setPagination } from "./set-pagination";
import { removeAllEventListeners } from "./utils";
export function claimRewardsPagination(rewardsCount: HTMLElement) {
- rewardsCount.innerHTML = `${app.transactionIndex + 1}/${app.claims.length} reward`;
+ rewardsCount.innerHTML = `${app.permitIndex + 1}/${app.claims.length} reward`;
const nextTxButton = document.getElementById("nextTx");
if (nextTxButton) {
nextTxButton.addEventListener("click", () => {
claimButton.element = removeAllEventListeners(claimButton.element) as HTMLButtonElement;
- app.nextTx();
- rewardsCount.innerHTML = `${app.transactionIndex + 1}/${app.claims.length} reward`;
- table.setAttribute(`data-claim`, "none");
+ app.nextPermit();
+ rewardsCount.innerHTML = `${app.permitIndex + 1}/${app.claims.length} reward`;
+ table.setAttribute(`data-claim`, "error");
renderTransaction(true).catch(console.error);
});
}
@@ -23,9 +23,9 @@ export function claimRewardsPagination(rewardsCount: HTMLElement) {
if (prevTxButton) {
prevTxButton.addEventListener("click", () => {
claimButton.element = removeAllEventListeners(claimButton.element) as HTMLButtonElement;
- app.previousTx();
- rewardsCount.innerHTML = `${app.transactionIndex + 1}/${app.claims.length} reward`;
- table.setAttribute(`data-claim`, "none");
+ app.previousPermit();
+ rewardsCount.innerHTML = `${app.permitIndex + 1}/${app.claims.length} reward`;
+ table.setAttribute(`data-claim`, "error");
renderTransaction(true).catch(console.error);
});
}
diff --git a/static/scripts/rewards/render-transaction/insert-table-data.ts b/static/scripts/rewards/render-transaction/insert-table-data.ts
index e19a306f..60ff1c01 100644
--- a/static/scripts/rewards/render-transaction/insert-table-data.ts
+++ b/static/scripts/rewards/render-transaction/insert-table-data.ts
@@ -1,16 +1,17 @@
import { BigNumber, ethers } from "ethers";
-import { app } from "../app-state";
-import { Erc20Permit, Erc721Permit } from "./tx-type";
+import { AppState, app } from "../app-state";
+import { Erc721Permit } from "./tx-type";
export function shortenAddress(address: string): string {
return `${address.slice(0, 10)}...${address.slice(-8)}`;
}
export function insertErc20PermitTableData(
- permit: Erc20Permit,
+ app: AppState,
table: Element,
treasury: { balance: BigNumber; allowance: BigNumber; decimals: number; symbol: string }
): Element {
+ const permit = app.permit;
const requestedAmountElement = document.getElementById("rewardAmount") as Element;
renderToFields(permit.transferDetails.to, app.currentExplorerUrl);
renderTokenFields(permit.permit.permitted.token, app.currentExplorerUrl);
@@ -18,7 +19,10 @@ export function insertErc20PermitTableData(
{ name: "From", value: `${permit.owner}` },
{
name: "Expiry",
- value: permit.permit.deadline.lte(Number.MAX_SAFE_INTEGER.toString()) ? new Date(permit.permit.deadline.toNumber()).toLocaleString() : undefined,
+ value: (() => {
+ const deadline = BigNumber.isBigNumber(permit.permit.deadline) ? permit.permit.deadline : BigNumber.from(permit.permit.deadline);
+ return deadline.lte(Number.MAX_SAFE_INTEGER.toString()) ? new Date(deadline.toNumber()).toLocaleString() : undefined;
+ })(),
},
{ name: "Balance", value: treasury.balance.gte(0) ? `${ethers.utils.formatUnits(treasury.balance, treasury.decimals)} ${treasury.symbol}` : "N/A" },
{ name: "Allowance", value: treasury.allowance.gte(0) ? `${ethers.utils.formatUnits(treasury.allowance, treasury.decimals)} ${treasury.symbol}` : "N/A" },
diff --git a/static/scripts/rewards/render-transaction/read-claim-data-from-url.ts b/static/scripts/rewards/render-transaction/read-claim-data-from-url.ts
index 327e4a65..0763b8fc 100644
--- a/static/scripts/rewards/render-transaction/read-claim-data-from-url.ts
+++ b/static/scripts/rewards/render-transaction/read-claim-data-from-url.ts
@@ -1,44 +1,46 @@
import { Type } from "@sinclair/typebox";
import { Value } from "@sinclair/typebox/value";
-import { app } from "../app-state";
-import { setClaimMessage } from "./set-claim-message";
-import { claimTxT } from "./tx-type";
+import { AppState, app } from "../app-state";
+import { useFastestRpc } from "../rpc-optimization/get-optimal-provider";
+import { connectWallet } from "../web3/connect-wallet";
+import { verifyCurrentNetwork } from "../web3/verify-current-network";
import { claimRewardsPagination } from "./claim-rewards-pagination";
import { renderTransaction } from "./render-transaction";
-import { getOptimalProvider } from "../rpc-optimization/get-optimal-provider";
+import { setClaimMessage } from "./set-claim-message";
+import { claimTxT } from "./tx-type";
export const table = document.getElementsByTagName(`table`)[0];
const urlParams = new URLSearchParams(window.location.search);
const base64encodedTxData = urlParams.get("claim");
-export async function readClaimDataFromUrl() {
+export async function readClaimDataFromUrl(app: AppState) {
if (!base64encodedTxData) {
// No claim data found
setClaimMessage({ type: "Notice", message: `No claim data found.` });
- table.setAttribute(`data-claim`, "none");
+ table.setAttribute(`data-claim`, "error");
return;
}
- decodeClaimData(base64encodedTxData);
-
- await getOptimalProvider(app);
-
+ app.claims = decodeClaimData(base64encodedTxData);
+ app.provider = await useFastestRpc(app);
+ const networkId = app.permit?.networkId || app.networkId;
+ app.signer = await connectWallet(networkId).catch(console.error);
displayRewardDetails();
displayRewardPagination();
renderTransaction(true)
- // .then(() => verifyCurrentNetwork(app.transaction?.networkId || app.networkId)) // @todo: verifyCurrentNetwork
+ .then(() => verifyCurrentNetwork(networkId))
.catch(console.error);
}
function decodeClaimData(base64encodedTxData: string) {
try {
- const claimTxs = Value.Decode(Type.Array(claimTxT), JSON.parse(atob(base64encodedTxData)));
- app.claims = claimTxs;
+ return Value.Decode(Type.Array(claimTxT), JSON.parse(atob(base64encodedTxData)));
} catch (error) {
console.error(error);
setClaimMessage({ type: "Error", message: `Invalid claim data passed in URL` });
table.setAttribute(`data-claim`, "error");
+ throw error;
}
}
@@ -56,7 +58,6 @@ function displayRewardPagination() {
function displayRewardDetails() {
let isDetailsVisible = false;
table.setAttribute(`data-details-visible`, isDetailsVisible.toString());
-
const additionalDetails = document.getElementById(`additionalDetails`) as HTMLElement;
additionalDetails.addEventListener("click", () => {
isDetailsVisible = !isDetailsVisible;
diff --git a/static/scripts/rewards/render-transaction/render-transaction.ts b/static/scripts/rewards/render-transaction/render-transaction.ts
index 960230ab..768aa04c 100644
--- a/static/scripts/rewards/render-transaction/render-transaction.ts
+++ b/static/scripts/rewards/render-transaction/render-transaction.ts
@@ -1,7 +1,7 @@
import { app } from "../app-state";
import { networkExplorers } from "../constants";
import { claimButton, hideLoader } from "../toaster";
-import { claimErc20PermitHandlerWrapper, fetchTreasury, generateInvalidatePermitAdminControl } from "../web3/erc20-permit";
+import { claimErc20PermitHandlerWrapper, fetchFundingWallet, generateInvalidatePermitAdminControl } from "../web3/erc20-permit";
import { claimErc721PermitHandler } from "../web3/erc721-permit";
import { verifyCurrentNetwork } from "../web3/verify-current-network";
import { insertErc20PermitTableData, insertErc721PermitTableData } from "./insert-table-data";
@@ -15,64 +15,64 @@ export async function renderTransaction(nextTx?: boolean): Promise {
const table = document.getElementsByTagName(`table`)[0];
if (nextTx) {
- app.nextTx();
+ app.nextPermit();
if (!app.claims || app.claims.length <= 1) {
// already hidden
} else {
setPagination(document.getElementById("nextTx"), document.getElementById("previousTx"));
const rewardsCount = document.getElementById("rewardsCount") as Element;
- rewardsCount.innerHTML = `${app.transactionIndex + 1}/${app.claims.length} reward`;
- table.setAttribute(`data-claim`, "none");
+ rewardsCount.innerHTML = `${app.permitIndex + 1}/${app.claims.length} reward`;
+ table.setAttribute(`data-claim`, "error");
}
}
- if (!app.transaction) {
+ if (!app.permit) {
hideLoader();
return false;
}
- verifyCurrentNetwork(app.transaction.networkId).catch(console.error);
+ verifyCurrentNetwork(app.permit.networkId).catch(console.error);
- if (app.transaction.type === "erc20-permit") {
- const treasury = await fetchTreasury(app.transaction, app.provider);
+ if (app.permit.type === "erc20-permit") {
+ const treasury = await fetchFundingWallet(app);
// insert tx data into table
- const requestedAmountElement = insertErc20PermitTableData(app.transaction, table, treasury);
- table.setAttribute(`data-claim`, "ok");
+ const requestedAmountElement = insertErc20PermitTableData(app, table, treasury);
renderTokenSymbol({
- tokenAddress: app.transaction.permit.permitted.token,
- ownerAddress: app.transaction.owner,
- amount: app.transaction.transferDetails.requestedAmount,
- explorerUrl: networkExplorers[app.transaction.networkId],
+ tokenAddress: app.permit.permit.permitted.token,
+ ownerAddress: app.permit.owner,
+ amount: app.permit.transferDetails.requestedAmount,
+ explorerUrl: networkExplorers[app.permit.networkId],
table,
requestedAmountElement,
provider: app.provider,
}).catch(console.error);
const toElement = document.getElementById(`rewardRecipient`) as Element;
- renderEnsName({ element: toElement, address: app.transaction.transferDetails.to }).catch(console.error);
+ renderEnsName({ element: toElement, address: app.permit.transferDetails.to }).catch(console.error);
- generateInvalidatePermitAdminControl(app.transaction).catch(console.error);
+ generateInvalidatePermitAdminControl(app).catch(console.error);
- claimButton.element.addEventListener("click", claimErc20PermitHandlerWrapper(app.transaction));
- } else if (app.transaction.type === "erc721-permit") {
- const requestedAmountElement = insertErc721PermitTableData(app.transaction, table);
+ claimButton.element.addEventListener("click", claimErc20PermitHandlerWrapper(app));
+ table.setAttribute(`data-claim`, "ok");
+ } else if (app.permit.type === "erc721-permit") {
+ const requestedAmountElement = insertErc721PermitTableData(app.permit, table);
table.setAttribute(`data-claim`, "ok");
renderNftSymbol({
- tokenAddress: app.transaction.nftAddress,
- explorerUrl: networkExplorers[app.transaction.networkId],
+ tokenAddress: app.permit.nftAddress,
+ explorerUrl: networkExplorers[app.permit.networkId],
table,
requestedAmountElement,
provider: app.provider,
}).catch(console.error);
const toElement = document.getElementById(`rewardRecipient`) as Element;
- renderEnsName({ element: toElement, address: app.transaction.request.beneficiary }).catch(console.error);
+ renderEnsName({ element: toElement, address: app.permit.request.beneficiary }).catch(console.error);
- claimButton.element.addEventListener("click", claimErc721PermitHandler(app.transaction));
+ claimButton.element.addEventListener("click", claimErc721PermitHandler(app.permit));
}
return true;
diff --git a/static/scripts/rewards/render-transaction/tx-type.ts b/static/scripts/rewards/render-transaction/tx-type.ts
index 23df1341..8891dcaf 100644
--- a/static/scripts/rewards/render-transaction/tx-type.ts
+++ b/static/scripts/rewards/render-transaction/tx-type.ts
@@ -23,19 +23,19 @@ const erc20PermitT = T.Object({
type: T.Literal("erc20-permit"),
permit: T.Object({
permitted: T.Object({
- token: addressT,
- amount: bigNumberT,
+ token: T.RegExp(/^0x[a-fA-F0-9]{40}$/),
+ amount: T.Union([T.RegExp(/^\d+$/), T.Number()]),
}),
- nonce: bigNumberT,
- deadline: bigNumberT,
+ nonce: T.Union([T.RegExp(/^\d+$/), T.Number()]),
+ deadline: T.Union([T.RegExp(/^\d+$/), T.Number()]),
}),
transferDetails: T.Object({
- to: addressT,
- requestedAmount: bigNumberT,
+ to: T.RegExp(/^0x[a-fA-F0-9]{40}$/),
+ requestedAmount: T.Union([T.RegExp(/^\d+$/), T.Number()]),
}),
- owner: addressT,
- signature: signatureT,
- networkId: networkIdT,
+ owner: T.RegExp(/^0x[a-fA-F0-9]{40}$/),
+ signature: T.RegExp(/^0x[a-fA-F0-9]+$/),
+ networkId: T.Number(),
});
export type Erc20Permit = StaticDecode;
@@ -59,10 +59,24 @@ const erc721Permit = T.Object({
nftAddress: addressT,
networkId: networkIdT,
signature: signatureT,
+ // @whilefoo: they should have matching key names.
+ owner: addressT,
+ permit: T.Object({
+ permitted: T.Object({
+ token: addressT,
+ amount: bigNumberT,
+ }),
+ nonce: bigNumberT,
+ deadline: bigNumberT,
+ }),
+ transferDetails: T.Object({
+ to: T.RegExp(/^0x[a-fA-F0-9]{40}$/),
+ requestedAmount: T.Union([T.RegExp(/^\d+$/), T.Number()]),
+ }),
});
export type Erc721Permit = StaticDecode;
export const claimTxT = T.Union([erc20PermitT, erc721Permit]);
-export type ClaimTx = StaticDecode;
+export type RewardPermit = StaticDecode;
diff --git a/static/scripts/rewards/rpc-optimization/get-optimal-provider.ts b/static/scripts/rewards/rpc-optimization/get-optimal-provider.ts
index 76910d92..970ca565 100644
--- a/static/scripts/rewards/rpc-optimization/get-optimal-provider.ts
+++ b/static/scripts/rewards/rpc-optimization/get-optimal-provider.ts
@@ -3,24 +3,19 @@ import { AppState } from "../app-state";
import { getFastestRpcProvider } from "./get-fastest-rpc-provider";
import { testRpcPerformance } from "./test-rpc-performance";
-let optimalProvider: JsonRpcProvider;
let isTestStarted = false;
let isTestCompleted = false;
-export async function getOptimalProvider(app: AppState): Promise {
- const networkId = app.transactionNetworkId;
+export async function useFastestRpc(app: AppState): Promise {
+ const networkId = app.permitNetworkId;
+
if (!networkId) throw new Error("Network ID not found");
if (!isTestCompleted && !isTestStarted) {
isTestStarted = true;
- testRpcPerformance(networkId)
- .then(() => (isTestCompleted = true))
- .catch(console.error);
+ await testRpcPerformance(networkId).catch(console.error);
+ isTestCompleted = true;
}
- if (!optimalProvider) {
- optimalProvider = getFastestRpcProvider(networkId);
- }
- app.provider = optimalProvider;
- return optimalProvider;
+ return getFastestRpcProvider(networkId);
}
diff --git a/static/scripts/rewards/rpc-optimization/test-rpc-performance.ts b/static/scripts/rewards/rpc-optimization/test-rpc-performance.ts
index 700ffb94..11d42b80 100644
--- a/static/scripts/rewards/rpc-optimization/test-rpc-performance.ts
+++ b/static/scripts/rewards/rpc-optimization/test-rpc-performance.ts
@@ -32,33 +32,36 @@ const RPC_HEADER = {
"Content-Type": "application/json",
};
+function raceUntilSuccess(promises: Promise[]) {
+ return new Promise((resolve) => {
+ promises.forEach((promise: Promise) => {
+ promise.then(resolve).catch(() => {});
+ });
+ });
+}
+
export async function testRpcPerformance(networkId: number) {
const latencies: Record = JSON.parse(localStorage.getItem("rpcLatencies") || "{}");
const promises = networkRpcs[networkId].map(async (baseURL: string) => {
- try {
- const startTime = performance.now();
- const API = axios.create({
- baseURL,
- headers: RPC_HEADER,
- });
+ const startTime = performance.now();
+ const API = axios.create({
+ baseURL,
+ headers: RPC_HEADER,
+ });
- const { data } = await API.post("", RPC_BODY).catch(() => ({ data: null }));
- const endTime = performance.now();
- const latency = endTime - startTime;
- if (verifyBlock(data)) {
- // Save the latency in localStorage
- latencies[`${baseURL}_${networkId}`] = latency;
- } else {
- // Save -1 in localStorage to indicate an error
- latencies[`${baseURL}_${networkId}`] = -1;
- }
- } catch (error) {
- // Save -1 in localStorage to indicate an error
- latencies[`${baseURL}_${networkId}`] = -1;
+ const { data } = await API.post("", RPC_BODY);
+ const endTime = performance.now();
+ const latency = endTime - startTime;
+ if (verifyBlock(data)) {
+ // Save the latency in localStorage
+ latencies[`${baseURL}_${networkId}`] = latency;
+ localStorage.setItem("rpcLatencies", JSON.stringify(latencies));
+ } else {
+ // Throw an error to indicate an invalid block data
+ throw new Error(`Invalid block data from ${baseURL}`);
}
});
- await Promise.race(promises);
- localStorage.setItem("rpcLatencies", JSON.stringify(latencies));
+ await raceUntilSuccess(promises);
}
diff --git a/static/scripts/rewards/web3/connect-wallet.ts b/static/scripts/rewards/web3/connect-wallet.ts
index ad596df6..b1353134 100644
--- a/static/scripts/rewards/web3/connect-wallet.ts
+++ b/static/scripts/rewards/web3/connect-wallet.ts
@@ -4,11 +4,6 @@ import { claimButton, toaster } from "../toaster";
export async function connectWallet(): Promise {
try {
- if (!window.ethereum) {
- console.error("Ethereum provider not found");
- return null;
- }
-
const wallet = new ethers.providers.Web3Provider(window.ethereum);
const signer = wallet.getSigner();
const address = await signer.getAddress();
diff --git a/static/scripts/rewards/web3/erc20-permit.ts b/static/scripts/rewards/web3/erc20-permit.ts
index ac08916a..f6121862 100644
--- a/static/scripts/rewards/web3/erc20-permit.ts
+++ b/static/scripts/rewards/web3/erc20-permit.ts
@@ -1,23 +1,19 @@
-import { JsonRpcProvider, JsonRpcSigner, TransactionResponse } from "@ethersproject/providers";
+import { JsonRpcSigner, TransactionResponse } from "@ethersproject/providers";
import { BigNumber, BigNumberish, Contract, ethers } from "ethers";
import { permit2Abi } from "../abis";
-import { app } from "../app-state";
+import { AppState } from "../app-state";
import { permit2Address } from "../constants";
import invalidateButton from "../invalidate-component";
import { tokens } from "../render-transaction/render-token-symbol";
import { renderTransaction } from "../render-transaction/render-transaction";
-import { Erc20Permit } from "../render-transaction/tx-type";
import { getErc20Contract } from "../rpc-optimization/getErc20Contract";
import { MetaMaskError, claimButton, errorToast, showLoader, toaster } from "../toaster";
-import { connectWallet } from "./connect-wallet";
-export async function fetchTreasury(
- permit: Erc20Permit,
- provider: JsonRpcProvider
-): Promise<{ balance: BigNumber; allowance: BigNumber; decimals: number; symbol: string }> {
+export async function fetchFundingWallet(app: AppState): Promise<{ balance: BigNumber; allowance: BigNumber; decimals: number; symbol: string }> {
+ const permit = app.permit;
try {
const tokenAddress = permit.permit.permitted.token.toLowerCase();
- const tokenContract = await getErc20Contract(tokenAddress, provider);
+ const tokenContract = await getErc20Contract(tokenAddress, app.provider);
if (tokenAddress === tokens[0].address || tokenAddress === tokens[1].address) {
const decimals = tokenAddress === tokens[0].address ? 18 : tokenAddress === tokens[1].address ? 18 : -1;
@@ -42,27 +38,10 @@ export async function fetchTreasury(
}
}
-async function connectToWallet() {
- let signer: JsonRpcSigner | null = null;
- try {
- signer = await connectWallet();
- if (!signer) {
- return null;
- }
- } catch (error: unknown) {
- if (error instanceof Error) {
- const e = error as unknown as MetaMaskError;
- console.error("Error in connectWallet: ", e);
- errorToast(e, e.reason);
- }
- }
- return signer;
-}
-
-async function checkPermitClaimability(permit: Erc20Permit, signer: JsonRpcSigner | null) {
+async function checkPermitClaimability(app: AppState): Promise {
let isPermitClaimable = false;
try {
- isPermitClaimable = await checkPermitClaimable(permit, signer, app.provider);
+ isPermitClaimable = await checkPermitClaimable(app);
} catch (error: unknown) {
if (error instanceof Error) {
const e = error as unknown as MetaMaskError;
@@ -87,9 +66,10 @@ async function createEthersContract(signer: JsonRpcSigner) {
return permit2Contract;
}
-async function transferFromPermit(permit2Contract: Contract, permit: Erc20Permit) {
+async function transferFromPermit(permit2Contract: Contract, app: AppState) {
+ const permit = app.permit;
try {
- const tx = await permit2Contract.permitTransferFrom(permit.permit, permit.transferDetails, permit.owner, permit.signature);
+ const tx = await permit2Contract.permitTransferFrom(permit, permit.transferDetails, permit.owner, permit.signature);
toaster.create("info", `Transaction sent`);
return tx;
} catch (error: unknown) {
@@ -137,20 +117,17 @@ async function renderTx() {
}
}
-export function claimErc20PermitHandlerWrapper(permit: Erc20Permit) {
+export function claimErc20PermitHandlerWrapper(app: AppState) {
return async function claimErc20PermitHandler() {
showLoader();
- const signer = await connectToWallet();
- if (!signer) return;
-
- const isPermitClaimable = await checkPermitClaimability(permit, signer);
+ const isPermitClaimable = await checkPermitClaimability(app);
if (!isPermitClaimable) return;
- const permit2Contract = await createEthersContract(signer);
+ const permit2Contract = await createEthersContract(app.signer);
if (!permit2Contract) return;
- const tx = await transferFromPermit(permit2Contract, permit);
+ const tx = await transferFromPermit(permit2Contract, app);
if (!tx) return;
const receipt = await waitForTransaction(tx);
@@ -162,10 +139,10 @@ export function claimErc20PermitHandlerWrapper(permit: Erc20Permit) {
};
}
-export async function checkPermitClaimable(permit: Erc20Permit, signer: JsonRpcSigner | null, provider: JsonRpcProvider) {
+export async function checkPermitClaimable(app: AppState): Promise {
let isClaimed;
try {
- isClaimed = await isNonceClaimed(permit);
+ isClaimed = await isNonceClaimed(app);
} catch (error: unknown) {
console.error("Error in isNonceClaimed: ", error);
return false;
@@ -176,21 +153,23 @@ export async function checkPermitClaimable(permit: Erc20Permit, signer: JsonRpcS
return false;
}
- if (permit.permit.deadline.lt(Math.floor(Date.now() / 1000))) {
+ const permit = app.permit.permit;
+
+ if (permit.deadline.lt(Math.floor(Date.now() / 1000))) {
toaster.create("error", `This reward has expired.`);
return false;
}
let treasury;
try {
- treasury = await fetchTreasury(permit, provider);
+ treasury = await fetchFundingWallet(app);
} catch (error: unknown) {
console.error("Error in fetchTreasury: ", error);
return false;
}
const { balance, allowance } = treasury;
- const permitted = BigNumber.from(permit.permit.permitted.amount);
+ const permitted = BigNumber.from(permit.permitted.amount);
const isSolvent = balance.gte(permitted);
const isAllowed = allowance.gte(permitted);
@@ -203,38 +182,33 @@ export async function checkPermitClaimable(permit: Erc20Permit, signer: JsonRpcS
return false;
}
- if (signer) {
- let user;
- try {
- user = (await signer.getAddress()).toLowerCase();
- } catch (error: unknown) {
- console.error("Error in signer.getAddress: ", error);
- return false;
- }
+ let user;
+ try {
+ user = (await app.signer.getAddress()).toLowerCase();
+ } catch (error: unknown) {
+ console.error("Error in signer.getAddress: ", error);
+ return false;
+ }
- const beneficiary = permit.transferDetails.to.toLowerCase();
- if (beneficiary !== user) {
- toaster.create("warning", `This reward is not for you.`);
- return false;
- }
+ const beneficiary = permit.transferDetails.to.toLowerCase();
+ if (beneficiary !== user) {
+ toaster.create("warning", `This reward is not for you.`);
+ return false;
}
return true;
}
-export async function generateInvalidatePermitAdminControl(permit: Erc20Permit) {
- const signer = await connectWallet();
- if (!signer) {
- console.log("Wallet not connected");
- return;
- }
-
+export async function generateInvalidatePermitAdminControl(app: AppState) {
try {
- const address = await signer.getAddress();
+ const address = await app.signer.getAddress();
const user = address.toLowerCase();
- const owner = permit.owner.toLowerCase();
- if (owner !== user) {
- return;
+
+ if (app.permit) {
+ const owner = app.permit.owner.toLowerCase();
+ if (owner !== user) {
+ return;
+ }
}
} catch (error) {
console.error("Error getting address from signer");
@@ -246,16 +220,12 @@ export async function generateInvalidatePermitAdminControl(permit: Erc20Permit)
invalidateButton.addEventListener("click", async function invalidateButtonClickHandler() {
try {
- const signer = await connectWallet();
- if (!signer) {
- return;
- }
- const isClaimed = await isNonceClaimed(permit);
+ const isClaimed = await isNonceClaimed(app);
if (isClaimed) {
toaster.create("error", `This reward has already been claimed or invalidated.`);
return;
}
- await invalidateNonce(signer, permit.permit.nonce);
+ await invalidateNonce(app.signer, app.permit.permit.nonce);
} catch (error: unknown) {
if (error instanceof Error) {
const e = error as unknown as MetaMaskError;
@@ -269,14 +239,14 @@ export async function generateInvalidatePermitAdminControl(permit: Erc20Permit)
}
//mimics https://github.com/Uniswap/permit2/blob/a7cd186948b44f9096a35035226d7d70b9e24eaf/src/SignatureTransfer.sol#L150
-export async function isNonceClaimed(permit: Erc20Permit): Promise {
+export async function isNonceClaimed(app: AppState): Promise {
const provider = app.provider;
const permit2Contract = new ethers.Contract(permit2Address, permit2Abi, provider);
- const { wordPos, bitPos } = nonceBitmap(BigNumber.from(permit.permit.nonce));
+ const { wordPos, bitPos } = nonceBitmap(BigNumber.from(app.permit.permit.nonce));
- const bitmap = await permit2Contract.nonceBitmap(permit.owner, wordPos).catch((error: MetaMaskError) => {
+ const bitmap = await permit2Contract.nonceBitmap(app.permit.owner, wordPos).catch((error: MetaMaskError) => {
console.error("Error in nonceBitmap method: ", error);
throw error;
});
diff --git a/static/scripts/rewards/web3/not-on-correct-network.ts b/static/scripts/rewards/web3/not-on-correct-network.ts
index 137fb421..aff4c909 100644
--- a/static/scripts/rewards/web3/not-on-correct-network.ts
+++ b/static/scripts/rewards/web3/not-on-correct-network.ts
@@ -1,7 +1,6 @@
import { ethers } from "ethers";
import { getNetworkName } from "../constants";
-import invalidateButton from "../invalidate-component";
-import { showLoader, toaster } from "../toaster";
+import { toaster } from "../toaster";
import { switchNetwork } from "./switch-network";
export function notOnCorrectNetwork(currentNetworkId: number, desiredNetworkId: number, web3provider: ethers.providers.Web3Provider) {
@@ -13,8 +12,6 @@ export function notOnCorrectNetwork(currentNetworkId: number, desiredNetworkId:
if (!networkName) {
toaster.create("error", `This dApp currently does not support payouts for network ID ${desiredNetworkId}`);
}
- showLoader();
- invalidateButton.disabled = true;
switchNetwork(web3provider, desiredNetworkId).catch((error) => {
console.error(error);
toaster.create("error", `Please switch to the ${networkName} network to claim this reward.`);
diff --git a/static/styles/rewards/claim-table.css b/static/styles/rewards/claim-table.css
index 6c965bb4..be7eb874 100644
--- a/static/styles/rewards/claim-table.css
+++ b/static/styles/rewards/claim-table.css
@@ -260,28 +260,19 @@ table thead {
table tbody {
display: none;
}
-table[data-claim="none"] thead {
- display: table-row-group;
-}
table[data-claim="error"] thead {
display: table-row-group;
}
table[data-claim="ok"] thead {
display: none;
}
-table[data-claim="none"] tbody {
- display: none;
-}
table[data-claim="error"] tbody {
display: none;
}
table[data-claim="ok"] tbody {
display: table-row-group;
}
-/*
-table[data-claim-rendered="true"][data-claim="none"][data-contract-loaded="true"][data-details-visible="false"] {
- border: none;
-} */
+
#rewardRecipient a div {
opacity: 0.66;
}