diff --git a/.github/workflows/continuous-deploy.yml b/.github/workflows/continuous-deploy.yml index f1aaf66f..6f11eeff 100644 --- a/.github/workflows/continuous-deploy.yml +++ b/.github/workflows/continuous-deploy.yml @@ -7,10 +7,27 @@ on: - completed jobs: + get-default-branch: + runs-on: ubuntu-latest + outputs: + isDefault: ${{ steps.check.outputs.isDefault }} + steps: + - name: Check if current branch is default + id: check + run: | + DEFAULT_BRANCH=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }} | jq -r '.default_branch') + IS_DEFAULT=false + if [ "$DEFAULT_BRANCH" = "${{ github.ref }}" ]; then + IS_DEFAULT=true + fi + echo "::set-output name=isDefault::$IS_DEFAULT" + deploy-to-cloudflare: name: Deploy to Cloudflare Pages if: ${{ github.event.workflow_run.conclusion == 'success' }} uses: ubiquity/.github/.github/workflows/deploy.yml@main + with: + deploy_preview_branches: ${{ needs.get-default-branch.outputs.isDefault }} permissions: contents: read pull-requests: write @@ -18,4 +35,4 @@ jobs: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} APP_ID: ${{ secrets.APP_ID }} - APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} \ No newline at end of file + APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} diff --git a/static/audit.html b/static/audit.html index a400d9d6..192f814e 100644 --- a/static/audit.html +++ b/static/audit.html @@ -1,70 +1,73 @@ + + Audit report + + + + - - Audit report - - - - - - -
-

Audit report

- -
- - -
-
- - -
-
- - -
-
- - -
-
- -
- - -
⚡Cache
+}' + > +
+
+ +
+ + +
⚡Cache
+
+
+ +
+ + + + + + + + + + + + + + +
- -
- - - - - - - - - - - - - - - -
-
- - - - - \ No newline at end of file + + + + diff --git a/static/scripts/audit-report/audit.ts b/static/scripts/audit-report/audit.ts index 65991db1..1879de9f 100644 --- a/static/scripts/audit-report/audit.ts +++ b/static/scripts/audit-report/audit.ts @@ -6,14 +6,25 @@ import GoDB from "godb"; import { permit2Abi } from "../rewards/abis"; import { ObserverKeys, ElemInterface, QuickImport, StandardInterface, TxData, GoDBSchema, GitHubUrlParts, ChainScanResult, SavedData } from "./types"; import { Chain, ChainScan, DatabaseName, NULL_HASH, NULL_ID } from "./constants"; -import { getCurrency, getGitHubUrlPartsArray, getRandomAPIKey, getRandomRpcUrl, isValidUrl, parseRepoUrl, populateTable, primaryRateLimitHandler, RateLimitOptions, secondaryRateLimitHandler } from "./helpers"; +import { + getCurrency, + getGitHubUrlPartsArray, + getRandomAPIKey, + getRandomRpcUrl, + isValidUrl, + parseRepoUrl, + populateTable, + primaryRateLimitHandler, + RateLimitOptions, + secondaryRateLimitHandler, +} from "./helpers"; import { getTxInfo } from "./utils/getTransaction"; const rateOctokit = Octokit.plugin(throttling); let BOT_WALLET_ADDRESS = ""; let REPOSITORY_URL = ""; -let GITHUB_PAT = "" +let GITHUB_PAT = ""; let repoArray: string[] = []; @@ -47,7 +58,6 @@ const permitTransferFromSelector = "0x30f28b7a"; const permitFunctionName = "permitTransferFrom"; const elemList: ElemInterface[] = []; - let gitID = NULL_ID; let etherHash = NULL_HASH; @@ -94,9 +104,9 @@ const getDataSchema = (storeHash: string) => { }; const parseAndAddUrls = (input: string): void => { - const urls = input.split(',').map((url) => url.trim()); + const urls = input.split(",").map(url => url.trim()); repoArray.push(...urls); -} +}; const updateDB = async (storeHash: string) => { const schema = getDataSchema(storeHash); @@ -121,8 +131,8 @@ const updateDB = async (storeHash: string) => { title, bounty_hunter, network, - owner, - repo + owner, + repo, }); } } @@ -224,7 +234,7 @@ class smartQueue { } = queueValue; // check for undefined - if(git?.issue_number) { + if (git?.issue_number) { elemList.push({ id: git?.issue_number!, tx: ether?.txHash!, @@ -238,7 +248,7 @@ class smartQueue { if (elemList.length > 0) { resultTableTbodyElem.innerHTML = ""; for (let data of elemList) { - populateTable(data?.owner, data?.repo, data?.id, data?.network, data?.tx, data?.title, data?.amount, data?.bounty_hunter) + populateTable(data?.owner, data?.repo, data?.id, data?.network, data?.tx, data?.title, data?.amount, data?.bounty_hunter); } } } @@ -299,7 +309,7 @@ const commentFetcher = async () => { }, }, }); - let [owner, repo] = parseRepoUrl(issueList[0].html_url) + let [owner, repo] = parseRepoUrl(issueList[0].html_url); const { data } = await octokit.rest.issues.listComments({ owner, repo, @@ -319,13 +329,13 @@ const commentFetcher = async () => { } else { let isFound = false; for (let comment of data) { - if(comment.user && comment.user.node_id === botNodeId && comment.body) { + if (comment.user && comment.user.node_id === botNodeId && comment.body) { const match = comment.body.match(urlRegex); if (match && isValidUrl(match[1])) { const url = new URL(match[1]); const params = new URLSearchParams(url.search); const base64Payload = params.get("claim"); - let network = getCurrency(comment.body) // Might change it to `const claimNetwork = params.get("network");` later because previous permits are missing network query + let network = getCurrency(comment.body); // Might change it to `const claimNetwork = params.get("network");` later because previous permits are missing network query if (base64Payload) { const { owner: ownerAddress, @@ -357,8 +367,8 @@ const commentFetcher = async () => { repo, bounty_hunter: { name: issueList[0].assignee ? issueList[0].assignee.login : issueList[0].assignees[0]?.login, - url: issueList[0].assignee ? issueList[0].assignee.html_url : issueList[0].assignees[0]?.html_url - } + url: issueList[0].assignee ? issueList[0].assignee.html_url : issueList[0].assignees[0]?.html_url, + }, }, ether: undefined, network: network as string, @@ -367,7 +377,7 @@ const commentFetcher = async () => { isFound = true; } } else { - console.log('URL not found, skipping'); + console.log("URL not found, skipping"); } } } @@ -408,15 +418,15 @@ const commentFetcher = async () => { const gitFetcher = async (repoUrls: GitHubUrlParts[]) => { if (isGit) { const octokit = new rateOctokit({ - auth: GITHUB_PAT, - throttle: { - onRateLimit: (retryAfter, options) => { - return primaryRateLimitHandler(retryAfter, options as RateLimitOptions); - }, - onSecondaryRateLimit: (retryAfter, options) => { - return secondaryRateLimitHandler(retryAfter, options as RateLimitOptions); - }, + auth: GITHUB_PAT, + throttle: { + onRateLimit: (retryAfter, options) => { + return primaryRateLimitHandler(retryAfter, options as RateLimitOptions); }, + onSecondaryRateLimit: (retryAfter, options) => { + return secondaryRateLimitHandler(retryAfter, options as RateLimitOptions); + }, + }, }); const getIssuesForRepo = async (owner: string, repo: string) => { @@ -434,7 +444,7 @@ const gitFetcher = async (repoUrls: GitHubUrlParts[]) => { if (data.length === 0) break; - const issues = data.filter((issue) => !issue.pull_request && issue.comments > 0); + const issues = data.filter(issue => !issue.pull_request && issue.comments > 0); if (issues.length > 0) { if (!lastGitID) { lastGitID = issues[0].number; @@ -467,17 +477,13 @@ const gitFetcher = async (repoUrls: GitHubUrlParts[]) => { }; try { - const issuesPromises = repoUrls.map((repoUrl) => - getIssuesForRepo(repoUrl.owner, repoUrl.repo) - ); + const issuesPromises = repoUrls.map(repoUrl => getIssuesForRepo(repoUrl.owner, repoUrl.repo)); const allIssues = await Promise.all(issuesPromises); for (let i = 0; i < allIssues.length; i++) { const issues = allIssues[i]; issueList.push(...issues); - console.log( - `Fetched ${issues.length} issues for repository ${repoUrls[i].owner}/${repoUrls[i].repo}` - ); + console.log(`Fetched ${issues.length} issues for repository ${repoUrls[i].owner}/${repoUrls[i].repo}`); } isGit = false; @@ -501,11 +507,11 @@ const fetchDataFromChainScanAPI = async (url: string, chain: string) => { const etherFetcher = async () => { const ethereumURL = `https://api.${ChainScan.Ethereum}/api?module=account&action=tokentx&address=${BOT_WALLET_ADDRESS}&apikey=${getRandomAPIKey( - Chain.Ethereum + Chain.Ethereum, )}&page=${etherPageNumber}&offset=${offset}&sort=desc`; const gnosisURL = `https://api.${ChainScan.Gnosis}/api?module=account&action=tokentx&address=${BOT_WALLET_ADDRESS}&apikey=${getRandomAPIKey( - Chain.Gnosis + Chain.Gnosis, )}&page=${etherPageNumber}&offset=${offset}&sort=desc`; if (isEther) { @@ -560,9 +566,9 @@ const rpcFetcher = async () => { try { const data = await rpcQueue.read(); if (data) { - const {hash, chain} = data + const { hash, chain } = data; - const txInfo = await getTxInfo(hash, getRandomRpcUrl(chain),chain); + const txInfo = await getTxInfo(hash, getRandomRpcUrl(chain), chain); if (txInfo.input.startsWith(permitTransferFromSelector)) { const decodedFunctionData = permit2Interface.decodeFunctionData(permitFunctionName, txInfo.input); @@ -636,27 +642,18 @@ const dbInit = async () => { if (tableData.length > 0) { for (let data of tableData) { - const { - owner, - repo, + const { owner, repo, id, network, tx, bounty_hunter, amount, title } = data as unknown as SavedData; + populateTable(owner, repo, id, network, tx, title, amount, bounty_hunter); + // for filtering + elemList.push({ id, - network, tx, - bounty_hunter, amount, title, - } = data as unknown as SavedData - populateTable(owner, repo, id, network, tx, title, amount, bounty_hunter); - // for filtering - elemList.push({ - id, - tx, - amount, - title, - bounty_hunter, - owner, - repo, - network, + bounty_hunter, + owner, + repo, + network, }); } } @@ -706,22 +703,17 @@ const auditInit = () => { BOT_WALLET_ADDRESS = WALLET.toLocaleLowerCase(); REPOSITORY_URL = REPO.toLocaleLowerCase(); GITHUB_PAT = PAT; - parseAndAddUrls(REPOSITORY_URL) + parseAndAddUrls(REPOSITORY_URL); } else { BOT_WALLET_ADDRESS = (document.querySelector("#botWalletAddress") as HTMLInputElement).value.toLocaleLowerCase(); REPOSITORY_URL = (document.querySelector("#repoURLs") as HTMLInputElement).value.toLocaleLowerCase(); GITHUB_PAT = (document.querySelector("#githubPAT") as HTMLInputElement).value; - parseAndAddUrls(REPOSITORY_URL) + parseAndAddUrls(REPOSITORY_URL); } - const REPOS = getGitHubUrlPartsArray(repoArray) + const REPOS = getGitHubUrlPartsArray(repoArray); - if ( - BOT_WALLET_ADDRESS !== "" && - REPOSITORY_URL !== "" && - GITHUB_PAT !== "" && - REPOS.length > 0 - ) { + if (BOT_WALLET_ADDRESS !== "" && REPOSITORY_URL !== "" && GITHUB_PAT !== "" && REPOS.length > 0) { await asyncInit(); await tabInit(REPOS); } else { @@ -731,38 +723,29 @@ const auditInit = () => { }; /** - * + * * Filter Logics - * + * */ // Function to filter the table based on search input function filterTable() { - const input = document.getElementById("searchInput")! as HTMLInputElement + const input = document.getElementById("searchInput")! as HTMLInputElement; let value = input.value.toLowerCase(); const filteredData = elemList.filter( - (row) => + row => row.owner.toLowerCase().includes(value) || row.repo.toLowerCase().includes(value) || row.amount.toLowerCase().includes(value) || row.tx.toLowerCase().includes(value) || row.title.toLowerCase().includes(value) || row.network.toLowerCase().includes(value) || - row.bounty_hunter.name.toLowerCase().includes(value) + row.bounty_hunter.name.toLowerCase().includes(value), ); resultTableTbodyElem.innerHTML = ""; // Clear the existing rows for (let data of filteredData) { - const { - owner, - repo, - id, - network, - tx, - bounty_hunter, - amount, - title, - } = data as unknown as SavedData - populateTable(owner, repo, id, network, tx, title, amount, bounty_hunter) + const { owner, repo, id, network, tx, bounty_hunter, amount, title } = data as unknown as SavedData; + populateTable(owner, repo, id, network, tx, title, amount, bounty_hunter); } } @@ -776,17 +759,8 @@ function sortTableByAmount() { updateSortArrow(); resultTableTbodyElem.innerHTML = ""; // Clear the existing rows for (let data of elemList) { - const { - owner, - repo, - id, - network, - tx, - bounty_hunter, - amount, - title, - } = data as unknown as SavedData - populateTable(owner, repo, id, network, tx, title, amount, bounty_hunter) + const { owner, repo, id, network, tx, bounty_hunter, amount, title } = data as unknown as SavedData; + populateTable(owner, repo, id, network, tx, title, amount, bounty_hunter); } } diff --git a/static/scripts/audit-report/constants.ts b/static/scripts/audit-report/constants.ts index fbe6773b..256f678b 100644 --- a/static/scripts/audit-report/constants.ts +++ b/static/scripts/audit-report/constants.ts @@ -1,17 +1,17 @@ export enum ChainScan { Ethereum = "etherscan.io", - Gnosis = "gnosisscan.io" + Gnosis = "gnosisscan.io", } export enum Chain { Ethereum = "Ethereum", - Gnosis = "Gnosis" + Gnosis = "Gnosis", } export const ChainMap = { Ethereum: 1, - Gnosis: 100 -} + Gnosis: 100, +}; export const NULL_ID = 0; export const NULL_HASH = "0x0000000000000000000000000000000000000000"; @@ -19,20 +19,11 @@ export const DatabaseName = "file_cache"; // hardcoded values export const API_KEYS = { - [Chain.Ethereum]: [ - "35G6PRE7U54QWZMXYGUSI3YWU27TP2TTBK" - ], - [Chain.Gnosis]: [ - "R75N38X1Y5KP8CRPPDWBRT3EM5VDJ73MUK" - ], + [Chain.Ethereum]: ["35G6PRE7U54QWZMXYGUSI3YWU27TP2TTBK"], + [Chain.Gnosis]: ["R75N38X1Y5KP8CRPPDWBRT3EM5VDJ73MUK"], }; export const RPC_URLS = { - [Chain.Ethereum]: [ - "https://rpc.builder0x69.io", - "https://eth.meowrpc.com", - ], - [Chain.Gnosis]: [ - "https://rpc.ankr.com/gnosis", - ], -} \ No newline at end of file + [Chain.Ethereum]: ["https://rpc.builder0x69.io", "https://eth.meowrpc.com"], + [Chain.Gnosis]: ["https://rpc.ankr.com/gnosis"], +}; diff --git a/static/scripts/audit-report/helpers.ts b/static/scripts/audit-report/helpers.ts index fe98e32f..6c55e766 100644 --- a/static/scripts/audit-report/helpers.ts +++ b/static/scripts/audit-report/helpers.ts @@ -3,13 +3,14 @@ import { API_KEYS, Chain, ChainScan, RPC_URLS } from "./constants"; import { BountyHunter, GitHubUrlParts } from "./types"; export interface RateLimitOptions { - method: string, url: string + method: string; + url: string; } const resultTableTbodyElem = document.querySelector("#resultTable tbody") as HTMLTableCellElement; export const shortenTransactionHash = (hash: string | undefined, length = 8): string => { - if(!hash) return "" + if (!hash) return ""; const prefixLength = Math.floor(length / 2); const suffixLength = length - prefixLength; @@ -19,8 +20,17 @@ export const shortenTransactionHash = (hash: string | undefined, length = 8): st return prefix + "..." + suffix; }; -export const populateTable = (owner: string, repo: string, issue_number: number, network: string, txHash: string, issue_title: string, amount: string, bounty_hunter: BountyHunter) => { - if(!txHash) return; // permit not claimed +export const populateTable = ( + owner: string, + repo: string, + issue_number: number, + network: string, + txHash: string, + issue_title: string, + amount: string, + bounty_hunter: BountyHunter, +) => { + if (!txHash) return; // permit not claimed const issue_url = `https://github.com/${owner}/${repo}/issues/${issue_number}`; const tx_url = `https://${getChainScan(network)}/tx/${txHash}`; const rows = ` @@ -28,18 +38,20 @@ export const populateTable = (owner: string, repo: string, issue_number: number, ${owner}/${repo} #${issue_number} - ${issue_title} ${bounty_hunter?.name} - ${ethers.BigNumber.isBigNumber(amount) ? ethers.utils.formatEther(amount) : amount} ${network === Chain.Ethereum ? "DAI" : "WXDAI"} + ${ethers.BigNumber.isBigNumber(amount) ? ethers.utils.formatEther(amount) : amount} ${ + network === Chain.Ethereum ? "DAI" : "WXDAI" + } ${shortenTransactionHash(txHash)} `; resultTableTbodyElem.insertAdjacentHTML("beforeend", rows); -} +}; export const getChainScan = (chain: string) => { - return chain === Chain.Ethereum ? ChainScan.Ethereum : ChainScan.Gnosis -} + return chain === Chain.Ethereum ? ChainScan.Ethereum : ChainScan.Gnosis; +}; -export const getRandomAPIKey = (chain: Chain): string => { +export const getRandomAPIKey = (chain: Chain): string => { const keys = API_KEYS[chain]; if (!keys || keys.length === 0) { throw new Error(`No API Keys found for chain: ${chain}`); @@ -47,7 +59,7 @@ export const getRandomAPIKey = (chain: Chain): string => { const randomIndex = Math.floor(Math.random() * keys.length); return keys[randomIndex]; -} +}; export const getRandomRpcUrl = (chain: Chain): string => { const urls = RPC_URLS[chain]; @@ -57,7 +69,7 @@ export const getRandomRpcUrl = (chain: Chain): string => { const randomIndex = Math.floor(Math.random() * urls.length); return urls[randomIndex]; -} +}; export const parseRepoUrl = (issueUrl: string): [string, string] => { const match = issueUrl.match(/github\.com\/([^/]+)\/([^/]+)\/issues\/\d+/i); @@ -84,7 +96,7 @@ export const getGitHubUrlPartsArray = (urls: string[]): GitHubUrlParts[] => { } return githubUrlPartsArray; -} +}; export const primaryRateLimitHandler = (retryAfter: number, options: RateLimitOptions) => { console.warn(`Request quota exhausted for request ${options.method} ${options.url}\nRetrying after ${retryAfter} seconds!`); @@ -97,19 +109,18 @@ export const secondaryRateLimitHandler = (retryAfter: number, options: RateLimit }; export const isValidUrl = (urlString: string) => { - try { - return Boolean(new URL(urlString)); - } - catch(e){ - return false; - } -} + try { + return Boolean(new URL(urlString)); + } catch (e) { + return false; + } +}; export const getCurrency = (comment: string) => { - if (comment.includes('WXDAI')) { + if (comment.includes("WXDAI")) { return Chain.Gnosis; - } else if (comment.includes('DAI')) { + } else if (comment.includes("DAI")) { return Chain.Ethereum; } return null; -} \ No newline at end of file +}; diff --git a/static/scripts/audit-report/types/audit.d.ts b/static/scripts/audit-report/types/audit.d.ts index 207d489f..f5d0382c 100644 --- a/static/scripts/audit-report/types/audit.d.ts +++ b/static/scripts/audit-report/types/audit.d.ts @@ -1,8 +1,8 @@ export type ObserverKeys = "isRPC" | "isComment" | "isGit" | "isEther"; export interface BountyHunter { - name: string, - url: string + name: string; + url: string; } export interface ElemInterface { @@ -22,40 +22,40 @@ export interface GitHubUrlParts { } export interface SavedData { - owner: string, - repo: string, - id: number, - network: string, - tx: string, + owner: string; + repo: string; + id: number; + network: string; + tx: string; bounty_hunter: { - url: string, - name: string - }, - amount: string, - title: string + url: string; + name: string; + }; + amount: string; + title: string; } export interface ChainScanResult { - blockNumber: string - timeStamp: string - hash: string - nonce: string - blockHash: string - from: string - contractAddress: string - to: string - value: string - tokenName: string - tokenSymbol: string - tokenDecimal: string - transactionIndex: string - gas: string - gasPrice: string - gasUsed: string - cumulativeGasUsed: string - input: string - confirmations: string - chain: string + blockNumber: string; + timeStamp: string; + hash: string; + nonce: string; + blockHash: string; + from: string; + contractAddress: string; + to: string; + value: string; + tokenName: string; + tokenSymbol: string; + tokenDecimal: string; + transactionIndex: string; + gas: string; + gasPrice: string; + gasUsed: string; + cumulativeGasUsed: string; + input: string; + confirmations: string; + chain: string; } export interface GitInterface { @@ -63,7 +63,7 @@ export interface GitInterface { repo: string; issue_number: number; issue_title: string; - bounty_hunter: BountyHunter + bounty_hunter: BountyHunter; } export interface EtherInterface { @@ -87,7 +87,7 @@ export interface StandardInterface { s: { ether: EtherInterface | undefined; git: GitInterface | undefined; - network: string + network: string; }; } @@ -111,7 +111,7 @@ export interface TxData { export interface QuickImport { WALLET: string; REPO: string; - PAT: string + PAT: string; } declare type TableIndexTypes = NumberConstructor | StringConstructor | BooleanConstructor | DateConstructor | ObjectConstructor | ArrayConstructor; diff --git a/static/styles/audit-report/audit.css b/static/styles/audit-report/audit.css index 8292558b..ef039e13 100644 --- a/static/styles/audit-report/audit.css +++ b/static/styles/audit-report/audit.css @@ -182,4 +182,4 @@ span { position: absolute; top: 50%; transform: translateY(-50%); -} \ No newline at end of file +} diff --git a/static/styles/audit-report/toggle.css b/static/styles/audit-report/toggle.css index ae3fc37d..686026b6 100644 --- a/static/styles/audit-report/toggle.css +++ b/static/styles/audit-report/toggle.css @@ -1,97 +1,94 @@ :root { - --switches-bg-color: black; - --switches-label-color: white; - --switch-bg-color: white; - --switch-text-color: black; + --switches-bg-color: black; + --switches-label-color: white; + --switch-bg-color: white; + --switch-text-color: black; } /* resize font-size on html and body level. html is required for widths based on rem */ @media screen and (min-width: 1024px) { - - html, - body { - font-size: 24px; - } + html, + body { + font-size: 24px; + } } @media screen and (max-width: 1024px) { - - html, - body { - font-size: 16px; - } + html, + body { + font-size: 16px; + } } @media screen and (max-width: 600px) { - - html, - body { - font-size: 12px; - } + html, + body { + font-size: 12px; + } } /* p - decorative, not required */ p { - margin-top: 2rem; - font-size: 0.75rem; - text-align: center; + margin-top: 2rem; + font-size: 0.75rem; + text-align: center; } /* container for all of the switch elements - adjust "width" to fit the content accordingly */ .switches-container { - width: 100%; - position: relative; - display: flex; - padding: 0; - position: relative; - background: var(--switches-bg-color); - line-height: 3rem; - margin-left: auto; - margin-right: auto; - height: 2rem; + width: 100%; + position: relative; + display: flex; + padding: 0; + position: relative; + background: var(--switches-bg-color); + line-height: 3rem; + margin-left: auto; + margin-right: auto; + height: 2rem; } /* input (radio) for toggling. hidden - use labels for clicking on */ .switches-container input { - visibility: hidden; - position: absolute; - top: 0; + visibility: hidden; + position: absolute; + top: 0; } /* labels for the input (radio) boxes - something to click on */ .switches-container label { - width: 50%; - padding: 0; - margin: 0; - text-align: center; - cursor: pointer; - color: var(--switches-label-color); - height: 2rem; - display: flex; - justify-content: center; - align-items: center; + width: 50%; + padding: 0; + margin: 0; + text-align: center; + cursor: pointer; + color: var(--switches-label-color); + height: 2rem; + display: flex; + justify-content: center; + align-items: center; } /* switch highlighters wrapper (sliding left / right) - need wrapper to enable the even margins around the highlight box */ .switch-wrapper { - position: absolute; - top: 0; - bottom: 0; - width: 50%; - padding: 0.15rem; - z-index: 3; - transition: transform 0.5s cubic-bezier(0.77, 0, 0.175, 1); - /* transition: transform 1s; */ + position: absolute; + top: 0; + bottom: 0; + width: 50%; + padding: 0.15rem; + z-index: 3; + transition: transform 0.5s cubic-bezier(0.77, 0, 0.175, 1); + /* transition: transform 1s; */ } /* switch box highlighter */ .switch { - background: var(--switch-bg-color); - height: 100%; + background: var(--switch-bg-color); + height: 100%; } /* switch box labels @@ -99,37 +96,37 @@ p { - toggle afterwards based on radio:checked status */ .switch div { - width: 100%; - text-align: center; - opacity: 0; - color: var(--switch-text-color); - transition: opacity 0.2s cubic-bezier(0.77, 0, 0.175, 1) 0.125s; - will-change: opacity; - position: absolute; - height: 2rem; - top: 0; - left: 0; - display: flex; - justify-content: center; - align-items: center; + width: 100%; + text-align: center; + opacity: 0; + color: var(--switch-text-color); + transition: opacity 0.2s cubic-bezier(0.77, 0, 0.175, 1) 0.125s; + will-change: opacity; + position: absolute; + height: 2rem; + top: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; } /* slide the switch box from right to left */ -.switches-container input:nth-of-type(1):checked~.switch-wrapper { - transform: translateX(0%); +.switches-container input:nth-of-type(1):checked ~ .switch-wrapper { + transform: translateX(0%); } /* slide the switch box from left to right */ -.switches-container input:nth-of-type(2):checked~.switch-wrapper { - transform: translateX(100%); +.switches-container input:nth-of-type(2):checked ~ .switch-wrapper { + transform: translateX(100%); } /* toggle the switch box labels - first checkbox:checked - show first switch div */ -.switches-container input:nth-of-type(1):checked~.switch-wrapper .switch div:nth-of-type(1) { - opacity: 1; +.switches-container input:nth-of-type(1):checked ~ .switch-wrapper .switch div:nth-of-type(1) { + opacity: 1; } /* toggle the switch box labels - second checkbox:checked - show second switch div */ -.switches-container input:nth-of-type(2):checked~.switch-wrapper .switch div:nth-of-type(2) { - opacity: 1; -} \ No newline at end of file +.switches-container input:nth-of-type(2):checked ~ .switch-wrapper .switch div:nth-of-type(2) { + opacity: 1; +} diff --git a/static/styles/rewards/claim-table.css b/static/styles/rewards/claim-table.css index 7d503cfc..3837b1e1 100644 --- a/static/styles/rewards/claim-table.css +++ b/static/styles/rewards/claim-table.css @@ -204,10 +204,13 @@ table[data-contract-loaded] #Token { #rewardAmount a { font-size: 24px; } -#rewardAmount a, #rewardRecipient div, #rewardsCount { +#rewardAmount a, +#rewardRecipient div, +#rewardsCount { color: #fff; } -#nextTx, #previousTx { +#nextTx, +#previousTx { fill: #fff; } table[data-details-visible="false"] #rewardToken .full, diff --git a/static/styles/rewards/light-mode.css b/static/styles/rewards/light-mode.css index 3e46c63d..c148ed78 100644 --- a/static/styles/rewards/light-mode.css +++ b/static/styles/rewards/light-mode.css @@ -49,13 +49,16 @@ div#build > a { color: #000; } - #rewardAmount div, #rewardRecipient div, #rewardsCount { + #rewardAmount div, + #rewardRecipient div, + #rewardsCount { color: #000; } - #nextTx, #previousTx { + #nextTx, + #previousTx { fill: #000; } - + html { background-color: #fff; } diff --git a/tsconfig.json b/tsconfig.json index a925d498..18496e08 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,109 +1,27 @@ { "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ "target": "esnext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, "lib": ["esnext", "dom", "dom.iterable"] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ "types": ["node"] /* Specify type package names to be included without being referenced in a source file. */, - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */ "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ } }