From b7483f785cfc652c09397dc746ed28fb3184fd87 Mon Sep 17 00:00:00 2001 From: Keyrxng <106303466+Keyrxng@users.noreply.github.com> Date: Sun, 25 Feb 2024 21:40:00 +0000 Subject: [PATCH] chore: pagination and permit to reward --- .../typescript/generate-erc20-permit-url.ts | 40 ++++++++++++++ .../typescript/generate-erc721-permit-url.ts | 52 +++++++++++++++++++ static/scripts/rewards/app-state.ts | 20 +++---- static/scripts/rewards/constants.ts | 4 +- .../claim-rewards-pagination.ts | 10 ++-- .../render-transaction/insert-table-data.ts | 27 +++++----- .../read-claim-data-from-url.ts | 14 ++--- .../render-transaction/render-transaction.ts | 39 +++++++------- .../rpc-optimization/get-optimal-provider.ts | 3 +- static/scripts/rewards/web3/erc20-permit.ts | 39 +++++++------- static/scripts/rewards/web3/erc721-permit.ts | 20 +++---- 11 files changed, 182 insertions(+), 86 deletions(-) diff --git a/scripts/typescript/generate-erc20-permit-url.ts b/scripts/typescript/generate-erc20-permit-url.ts index 08425268..b3d67cd2 100644 --- a/scripts/typescript/generate-erc20-permit-url.ts +++ b/scripts/typescript/generate-erc20-permit-url.ts @@ -31,6 +31,28 @@ export async function generateERC20Permit() { process.env.CHAIN_ID ? Number(process.env.CHAIN_ID) : 1 ); const signature = await myWallet._signTypedData(domain, types, values); + + const permitTransferFromData2: PermitTransferFrom = { + permitted: { + // token we are permitting to be transferred + token: process.env.PAYMENT_TOKEN_ADDRESS || "", + // amount we are permitting to be transferred + amount: ethers.utils.parseUnits("9" || "", 18), + }, + // who can transfer the tokens + spender: process.env.BENEFICIARY_ADDRESS || "", + nonce: BigNumber.from(`0x${randomBytes(32).toString("hex")}`), + // signature deadline + deadline: MaxUint256, + }; + + const { + domain: d, + types: t, + values: v, + } = SignatureTransfer.getPermitData(permitTransferFromData2, PERMIT2_ADDRESS, process.env.CHAIN_ID ? Number(process.env.CHAIN_ID) : 1); + const sig = await myWallet._signTypedData(d, t, v); + const txData = [ { type: "erc20-permit", @@ -50,6 +72,24 @@ export async function generateERC20Permit() { signature: signature, networkId: Number(process.env.CHAIN_ID), }, + { + type: "erc20-permit", + permit: { + permitted: { + token: permitTransferFromData2.permitted.token, + amount: permitTransferFromData2.permitted.amount.toString(), + }, + nonce: permitTransferFromData2.nonce.toString(), + deadline: permitTransferFromData2.deadline.toString(), + }, + transferDetails: { + to: permitTransferFromData2.spender, + requestedAmount: permitTransferFromData2.permitted.amount.toString(), + }, + owner: myWallet.address, + signature: sig, + networkId: Number(process.env.CHAIN_ID), + }, ]; const base64encodedTxData = Buffer.from(JSON.stringify(txData)).toString("base64"); diff --git a/scripts/typescript/generate-erc721-permit-url.ts b/scripts/typescript/generate-erc721-permit-url.ts index cba6cd99..3678caf8 100644 --- a/scripts/typescript/generate-erc721-permit-url.ts +++ b/scripts/typescript/generate-erc721-permit-url.ts @@ -36,6 +36,16 @@ export async function generateERC721Permit() { deadline: MaxUint256, }; + const erc721TransferFromData2: PermitTransferFrom = { + permitted: { + token: network == "localhost" ? NFT_REWARDS_ANVIL_DEPLOYMENT : NFT_ADDRESS, + amount: 1, + }, + spender: network == "localhost" ? ANVIL_ACC_1_ADDRESS : myWallet.address, + nonce: 3137, + deadline: MaxUint256, + }; + const domain = { name: SIGNING_DOMAIN_NAME, version: SIGNING_DOMAIN_VERSION, @@ -69,6 +79,16 @@ export async function generateERC721Permit() { values: [GITHUB_ORGANIZATION_NAME, GITHUB_REPOSITORY_NAME, GITHUB_ISSUE_ID, GITHUB_USERNAME, GITHUB_CONTRIBUTION_TYPE], }; + const mintRequest2 = { + beneficiary: network == "localhost" ? ANVIL_ACC_1_ADDRESS : myWallet.address, + deadline: MaxUint256, + keys: valueBytes, + nonce: 3137, + values: [GITHUB_ORGANIZATION_NAME, GITHUB_REPOSITORY_NAME, GITHUB_ISSUE_ID, GITHUB_USERNAME, GITHUB_CONTRIBUTION_TYPE], + }; + + const sig = await myWallet._signTypedData(domain, types, mintRequest2); + const signature = await myWallet._signTypedData(domain, types, mintRequest); const txData721 = [ @@ -104,6 +124,38 @@ export async function generateERC721Permit() { values: [GITHUB_ORGANIZATION_NAME, GITHUB_REPOSITORY_NAME, GITHUB_ISSUE_ID, GITHUB_USERNAME, GITHUB_CONTRIBUTION_TYPE], }, }, + { + type: "erc721-permit", + permit: { + permitted: { + token: erc721TransferFromData2.permitted.token, + amount: erc721TransferFromData2.permitted.amount.toString(), + }, + nonce: erc721TransferFromData2.nonce.toString(), + deadline: erc721TransferFromData2.deadline.toString(), + }, + transferDetails: { + to: erc721TransferFromData2.spender, + requestedAmount: erc721TransferFromData2.permitted.amount.toString(), + }, + owner: myWallet.address, + signature: sig, + networkId: CHAIN_ID, + nftMetadata: { + GITHUB_ORGANIZATION_NAME, + GITHUB_REPOSITORY_NAME, + GITHUB_ISSUE_ID, + GITHUB_USERNAME, + GITHUB_CONTRIBUTION_TYPE, + }, + request: { + beneficiary: network == "localhost" ? ANVIL_ACC_1_ADDRESS : myWallet.address, + deadline: erc721TransferFromData2.deadline.toString(), + keys: valueBytes, + nonce: erc721TransferFromData2.nonce.toString(), + values: [GITHUB_ORGANIZATION_NAME, GITHUB_REPOSITORY_NAME, GITHUB_ISSUE_ID, GITHUB_USERNAME, GITHUB_CONTRIBUTION_TYPE], + }, + }, ]; const base64encodedTxData721 = Buffer.from(JSON.stringify(txData721)).toString("base64"); diff --git a/static/scripts/rewards/app-state.ts b/static/scripts/rewards/app-state.ts index 4d5d7ebd..9a95075a 100644 --- a/static/scripts/rewards/app-state.ts +++ b/static/scripts/rewards/app-state.ts @@ -17,7 +17,7 @@ export class AppState { } get networkId(): number | null { - return this.permit?.networkId || null; + return this.reward?.networkId || null; } get provider(): JsonRpcProvider { @@ -28,33 +28,33 @@ export class AppState { this._provider = value; } - get permitIndex(): number { + get rewardIndex(): number { return this._currentIndex; } - get permit(): RewardPermit { - return this.permitIndex < this.claims.length ? this.claims[this.permitIndex] : this.claims[0]; + get reward(): RewardPermit { + return this.rewardIndex < this.claims.length ? this.claims[this.rewardIndex] : this.claims[0]; } get permitNetworkId() { - return this.permit?.networkId; + return this.reward?.networkId; } get currentExplorerUrl(): string { - if (!this.permit) { + if (!this.reward) { return "https://etherscan.io"; } - return networkExplorers[this.permit.networkId] || "https://etherscan.io"; + return networkExplorers[this.reward.networkId] || "https://etherscan.io"; } nextPermit(): RewardPermit | null { - this._currentIndex = Math.min(this.claims.length - 1, this._currentIndex + 1); - return this.permit; + this._currentIndex = Math.min(this.claims.length - 1, this.rewardIndex + 1); + return this.reward; } previousPermit(): RewardPermit | null { this._currentIndex = Math.max(0, this._currentIndex - 1); - return this.permit; + return this.reward; } } diff --git a/static/scripts/rewards/constants.ts b/static/scripts/rewards/constants.ts index c5f52047..54fd92d0 100644 --- a/static/scripts/rewards/constants.ts +++ b/static/scripts/rewards/constants.ts @@ -20,7 +20,7 @@ export const networkNames = { [NetworkIds.Mainnet]: "Ethereum Mainnet", [NetworkIds.Goerli]: "Goerli Testnet", [NetworkIds.Gnosis]: "Gnosis Chain", - [NetworkIds.Anvil]: "Anvil Development", + [NetworkIds.Anvil]: "http://127.0.0.1:8545", }; export const networkCurrencies: Record = { @@ -49,7 +49,7 @@ export const networkRpcs: Record = { [NetworkIds.Mainnet]: ["https://rpc-pay.ubq.fi/v1/mainnet", ...(extraRpcs[NetworkIds.Mainnet] || [])], [NetworkIds.Goerli]: ["https://rpc-pay.ubq.fi/v1/goerli", ...(extraRpcs[NetworkIds.Goerli] || [])], [NetworkIds.Gnosis]: [...(extraRpcs[NetworkIds.Gnosis] || [])], - [NetworkIds.Anvil]: ["http://localhost:8545"], + [NetworkIds.Anvil]: ["http://127.0.0.1:8545"], }; export const permit2Address = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; diff --git a/static/scripts/rewards/render-transaction/claim-rewards-pagination.ts b/static/scripts/rewards/render-transaction/claim-rewards-pagination.ts index 1559a1c9..146414ea 100644 --- a/static/scripts/rewards/render-transaction/claim-rewards-pagination.ts +++ b/static/scripts/rewards/render-transaction/claim-rewards-pagination.ts @@ -6,16 +6,16 @@ import { setPagination } from "./set-pagination"; import { removeAllEventListeners } from "./utils"; export function claimRewardsPagination(rewardsCount: HTMLElement) { - rewardsCount.innerHTML = `${app.permitIndex + 1}/${app.claims.length} reward`; + rewardsCount.innerHTML = `${app.rewardIndex + 1}/${app.claims.length} reward`; const nextTxButton = document.getElementById("nextTx"); if (nextTxButton) { nextTxButton.addEventListener("click", () => { claimButton.element = removeAllEventListeners(claimButton.element) as HTMLButtonElement; app.nextPermit(); - rewardsCount.innerHTML = `${app.permitIndex + 1}/${app.claims.length} reward`; + rewardsCount.innerHTML = `${app.rewardIndex + 1}/${app.claims.length} reward`; table.setAttribute(`data-claim`, "error"); - renderTransaction(true).catch(console.error); + renderTransaction(app).catch(console.error); }); } @@ -24,9 +24,9 @@ export function claimRewardsPagination(rewardsCount: HTMLElement) { prevTxButton.addEventListener("click", () => { claimButton.element = removeAllEventListeners(claimButton.element) as HTMLButtonElement; app.previousPermit(); - rewardsCount.innerHTML = `${app.permitIndex + 1}/${app.claims.length} reward`; + rewardsCount.innerHTML = `${app.rewardIndex + 1}/${app.claims.length} reward`; table.setAttribute(`data-claim`, "error"); - renderTransaction(true).catch(console.error); + renderTransaction(app, 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 5f5df0ee..c8485b20 100644 --- a/static/scripts/rewards/render-transaction/insert-table-data.ts +++ b/static/scripts/rewards/render-transaction/insert-table-data.ts @@ -1,6 +1,6 @@ import { BigNumber, ethers } from "ethers"; import { AppState, app } from "../app-state"; -import { Erc721Permit } from "./tx-type"; +import { Erc20Permit, Erc721Permit } from "./tx-type"; export function shortenAddress(address: string): string { return `${address.slice(0, 10)}...${address.slice(-8)}`; @@ -11,16 +11,16 @@ export function insertErc20PermitTableData( table: Element, treasury: { balance: BigNumber; allowance: BigNumber; decimals: number; symbol: string } ): Element { - const permit = app.permit; + const reward = app.reward as Erc20Permit; const requestedAmountElement = document.getElementById("rewardAmount") as Element; - renderToFields(permit.transferDetails.to, app.currentExplorerUrl); - renderTokenFields(permit.permit.permitted.token, app.currentExplorerUrl); + renderToFields(reward.transferDetails.to, app.currentExplorerUrl); + renderTokenFields(reward.permit.permitted.token, app.currentExplorerUrl); renderDetailsFields([ - { name: "From", value: `${permit.owner}` }, + { name: "From", value: `${reward.owner}` }, { name: "Expiry", value: (() => { - const deadline = BigNumber.isBigNumber(permit.permit.deadline) ? permit.permit.deadline : BigNumber.from(permit.permit.deadline); + const deadline = BigNumber.isBigNumber(reward.permit.deadline) ? reward.permit.deadline : BigNumber.from(reward.permit.deadline); return deadline.lte(Number.MAX_SAFE_INTEGER.toString()) ? new Date(deadline.toNumber()).toLocaleString() : undefined; })(), }, @@ -31,19 +31,19 @@ export function insertErc20PermitTableData( return requestedAmountElement; } -export function insertErc721PermitTableData(permit: Erc721Permit, table: Element): Element { +export function insertErc721PermitTableData(reward: Erc721Permit, table: Element): Element { const requestedAmountElement = document.getElementById("rewardAmount") as Element; - renderToFields(permit.transferDetails.to, app.currentExplorerUrl); - renderTokenFields(permit.permit.permitted.token, app.currentExplorerUrl); - const { GITHUB_REPOSITORY_NAME, GITHUB_CONTRIBUTION_TYPE, GITHUB_ISSUE_ID, GITHUB_ORGANIZATION_NAME, GITHUB_USERNAME } = permit.nftMetadata; + renderToFields(reward.transferDetails.to, app.currentExplorerUrl); + renderTokenFields(reward.permit.permitted.token, app.currentExplorerUrl); + const { GITHUB_REPOSITORY_NAME, GITHUB_CONTRIBUTION_TYPE, GITHUB_ISSUE_ID, GITHUB_ORGANIZATION_NAME, GITHUB_USERNAME } = reward.nftMetadata; renderDetailsFields([ { name: "NFT address", - value: `${permit.permit.permitted.token}`, + value: `${reward.permit.permitted.token}`, }, { name: "Expiry", - value: permit.permit.deadline.lte(Number.MAX_SAFE_INTEGER.toString()) ? new Date(permit.permit.deadline.toNumber()).toLocaleString() : undefined, + value: reward.permit.deadline.lte(Number.MAX_SAFE_INTEGER.toString()) ? new Date(reward.permit.deadline.toNumber()).toLocaleString() : undefined, }, { name: "GitHub Organization", @@ -84,6 +84,7 @@ function renderDetailsFields(additionalDetails: { name: string; value: string | function renderTokenFields(tokenAddress: string, explorerUrl: string) { const tokenFull = document.querySelector("#Token .full") as Element; const tokenShort = document.querySelector("#Token .short") as Element; + tokenFull.innerHTML = `
${tokenAddress}
`; tokenShort.innerHTML = `
${shortenAddress(tokenAddress)}
`; @@ -95,7 +96,7 @@ function renderToFields(receiverAddress: string, explorerUrl: string) { const toFull = document.querySelector("#rewardRecipient .full") as Element; const toShort = document.querySelector("#rewardRecipient .short") as Element; - // after a single claim toFull returns null as creates a toaster error + // if the for address is an ENS name neither will be found if (!toFull || !toShort) return; toFull.innerHTML = `
${receiverAddress}
`; 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 fea4d522..6115f7f0 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 @@ -6,7 +6,8 @@ import { verifyCurrentNetwork } from "../web3/verify-current-network"; import { claimRewardsPagination } from "./claim-rewards-pagination"; import { renderTransaction } from "./render-transaction"; import { setClaimMessage } from "./set-claim-message"; -import { claimTxT } from "./tx-type"; +import { RewardPermit, claimTxT } from "./tx-type"; +import { Type } from "@sinclair/typebox"; export const table = document.getElementsByTagName(`table`)[0]; const urlParams = new URLSearchParams(window.location.search); @@ -20,19 +21,19 @@ export async function readClaimDataFromUrl(app: AppState) { return; } - app.claims = decodeClaimData(base64encodedTxData); + app.claims = decodeClaimData(base64encodedTxData).flat(); app.provider = await useFastestRpc(app); - const networkId = app.permit?.networkId || app.networkId; + const networkId = app.reward?.networkId || app.networkId; app.signer = await connectWallet().catch(console.error); displayRewardDetails(); displayRewardPagination(); - renderTransaction(true) + renderTransaction(app) .then(() => verifyCurrentNetwork(networkId as number)) .catch(console.error); } -function decodeClaimData(base64encodedTxData: string) { +function decodeClaimData(base64encodedTxData: string): RewardPermit[] { let permit; try { @@ -43,9 +44,8 @@ function decodeClaimData(base64encodedTxData: string) { table.setAttribute(`data-claim`, "error"); throw error; } - try { - return [Value.Decode(claimTxT, permit[0])]; + return [Value.Decode(Type.Array(claimTxT), permit)]; } catch (error) { console.error(error); setClaimMessage({ type: "Error", message: `2. Invalid claim data passed in URL` }); diff --git a/static/scripts/rewards/render-transaction/render-transaction.ts b/static/scripts/rewards/render-transaction/render-transaction.ts index bc531637..cfcc4aca 100644 --- a/static/scripts/rewards/render-transaction/render-transaction.ts +++ b/static/scripts/rewards/render-transaction/render-transaction.ts @@ -1,78 +1,81 @@ -import { app } from "../app-state"; +import { AppState } from "../app-state"; import { networkExplorers } from "../constants"; import { claimButton, hideLoader } from "../toaster"; 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"; +import { displayRewardDetails, displayRewardPagination } from "./read-claim-data-from-url"; import { renderEnsName } from "./render-ens-name"; import { renderNftSymbol, renderTokenSymbol } from "./render-token-symbol"; import { setPagination } from "./set-pagination"; +import { Erc721Permit } from "./tx-type"; type Success = boolean; -export async function renderTransaction(nextTx?: boolean): Promise { +export async function renderTransaction(app: AppState, nextTx?: boolean): Promise { const table = document.getElementsByTagName(`table`)[0]; if (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.permitIndex + 1}/${app.claims.length} reward`; - table.setAttribute(`data-claim`, "error"); + rewardsCount.innerHTML = `${app.rewardIndex + 1}/${app.claims.length} reward`; } } - if (!app.permit) { + if (!app.reward) { hideLoader(); + console.log("No reward found"); return false; } - verifyCurrentNetwork(app.permit.networkId).catch(console.error); + verifyCurrentNetwork(app.reward.networkId).catch(console.error); - if (app.permit.type === "erc20-permit") { + if (app.reward.type === "erc20-permit") { const treasury = await fetchFundingWallet(app); // insert tx data into table const requestedAmountElement = insertErc20PermitTableData(app, table, treasury); renderTokenSymbol({ - tokenAddress: app.permit.permit.permitted.token, - ownerAddress: app.permit.owner, - amount: app.permit.transferDetails.requestedAmount, - explorerUrl: networkExplorers[app.permit.networkId], + tokenAddress: app.reward.permit.permitted.token, + ownerAddress: app.reward.owner, + amount: app.reward.transferDetails.requestedAmount, + explorerUrl: networkExplorers[app.reward.networkId], table, requestedAmountElement, provider: app.provider, }).catch(console.error); const toElement = document.getElementById(`rewardRecipient`) as Element; - renderEnsName({ element: toElement, address: app.permit.transferDetails.to }).catch(console.error); + renderEnsName({ element: toElement, address: app.reward.transferDetails.to }).catch(console.error); generateInvalidatePermitAdminControl(app).catch(console.error); claimButton.element.addEventListener("click", claimErc20PermitHandlerWrapper(app)); table.setAttribute(`data-claim`, "ok"); - } else if (app.permit.type === "erc721-permit") { - const requestedAmountElement = insertErc721PermitTableData(app.permit, table); + } else if (app.reward.type === "erc721-permit") { + const requestedAmountElement = insertErc721PermitTableData(app.reward, table); table.setAttribute(`data-claim`, "ok"); renderNftSymbol({ - tokenAddress: app.permit.permit.permitted.token, - explorerUrl: networkExplorers[app.permit.networkId], + tokenAddress: app.reward.permit.permitted.token, + explorerUrl: networkExplorers[app.reward.networkId], table, requestedAmountElement, provider: app.provider, }).catch(console.error); const toElement = document.getElementById(`rewardRecipient`) as Element; - renderEnsName({ element: toElement, address: app.permit.transferDetails.to }).catch(console.error); + renderEnsName({ element: toElement, address: app.reward.transferDetails.to }).catch(console.error); - claimButton.element.addEventListener("click", claimErc721PermitHandler(app.permit)); + claimButton.element.addEventListener("click", claimErc721PermitHandler(app.reward as Erc721Permit)); } return true; diff --git a/static/scripts/rewards/rpc-optimization/get-optimal-provider.ts b/static/scripts/rewards/rpc-optimization/get-optimal-provider.ts index 970ca565..b0a0896d 100644 --- a/static/scripts/rewards/rpc-optimization/get-optimal-provider.ts +++ b/static/scripts/rewards/rpc-optimization/get-optimal-provider.ts @@ -7,8 +7,7 @@ let isTestStarted = false; let isTestCompleted = false; export async function useFastestRpc(app: AppState): Promise { - const networkId = app.permitNetworkId; - + const networkId = app.reward.networkId || app.networkId || app.claims[0].networkId; if (!networkId) throw new Error("Network ID not found"); if (!isTestCompleted && !isTestStarted) { diff --git a/static/scripts/rewards/web3/erc20-permit.ts b/static/scripts/rewards/web3/erc20-permit.ts index 29fad9fe..33dabe9a 100644 --- a/static/scripts/rewards/web3/erc20-permit.ts +++ b/static/scripts/rewards/web3/erc20-permit.ts @@ -10,23 +10,23 @@ import { getErc20Contract } from "../rpc-optimization/getErc20Contract"; import { MetaMaskError, claimButton, errorToast, showLoader, toaster } from "../toaster"; export async function fetchFundingWallet(app: AppState): Promise<{ balance: BigNumber; allowance: BigNumber; decimals: number; symbol: string }> { - const permit = app.permit; + const reward = app.reward; try { - const tokenAddress = permit.permit.permitted.token.toLowerCase(); + const tokenAddress = reward.permit.permitted.token.toLowerCase(); 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; const symbol = tokenAddress === tokens[0].address ? tokens[0].name : tokenAddress === tokens[1].address ? tokens[1].name : ""; - const [balance, allowance] = await Promise.all([tokenContract.balanceOf(permit.owner), tokenContract.allowance(permit.owner, permit2Address)]); + const [balance, allowance] = await Promise.all([tokenContract.balanceOf(reward.owner), tokenContract.allowance(reward.owner, permit2Address)]); return { balance, allowance, decimals, symbol }; } else { console.log(`Hardcode this token in render-token-symbol.ts and save two calls: ${tokenAddress}`); const [balance, allowance, decimals, symbol] = await Promise.all([ - tokenContract.balanceOf(permit.owner), - tokenContract.allowance(permit.owner, permit2Address), + tokenContract.balanceOf(reward.owner), + tokenContract.allowance(reward.owner, permit2Address), tokenContract.decimals(), tokenContract.symbol(), ]); @@ -67,9 +67,9 @@ async function createEthersContract(signer: JsonRpcSigner) { } async function transferFromPermit(permit2Contract: Contract, app: AppState) { - const permit = app.permit; + const reward = app.reward; try { - const tx = await permit2Contract.permitTransferFrom(permit.permit, permit.transferDetails, permit.owner, permit.signature); + const tx = await permit2Contract.permitTransferFrom(reward.permit, reward.transferDetails, reward.owner, reward.signature); toaster.create("info", `Transaction sent`); return tx; } catch (error: unknown) { @@ -105,9 +105,10 @@ async function waitForTransaction(tx: TransactionResponse) { return receipt; } -async function renderTx() { +async function renderTx(app: AppState) { try { - await renderTransaction(); + app.claims.slice(0, 1); + await renderTransaction(app, true); } catch (error: unknown) { if (error instanceof Error) { const e = error as unknown as MetaMaskError; @@ -135,7 +136,7 @@ export function claimErc20PermitHandlerWrapper(app: AppState) { claimButton.element.removeEventListener("click", claimErc20PermitHandler); - await renderTx(); + await renderTx(app); }; } @@ -153,9 +154,9 @@ export async function checkPermitClaimable(app: AppState): Promise { return false; } - const permit = app.permit; + const reward = app.reward; - if (permit.permit.deadline.lt(Math.floor(Date.now() / 1000))) { + if (reward.permit.deadline.lt(Math.floor(Date.now() / 1000))) { toaster.create("error", `This reward has expired.`); return false; } @@ -169,7 +170,7 @@ export async function checkPermitClaimable(app: AppState): Promise { } const { balance, allowance } = treasury; - const permitted = BigNumber.from(permit.permit.permitted.amount); + const permitted = BigNumber.from(reward.permit.permitted.amount); const isSolvent = balance.gte(permitted); const isAllowed = allowance.gte(permitted); @@ -190,7 +191,7 @@ export async function checkPermitClaimable(app: AppState): Promise { return false; } - const beneficiary = permit.transferDetails.to.toLowerCase(); + const beneficiary = reward.transferDetails.to.toLowerCase(); if (beneficiary !== user) { toaster.create("warning", `This reward is not for you.`); return false; @@ -204,8 +205,8 @@ export async function generateInvalidatePermitAdminControl(app: AppState) { const address = await app.signer.getAddress(); const user = address.toLowerCase(); - if (app.permit) { - const owner = app.permit.owner.toLowerCase(); + if (app.reward) { + const owner = app.reward.owner.toLowerCase(); if (owner !== user) { return; } @@ -225,7 +226,7 @@ export async function generateInvalidatePermitAdminControl(app: AppState) { toaster.create("error", `This reward has already been claimed or invalidated.`); return; } - await invalidateNonce(app.signer, app.permit.permit.nonce); + await invalidateNonce(app.signer, app.reward.permit.nonce); } catch (error: unknown) { if (error instanceof Error) { const e = error as unknown as MetaMaskError; @@ -244,9 +245,9 @@ export async function isNonceClaimed(app: AppState): Promise { const permit2Contract = new ethers.Contract(permit2Address, permit2Abi, provider); - const { wordPos, bitPos } = nonceBitmap(BigNumber.from(app.permit.permit.nonce)); + const { wordPos, bitPos } = nonceBitmap(BigNumber.from(app.reward.permit.nonce)); - const bitmap = await permit2Contract.nonceBitmap(app.permit.owner, wordPos).catch((error: MetaMaskError) => { + const bitmap = await permit2Contract.nonceBitmap(app.reward.owner, wordPos).catch((error: MetaMaskError) => { console.error("Error in nonceBitmap method: ", error); throw error; }); diff --git a/static/scripts/rewards/web3/erc721-permit.ts b/static/scripts/rewards/web3/erc721-permit.ts index b8b0a9a2..25af2fb0 100644 --- a/static/scripts/rewards/web3/erc721-permit.ts +++ b/static/scripts/rewards/web3/erc721-permit.ts @@ -6,24 +6,24 @@ import { renderTransaction } from "../render-transaction/render-transaction"; import { Erc721Permit } from "../render-transaction/tx-type"; import { claimButton, showLoader, toaster } from "../toaster"; import { connectWallet } from "./connect-wallet"; -export function claimErc721PermitHandler(permit: Erc721Permit) { +export function claimErc721PermitHandler(reward: Erc721Permit) { return async function claimButtonHandler() { const signer = await connectWallet(); if (!signer) { return; } - if ((await signer.getAddress()).toLowerCase() !== permit.request.beneficiary) { + if ((await signer.getAddress()).toLowerCase() !== reward.request.beneficiary) { toaster.create("warning", `This NFT is not for you.`); return; } - if (permit.permit.deadline.lt(Math.floor(Date.now() / 1000))) { + if (reward.permit.deadline.lt(Math.floor(Date.now() / 1000))) { toaster.create("error", `This NFT has expired.`); return; } - const isRedeemed = await isNonceRedeemed(permit, app.provider); + const isRedeemed = await isNonceRedeemed(reward, app.provider); if (isRedeemed) { toaster.create("error", `This NFT has already been redeemed.`); return; @@ -31,9 +31,9 @@ export function claimErc721PermitHandler(permit: Erc721Permit) { showLoader(); try { - const nftContract = new ethers.Contract(permit.permit.permitted.token, nftRewardAbi, signer); + const nftContract = new ethers.Contract(reward.permit.permitted.token, nftRewardAbi, signer); - const tx: TransactionResponse = await nftContract.safeMint(permit.request, permit.signature); + const tx: TransactionResponse = await nftContract.safeMint(reward.request, reward.signature); toaster.create("info", `Transaction sent. Waiting for confirmation...`); const receipt = await tx.wait(); toaster.create("success", `Claim Complete.`); @@ -41,7 +41,7 @@ export function claimErc721PermitHandler(permit: Erc721Permit) { claimButton.element.removeEventListener("click", claimButtonHandler); - renderTransaction(true).catch((error) => { + renderTransaction(app, true).catch((error) => { console.error(error); toaster.create("error", `Error rendering transaction: ${error.message}`); }); @@ -52,7 +52,7 @@ export function claimErc721PermitHandler(permit: Erc721Permit) { }; } -export async function isNonceRedeemed(nftMint: Erc721Permit, provider: JsonRpcProvider): Promise { - const nftContract = new ethers.Contract(nftMint.permit.permitted.token, nftRewardAbi, provider); - return nftContract.nonceRedeemed(nftMint.request.nonce); +export async function isNonceRedeemed(reward: Erc721Permit, provider: JsonRpcProvider): Promise { + const nftContract = new ethers.Contract(reward.permit.permitted.token, nftRewardAbi, provider); + return nftContract.nonceRedeemed(reward.request.nonce); }