diff --git a/.cspell.json b/.cspell.json index dfd6093..d7ec736 100644 --- a/.cspell.json +++ b/.cspell.json @@ -1,11 +1,45 @@ { "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", "version": "0.2", - "ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log"], + "ignorePaths": ["**/*.json", "**/*.css", "node_modules", "**/*.log", "/lib"], "useGitignore": true, "language": "en", - "words": ["dataurl", "devpool", "outdir", "servedir"], - "dictionaries": ["typescript", "node", "software-terms"], + "words": [ + "binkey", + "binsec", + "chainlist", + "cirip", + "dataurl", + "devpool", + "ethersproject", + "fract", + "gnosisscan", + "godb", + "greyscale", + "IERC", + "keccak", + "keypair", + "libsodium", + "Numberish", + "outdir", + "Rpcs", + "scalarmult", + "servedir", + "solmate", + "sonarjs", + "typebox", + "TYPEHASH", + "ubiquibot", + "UBIQUIBOT", + "URLSAFE", + "WXDAI", + "XDAI", + "xmark", + "supabase", + "SUPABASE" + + ], + "dictionaries": ["typescript", "node", "software-terms", "html"], "import": ["@cspell/dict-typescript/cspell-ext.json", "@cspell/dict-node/cspell-ext.json", "@cspell/dict-software-terms"], "ignoreRegExpList": ["[0-9a-fA-F]{6}"] } diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 899707c..84674e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,9 +27,9 @@ jobs: run: | yarn yarn build - # env: # Set environment variables for the build - # SUPABASE_URL: "https://wfzpewmlyiozupulbuur.supabase.co" - # SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6IndmenBld21seWlvenVwdWxidXVyIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTU2NzQzMzksImV4cCI6MjAxMTI1MDMzOX0.SKIL3Q0NOBaMehH0ekFspwgcu3afp3Dl9EDzPqs1nKs" + env: # Set environment variables for the build + SUPABASE_URL: "https://wfzpewmlyiozupulbuur.supabase.co" + SUPABASE_ANON_KEY: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6IndmenBld21seWlvenVwdWxidXVyIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTU2NzQzMzksImV4cCI6MjAxMTI1MDMzOX0.SKIL3Q0NOBaMehH0ekFspwgcu3afp3Dl9EDzPqs1nKs" - name: Deploy to Cloudflare uses: ubiquity/cloudflare-deploy-action@main diff --git a/README.md b/README.md index f5bdeee..ade7a5a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,20 @@ -# `@ubiquity/ts-template` +# `@ubiquity/audit.ubq.fi` -This template repository includes support for the following: +#### Install Dependencies +- yarn -- TypeScript -- Environment Variables -- Conventional Commits -- Automatic deployment to Cloudflare Pages +#### Build +- yarn build + +### Start UI + +- yarn start + +Test Uses: + +```json +{ + "WALLET": "0xrandomwallet", + "REPO": "https://github.com/repo/repo", + "PAT": "YOUR_PAT" +} diff --git a/build/esbuild-build.ts b/build/esbuild-build.ts index 3004b1d..94f52ed 100644 --- a/build/esbuild-build.ts +++ b/build/esbuild-build.ts @@ -1,10 +1,9 @@ import esbuild from "esbuild"; -const typescriptEntries = ["static/main.ts"]; -// const cssEntries = ["static/style.css"]; -const entries = [ - ...typescriptEntries, - // ...cssEntries -]; +import * as dotenv from "dotenv"; + +const typescriptEntries = ["static/scripts/rewards/index.ts", "static/scripts/audit-report/audit.ts"]; +const cssEntries = ["static/styles/rewards/rewards.css", "static/styles/audit-report/audit.css"]; +export const entries = [...typescriptEntries, ...cssEntries]; export const esBuildContext: esbuild.BuildOptions = { sourcemap: true, @@ -19,7 +18,8 @@ export const esBuildContext: esbuild.BuildOptions = { ".ttf": "dataurl", ".svg": "dataurl", }, - outdir: "static/dist", + outdir: "static/out", + define: createEnvDefines(["SUPABASE_URL", "SUPABASE_ANON_KEY"]), }; esbuild @@ -31,3 +31,17 @@ esbuild console.error(err); process.exit(1); }); + +function createEnvDefines(envVarNames: string[]): Record { + const defines: Record = {}; + dotenv.config(); + for (const name of envVarNames) { + const envVar = process.env[name]; + if (envVar !== undefined) { + defines[name] = JSON.stringify(envVar); + } else { + throw new Error(`Missing environment variable: ${name}`); + } + } + return defines; +} diff --git a/package.json b/package.json index 73e995c..26edb62 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ts-template", "version": "1.0.0", - "description": "Template repository with TypeScript support.", + "description": "audit.ubq.fi", "main": "build/index.ts", "author": "Ubiquity DAO", "license": "MIT", @@ -27,7 +27,14 @@ "open-source" ], "dependencies": { - "dotenv": "^16.4.4" + "@octokit/plugin-throttling": "^8.1.3", + "@octokit/rest": "^20.0.2", + "@sinclair/typebox": "^0.32.14", + "@supabase/supabase-js": "2.39.7", + "axios": "^1.6.7", + "dotenv": "^16.4.4", + "ethers": "^5.7.2", + "godb": "^0.6.2" }, "devDependencies": { "@commitlint/cli": "^18.6.1", diff --git a/static/index.html b/static/index.html index dbae5f4..bf505dc 100644 --- a/static/index.html +++ b/static/index.html @@ -1,13 +1,73 @@ - + - - - Ubiquity TypeScript Template - + Audit report + + + + -

Ubiquity TypeScript Template

- +
+

Audit report

+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
⚡Cache
+
+
+ +
+ + + + + + + + + + + + + + + +
+
+ + diff --git a/static/scripts/audit-report/audit.ts b/static/scripts/audit-report/audit.ts new file mode 100644 index 0000000..ed9f862 --- /dev/null +++ b/static/scripts/audit-report/audit.ts @@ -0,0 +1,750 @@ +import { throttling } from "@octokit/plugin-throttling"; +import { Octokit } from "@octokit/rest"; +import { createClient } from "@supabase/supabase-js"; +import axios from "axios"; +import { ethers } from "ethers"; +import GoDB from "godb"; +import { permit2Abi } from "../rewards/abis"; +import { Chain, ChainScan, DATABASE_NAME, NULL_HASH, NULL_ID } from "./constants"; +import { + getCurrency, + getGitHubUrlPartsArray, + getOptimalRPC, + getRandomAPIKey, + populateTable, + primaryRateLimitHandler, + RateLimitOptions, + secondaryRateLimitHandler, +} from "./helpers"; +import { + ChainScanResult, + ElemInterface, + EtherInterface, + GitHubUrlParts, + GitInterface, + GoDBSchema, + ObserverKeys, + QuickImport, + SavedData, + StandardInterface, + TxData, +} from "./types"; +import { getTxInfo } from "./utils/getTransaction"; + +declare const SUPABASE_URL: string; +declare const SUPABASE_ANON_KEY: string; + +const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY); + +const rateOctokit = Octokit.plugin(throttling); + +let octokit: Octokit; + +let BOT_WALLET_ADDRESS = ""; +let REPOSITORY_URL = ""; +let GITHUB_PAT = ""; + +const repoArray: string[] = []; + +const resultTableElem = document.querySelector("#resultTable") as HTMLElement; +const resultTableTbodyElem = document.querySelector("#resultTable tbody") as HTMLTableCellElement; +const getReportElem = document.querySelector("#getReport") as HTMLButtonElement; +const reportLoader = document.querySelector("#report-loader") as HTMLElement; +const tgBtnInput = document.querySelector("#cb4") as HTMLInputElement; + +let isCache = true; + +// TODO: should be generated directly from the Supabase db schema +interface Permit { + id: number; + created: Date; + updated: Date; + amount: string; + nonce: string; + deadline: string; + signature: string; + token_id: number; + partner_id: null | number; + beneficiary_id: number; + transaction: string; + location_id: number; + locations: { + id: number; + node_id: string; + node_type: string; + updated: Date; + created: Date; + node_url: string; + user_id: number; + repository_id: number; + organization_id: number; + comment_id: number; + issue_id: number; + }; + users: { + id: number; + created: string; + updated: string; + wallet_id: number; + location_id: number; + wallets: { + id: number; + created: string; + updated: Date | null; + address: string; + location_id: number | null; + }; + }; + tokens: { + id: 1; + created: string; + updated: string; + network: number; + address: string; + location_id: null | number; + }; + owner: string; + repo: string; + network_id: number; +} + +const permitList: Permit[] = []; + +let isGit = true; +const offset = 100; + +let isEther = true; +const ETHER_INTERVAL = 250; +let etherPageNumber = 1; + +let isRPC = true; +const RPC_INTERVAL = 50; +const permit2Interface = new ethers.utils.Interface(permit2Abi); +const permitTransferFromSelector = "0x30f28b7a"; +const permitFunctionName = "permitTransferFrom"; +const elemList: ElemInterface[] = []; + +let gitID = NULL_ID; +let etherHash = NULL_HASH; + +let lastGitID: number | boolean = false; +let lastEtherHash: string | boolean = false; + +function getDataSchema(storeHash: string) { + const schema: GoDBSchema = { + [NULL_HASH]: { + id: { + type: String, + unique: true, + }, + hash: { + type: String, + unique: false, + }, + issue: { + type: Number, + unique: false, + }, + }, + [storeHash]: { + id: { + type: Number, + unique: true, + }, + tx: { + type: String, + unique: false, + }, + amount: { + type: String, + unique: false, + }, + title: { + type: String, + unique: false, + }, + }, + }; + + return schema; +} + +function parseAndAddUrls(input: string): void { + const urls = input.split(",").map((url) => url.trim()); + repoArray.push(...urls); +} + +async function updateDB(storeHash: string) { + const schema = getDataSchema(storeHash); + const cacheDB = new GoDB(DATABASE_NAME, schema); + const metaTable = cacheDB.table(NULL_HASH); + const storeTable = cacheDB.table(storeHash); + + const metaData = { + // unknown as number because the only time it receives a string is initiating the db + // and it is always a number after that according to the schema definition + // [NULL_HASH]: id: storeHash + // [STORE_HASH]: id: storeHash + id: storeHash as unknown as number, + hash: lastEtherHash !== etherHash ? (lastEtherHash as string) : (etherHash as string), + issue: lastGitID !== gitID ? (lastGitID as number) : (gitID as number), + }; + + await metaTable.put(metaData); + if (elemList.length > 0) { + for (const elem of elemList) { + const { id, tx, amount, title, bounty_hunter, network, owner, repo } = elem; + await storeTable.put({ + id, + tx, + amount, + title, + bounty_hunter, + network, + owner, + repo, + }); + } + } + return cacheDB.close(); +} + +async function readDB(storeHash: string) { + const schema = getDataSchema(storeHash); + const cacheDB = new GoDB(DATABASE_NAME, schema); + const storeTable = cacheDB.table(storeHash); + const tableData = await storeTable.getAll(); + cacheDB.close(); + return tableData; +} + +async function readMeta(storeHash: string) { + const schema = getDataSchema(storeHash); + const cacheDB = new GoDB(DATABASE_NAME, schema); + const metaTable = cacheDB.table(NULL_HASH); + const metaData = await metaTable.get({ id: storeHash }); + cacheDB.close(); + return metaData; +} + +function toggleLoader(type: "none" | "block") { + getReportElem.disabled = type === "block" ? true : false; + reportLoader.style.display = type; +} + +class QueueObserver { + private readonly _queueObject: { + isRPC: boolean; + isComment: boolean; + isGit: boolean; + isEther: boolean; + }; + private _isException; + + constructor() { + this._queueObject = { + isRPC: false, + isComment: false, + isGit: false, + isEther: false, + }; + this._isException = false; + } + + private _databaseCallback() { + const storeHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`${REPOSITORY_URL}_${BOT_WALLET_ADDRESS}`)); + updateDB(storeHash).catch((error) => console.error(error)); + } + + private _callback() { + toggleLoader("none"); + if (!this._isException) { + this._databaseCallback(); + } + } + + mutate(key: ObserverKeys, value: boolean) { + this._queueObject[key] = value; + const { isRPC, isComment, isGit, isEther } = this._queueObject; + const isUpdateFinished = isRPC && isComment && isGit && isEther; + if (isUpdateFinished) { + this._callback(); + } + } + + clearQueue() { + this._queueObject.isComment = false; + this._queueObject.isEther = false; + this._queueObject.isGit = false; + this._queueObject.isRPC = false; + } + + raise() { + this._isException = true; + } +} + +const finishedQueue = new QueueObserver(); + +class SmartQueue { + private readonly _queue: Map; + + constructor() { + this._queue = new Map(); + } + + add(key: string, value: StandardInterface) { + if (this._queue.has(key)) { + const queueValue = this._queue.get(key) as StandardInterface; + queueValue.s[value.t] = value.s[value.t] as object extends GitInterface ? GitInterface : object extends EtherInterface ? EtherInterface : never; + const { + s: { ether, git, network }, + c: { amount }, + } = queueValue; + + // check for undefined + if (git?.issue_number) { + elemList.push({ + id: git.issue_number, + tx: ether?.txHash || "N/A", // @TODO - handle this better + amount: ethers.utils.formatEther(amount), + title: git.issue_title, + bounty_hunter: git.bounty_hunter, + owner: git.owner, + repo: git.repo, + network, + }); + if (elemList.length > 0) { + resultTableTbodyElem.innerHTML = ""; + for (const data of elemList) { + populateTable(data?.owner, data?.repo, data?.id, data?.network, data?.tx, data?.title, data?.amount, data?.bounty_hunter); + } + } + } + this._queue.delete(key); + } else { + this._queue.set(key, value); + } + } +} +type QueueItem = ChainScanResult; +type Queue = QueueItem extends string ? string[] : QueueItem[]; + +class QueueSet { + private readonly _queue: Queue; + private readonly _set: Set>; + + constructor() { + this._queue = []; + this._set = new Set(); + } + + add(item: NonNullable) { + if (!this._set.has(item)) { + this._set.add(item); + this._queue.push(item as QueueItem); + } + } + + remove() { + const v = this._queue.shift(); + if (v) this._set.delete(v); + } + + read(): ChainScanResult { + return this._queue[0]; + } + + isEmpty() { + return this._queue.length === 0; + } +} + +const updateQueue = new SmartQueue(); +const rpcQueue = new QueueSet(); + +async function getPermitsForRepo(owner: string, repo: string) { + const permitList: Permit[] = []; + try { + const { data: gitData } = await octokit.rest.repos.get({ + owner, + repo, + }); + const { data } = await supabase + .from("permits") + .select("*, locations(*), users(*, wallets(*)), tokens(*)") + .eq("locations.repository_id", gitData?.id) + .not("locations", "is", null); + if (data) { + permitList.push(...data.map((d) => ({ ...d, owner, repo }))); + } + } catch (error) { + console.error(error); + throw error; + } + + return permitList; +} + +async function gitFetcher(repoUrls: GitHubUrlParts[]) { + if (isGit) { + try { + const permitsPromises = repoUrls.map((repoUrl) => getPermitsForRepo(repoUrl.owner, repoUrl.repo)); + const allPermits = await Promise.all(permitsPromises); + + for (let i = 0; i < allPermits.length; i++) { + const issues = allPermits[i]; + permitList.push(...issues); + console.log(`Fetched ${issues.length} permits for repository ${repoUrls[i].owner}/${repoUrls[i].repo}`); + } + isGit = false; + finishedQueue.mutate("isGit", true); + for (const permit of permitList) { + const { data: userData } = await octokit.request("GET /user/:id", { id: permit.locations.user_id }); + const { data } = await supabase.from("locations").select("*").eq("issue_id", permit.locations.issue_id).single(); + const lastSlashIndex = data.node_url.lastIndexOf("/"); + const hashIndex = data.node_url.lastIndexOf("#") || data.node_url.length; + const issueNumber = Number(data.node_url.substring(lastSlashIndex + 1, hashIndex)); + const { data: issueData } = await octokit.rest.issues.get({ + issue_number: issueNumber, + owner: permit.owner, + repo: permit.repo, + }); + updateQueue.add(permit.signature, { + c: { + amount: permit.amount, + deadline: permit.deadline, + nonce: permit.nonce, + owner: permit.owner, + signature: permit.signature, + to: permit.users.wallets.address, + token: permit.tokens.address, + }, + k: permit.signature, + s: { + ether: undefined, + git: { + bounty_hunter: { + name: userData.login, + url: userData.html_url, + }, + issue_number: issueData.number, + issue_title: issueData.title, + owner: permit.owner, + repo: permit.repo, + }, + network: getCurrency(permit.network_id) || Chain.Ethereum, + }, + t: "git", + }); + } + finishedQueue.mutate("isComment", true); + } catch (error) { + console.error(`Error fetching issues: ${error}`); + finishedQueue.mutate("isComment", true); + } + + return permitList; + } +} + +async function fetchDataFromChainScanAPI(url: string, chain: string) { + try { + const { data } = await axios.get(url); + return data.result.map((item: NonNullable) => ({ ...item, chain })); + } catch (error: unknown) { + console.error(error); + throw error; + } +} + +async function etherFetcher() { + const ethereumURL = `https://api.${ChainScan.Ethereum}/api?module=account&action=tokentx&address=${BOT_WALLET_ADDRESS}&apikey=${getRandomAPIKey( + 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 + )}&page=${etherPageNumber}&offset=${offset}&sort=desc`; + + if (isEther) { + const etherIntervalID = setInterval(async () => { + clearInterval(etherIntervalID); + try { + const [ethereumData, gnosisData] = await Promise.all([ + fetchDataFromChainScanAPI(ethereumURL, Chain.Ethereum), + fetchDataFromChainScanAPI(gnosisURL, Chain.Gnosis), + ]); + + const combinedData: ChainScanResult[] = [...ethereumData, ...gnosisData]; + await handleCombinedData(combinedData); + } catch (error: unknown) { + console.error(error); + finishedQueue.raise(); + isEther = false; + finishedQueue.mutate("isEther", true); + } + }, ETHER_INTERVAL); + } +} + +async function handleCombinedData(combinedData: ChainScanResult[]) { + if (combinedData.length > 0) { + if (!lastEtherHash) { + lastEtherHash = combinedData[0].hash; + } + let isIEF = true; + for (const e of combinedData) { + if (e.hash !== etherHash) { + rpcQueue.add({ hash: e.hash, chain: e.chain }); + } else { + isIEF = false; + break; + } + } + + if (isIEF) { + etherPageNumber++; + await etherFetcher(); + } else { + isEther = false; + finishedQueue.mutate("isEther", true); + } + } else { + isEther = false; + finishedQueue.mutate("isEther", true); + } +} + +async function rpcFetcher() { + if (isRPC) { + const rpcIntervalID = setInterval(async () => { + clearInterval(rpcIntervalID); + try { + const data = rpcQueue.read(); + await handleRPCData(data); + rpcQueue.remove(); + if (isEther || !rpcQueue.isEmpty()) { + await rpcFetcher(); + } else { + isRPC = false; + finishedQueue.mutate("isRPC", true); + } + } catch (error: unknown) { + console.error(error); + finishedQueue.raise(); + rpcQueue.remove(); + if (isEther || !rpcQueue.isEmpty()) { + await rpcFetcher(); + } else { + isRPC = false; + finishedQueue.mutate("isRPC", true); + } + } + }, RPC_INTERVAL); + } +} + +async function handleRPCData(data: ChainScanResult) { + if (data) { + const { hash, chain } = data as { hash: string; chain: string }; + const providerUrl = await getOptimalRPC(chain as Chain); + const txInfo = await getTxInfo(hash, providerUrl, chain as Chain); + + if (txInfo.input.startsWith(permitTransferFromSelector)) { + const decodedFunctionData = permit2Interface.decodeFunctionData(permitFunctionName, txInfo.input); + const { + permit: { + permitted: { token, amount }, + nonce, + deadline, + }, + transferDetails: { to }, + owner, + signature, + } = decodedFunctionData as unknown as TxData; + updateQueue.add(signature, { + k: signature, + t: "ether", + c: { + nonce, + owner, + token, + amount, + to, + deadline, + signature, + }, + s: { + ether: { + txHash: txInfo.hash, + timestamp: parseInt(txInfo.timestamp, 16), + block_number: parseInt(txInfo.blockNumber, 16), + }, + git: undefined, + network: chain as string, + }, + }); + } + } +} + +async function dbInit() { + if (isCache) { + const storeHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(`${REPOSITORY_URL}_${BOT_WALLET_ADDRESS}`)); + const metaData = await readMeta(storeHash); + + if (metaData !== undefined) { + const { hash, issue } = metaData; + gitID = issue as number; + etherHash = hash as string; + + const tableData = await readDB(storeHash); + + if (tableData.length > 0) { + for (const data of tableData) { + 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, + tx, + amount, + title, + bounty_hunter, + owner, + repo, + network, + }); + } + } + } + } +} + +async function resetInit() { + permitList.splice(0, permitList.length); + isGit = true; + isEther = true; + etherPageNumber = 1; + isRPC = true; + elemList.splice(0, elemList.length); + gitID = NULL_ID; + etherHash = NULL_HASH; + lastGitID = false; + lastEtherHash = false; + repoArray.splice(0, repoArray.length); + finishedQueue.clearQueue(); +} + +async function asyncInit() { + await resetInit(); + await dbInit(); +} + +function tabInit(repoUrls: GitHubUrlParts[]) { + etherFetcher().catch((error) => console.error(error)); + gitFetcher(repoUrls).catch((error) => console.error(error)); + rpcFetcher().catch((error) => console.error(error)); +} + +function auditInit() { + tgBtnInput.checked = true; + getReportElem.addEventListener("click", async () => { + isCache = tgBtnInput.checked; + toggleLoader("block"); + resultTableElem.style.display = "table"; + resultTableTbodyElem.innerHTML = ""; + const quickImportValue = (document.querySelector("#quickName") as HTMLTextAreaElement).value; + if (quickImportValue !== "") { + const { WALLET, REPO, PAT }: QuickImport = JSON.parse(quickImportValue); + BOT_WALLET_ADDRESS = WALLET.toLocaleLowerCase(); + REPOSITORY_URL = REPO.toLocaleLowerCase(); + GITHUB_PAT = PAT; + 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); + } + + const REPOS = getGitHubUrlPartsArray(repoArray); + + if (BOT_WALLET_ADDRESS !== "" && REPOSITORY_URL !== "" && GITHUB_PAT !== "" && REPOS.length > 0) { + await asyncInit(); + 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); + }, + }, + }); + tabInit(REPOS); + } else { + toggleLoader("none"); + } + }); +} + +/** + * + * Filter Logics + * + */ + +// Function to filter the table based on search input +function filterTable() { + const input = document.getElementById("searchInput") as HTMLInputElement; + const value = input.value.toLowerCase(); + const filteredData = elemList.filter( + (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) + ); + resultTableTbodyElem.innerHTML = ""; // Clear the existing rows + for (const 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); + } +} + +// Variables to track sorting +let sortDirection = 1; // 1 for ascending, -1 for descending + +// Function to sort the table by the "Amount" column +function sortTableByAmount() { + elemList.sort((a, b) => sortDirection * (Number(a.amount) - Number(b.amount))); + sortDirection *= -1; + updateSortArrow(); + resultTableTbodyElem.innerHTML = ""; // Clear the existing rows + for (const 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); + } +} + +// Function to update the sort arrow indicator +function updateSortArrow() { + const sortArrow = document.getElementById("sortArrow") as HTMLElement; + sortArrow.textContent = sortDirection === 1 ? "\u2191" : "\u2193"; +} + +const searchInput = document.getElementById("searchInput") as HTMLInputElement; +const amountHeader = document.getElementById("amountHeader") as HTMLTableCellElement; + +// Add event listener for the search button +searchInput.addEventListener("keyup", filterTable); +// Add event listener for the "Amount" column header +amountHeader.addEventListener("click", sortTableByAmount); + +auditInit(); diff --git a/static/scripts/audit-report/constants.ts b/static/scripts/audit-report/constants.ts new file mode 100644 index 0000000..b828268 --- /dev/null +++ b/static/scripts/audit-report/constants.ts @@ -0,0 +1,30 @@ +export enum ChainScan { + Ethereum = "etherscan.io", + Gnosis = "gnosisscan.io", +} + +export enum Chain { + Ethereum = "Ethereum", + Gnosis = "Gnosis", +} + +export const CHAIN_MAP = { + Ethereum: 1, + Gnosis: 100, +}; + +export const NULL_ID = 0; +export const NULL_HASH = "0x0000000000000000000000000000000000000000"; +export const DATABASE_NAME = "file_cache"; + +// hardcoded values +// cspell:ignore 35G6PRE7U54QWZMXYGUSI3YWU27TP2TTBK R75N38X1Y5KP8CRPPDWBRT3EM5VDJ73MUK +export const API_KEYS = { + [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"], +}; diff --git a/static/scripts/audit-report/helpers.ts b/static/scripts/audit-report/helpers.ts new file mode 100644 index 0000000..38c620b --- /dev/null +++ b/static/scripts/audit-report/helpers.ts @@ -0,0 +1,187 @@ +import axios from "axios"; +import { ethers } from "ethers"; +import { API_KEYS, Chain, ChainScan, RPC_URLS } from "./constants"; +import { BountyHunter, GitHubUrlParts } from "./types"; + +export interface RateLimitOptions { + method: string; + url: string; +} + +const resultTableTbodyElem = document.querySelector("#resultTable tbody") as HTMLTableCellElement; + +type DataType = { + jsonrpc: string; + id: number; + result: { + number: string; + timestamp: string; + hash: string; + }; +}; + +const RPC_BODY = JSON.stringify({ + jsonrpc: "2.0", + method: "eth_getBlockByNumber", + params: ["latest", false], + id: 1, +}); + +const RPC_HEADER = { + "Content-Type": "application/json", +}; + +export function shortenTransactionHash(hash: string | undefined, length = 8): string { + if (!hash) return ""; + const prefixLength = Math.floor(length / 2); + const suffixLength = length - prefixLength; + + const prefix = hash.slice(0, prefixLength); + const suffix = hash.slice(-suffixLength); + + return prefix + "..." + suffix; +} + +export function populateTable( + owner: string, + repo: string, + issueNumber: number, + network: string, + txHash: string, + issueTitle: string, + amount: string, + bountyHunter: BountyHunter +) { + if (!txHash) return; // permit not claimed + const issueUrl = `https://github.com/${owner}/${repo}/issues/${issueNumber}`; + const txUrl = `https://${getChainScan(network)}/tx/${txHash}`; + const rows = ` + + ${owner}/${repo} + #${issueNumber} - ${issueTitle} + ${bountyHunter?.name} + ${ethers.BigNumber.isBigNumber(amount) ? ethers.utils.formatEther(amount) : amount} ${ + network === Chain.Ethereum ? "DAI" : "WXDAI" + } + ${shortenTransactionHash(txHash)} + `; + + resultTableTbodyElem.insertAdjacentHTML("beforeend", rows); +} + +export function getChainScan(chain: string) { + return chain === Chain.Ethereum ? ChainScan.Ethereum : ChainScan.Gnosis; +} + +export function getRandomAPIKey(chain: Chain): string { + const keys = API_KEYS[chain]; + if (!keys || keys.length === 0) { + throw new Error(`No API Keys found for chain: ${chain}`); + } + + const randomIndex = Math.floor(Math.random() * keys.length); + return keys[randomIndex]; +} + +export function getRandomRpcUrl(chain: Chain): string { + const urls = RPC_URLS[chain]; + if (!urls || urls.length === 0) { + throw new Error(`No RPC URLs found for chain: ${chain}`); + } + + const randomIndex = Math.floor(Math.random() * urls.length); + return urls[randomIndex]; +} + +function verifyBlock(data: DataType) { + try { + const { jsonrpc, id, result } = data; + const { number, timestamp, hash } = result; + return jsonrpc === "2.0" && id === 1 && parseInt(number, 16) > 0 && parseInt(timestamp, 16) > 0 && hash.match(/[0-9|a-f|A-F|x]/gm)?.join("").length === 66; + } catch (error) { + return false; + } +} + +export async function getOptimalRPC(chain: Chain): Promise { + const promises = RPC_URLS[chain].map(async (baseURL: string) => { + try { + const startTime = performance.now(); + const API = axios.create({ + baseURL, + headers: RPC_HEADER, + }); + + const { data } = await API.post("", RPC_BODY); + const endTime = performance.now(); + const latency = endTime - startTime; + if (verifyBlock(data)) { + return Promise.resolve({ + latency, + baseURL, + }); + } else { + return Promise.reject(); + } + } catch (error) { + return Promise.reject(); + } + }); + + const { baseURL: optimalRPC } = await Promise.any(promises); + return optimalRPC; +} + +export function parseRepoUrl(issueUrl: string): [string, string] { + const match = issueUrl.match(/github\.com\/([^/]+)\/([^/]+)\/issues\/\d+/i); + if (match) { + const owner = match[1]; + const repo = match[2]; + return [owner, repo]; + } else { + throw new Error("Invalid GitHub issue URL format"); + } +} + +export function getGitHubUrlPartsArray(urls: string[]): GitHubUrlParts[] { + const githubUrlPartsArray: GitHubUrlParts[] = []; + + for (const url of urls) { + const regex = /([^/]+)\/([^/]+)$/i; + const matches = url.match(regex); + if (matches && matches.length === 3) { + const owner = matches[1]; + const repo = matches[2]; + githubUrlPartsArray.push({ owner, repo }); + } + } + + return githubUrlPartsArray; +} + +export function primaryRateLimitHandler(retryAfter: number, options: RateLimitOptions) { + console.warn(`Request quota exhausted for request ${options.method} ${options.url}\nRetrying after ${retryAfter} seconds!`); + return true; +} + +export function secondaryRateLimitHandler(retryAfter: number, options: RateLimitOptions) { + console.warn(`Secondary quota detected for request ${options.method} ${options.url}\nRetrying after ${retryAfter} seconds!`); + return true; +} + +export function isValidUrl(urlString: string) { + try { + return Boolean(new URL(urlString)); + } catch (e) { + return false; + } +} + +export function getCurrency(id: number) { + if (id === 100) { + return Chain.Gnosis; + } else if (id === 1) { + return Chain.Ethereum; + } + return null; +} diff --git a/static/scripts/audit-report/types/audit.d.ts b/static/scripts/audit-report/types/audit.d.ts new file mode 100644 index 0000000..86c3b64 --- /dev/null +++ b/static/scripts/audit-report/types/audit.d.ts @@ -0,0 +1,130 @@ +export type ObserverKeys = "isRPC" | "isComment" | "isGit" | "isEther"; + +export interface BountyHunter { + name: string; + url: string; +} + +export interface ElemInterface { + id: number; + tx: string; + amount: string; + title: string; + bounty_hunter: BountyHunter; + owner: string; + repo: string; + network: string; +} + +export interface GitHubUrlParts { + owner: string; + repo: string; +} + +export interface SavedData { + owner: string; + repo: string; + id: number; + network: string; + tx: string; + bounty_hunter: { + 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; +} + +export interface GitInterface { + owner: string; + repo: string; + issue_number: number; + issue_title: string; + bounty_hunter: BountyHunter; +} + +export interface EtherInterface { + txHash: string; + timestamp: number; + block_number: number; +} + +export interface StandardInterface { + k: string; + t: "git" | "ether"; + c: { + nonce: string; + owner: string; + token: string; + amount: string; + to: string; + deadline: string; + signature: string; + }; + s: { + ether: EtherInterface | undefined; + git: GitInterface | undefined; + network: string; + }; +} + +export interface TxData { + permit: { + permitted: { + token: string; + amount: string; + }; + nonce: string; + deadline: string; + }; + transferDetails: { + to: string; + requestedAmount: string; + }; + owner: string; + signature: string; +} + +export interface QuickImport { + WALLET: string; + REPO: string; + PAT: string; +} + +declare type TableIndexTypes = NumberConstructor | StringConstructor | BooleanConstructor | DateConstructor | ObjectConstructor | ArrayConstructor; +interface TableIndex { + type: TableIndexTypes; + multiEntry?: boolean; + unique?: boolean; + default?: NonNullable; + ref?: string; +} +interface GoDBTableSchema { + [key: string]: TableIndex | TableIndexTypes; +} +export interface GoDBSchema { + [table: string]: GoDBTableSchema; +} diff --git a/static/scripts/audit-report/types/index.ts b/static/scripts/audit-report/types/index.ts new file mode 100644 index 0000000..df50688 --- /dev/null +++ b/static/scripts/audit-report/types/index.ts @@ -0,0 +1 @@ +export * from "./audit"; diff --git a/static/scripts/audit-report/types/transaction.ts b/static/scripts/audit-report/types/transaction.ts new file mode 100644 index 0000000..0d2cd07 --- /dev/null +++ b/static/scripts/audit-report/types/transaction.ts @@ -0,0 +1,6 @@ +export interface Transaction { + input: string; + hash: string; + blockNumber: string; + timestamp: string; +} diff --git a/static/scripts/audit-report/utils/blockInfo.ts b/static/scripts/audit-report/utils/blockInfo.ts new file mode 100644 index 0000000..ee008c6 --- /dev/null +++ b/static/scripts/audit-report/utils/blockInfo.ts @@ -0,0 +1,9 @@ +import { Chain, CHAIN_MAP } from "../constants"; + +export async function getBlockInfo(blockNumber: string, chain: Chain) { + return localStorage.getItem(`${CHAIN_MAP[chain]}:${blockNumber}`); +} + +export async function updateBlockInfo(blockNumber: string, timestamp: string, chain: Chain) { + localStorage.setItem(`${CHAIN_MAP[chain]}:${blockNumber}`, timestamp); +} diff --git a/static/scripts/audit-report/utils/getTransaction.ts b/static/scripts/audit-report/utils/getTransaction.ts new file mode 100644 index 0000000..e165e21 --- /dev/null +++ b/static/scripts/audit-report/utils/getTransaction.ts @@ -0,0 +1,35 @@ +import axios from "axios"; +import { Chain } from "../constants"; +import { Transaction } from "../types/transaction"; +import { getBlockInfo, updateBlockInfo } from "./blockInfo"; + +export async function getTxInfo(hash: string, url: string, chain: Chain): Promise { + try { + const transactionResponse = await axios.post(url, { + jsonrpc: "2.0", + id: 1, + method: "eth_getTransactionByHash", + params: [hash], + }); + const transaction = transactionResponse.data.result as Transaction; + + const timestamp = await getBlockInfo(transaction.blockNumber, chain); + if (timestamp !== null) { + transaction.timestamp = timestamp; + } else { + const blockResponse = await axios.post(url, { + jsonrpc: "2.0", + id: 1, + method: "eth_getBlockByNumber", + params: [transaction.blockNumber, false], + }); + transaction.timestamp = blockResponse.data.result.timestamp; + await updateBlockInfo(transaction.blockNumber, transaction.timestamp, chain); + } + + return transaction; + } catch (error) { + console.error(error); + throw error; + } +} diff --git a/static/scripts/rewards/abis/cirip.json b/static/scripts/rewards/abis/cirip.json new file mode 100644 index 0000000..ecbdc6f --- /dev/null +++ b/static/scripts/rewards/abis/cirip.json @@ -0,0 +1,32 @@ +[ + { + "inputs": [ + { + "internalType": "contract ENS", + "name": "_ens", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "addresses", + "type": "address[]" + } + ], + "name": "getNames", + "outputs": [ + { + "internalType": "string[]", + "name": "r", + "type": "string[]" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/static/scripts/rewards/abis/erc20Abi.ts b/static/scripts/rewards/abis/erc20Abi.ts new file mode 100644 index 0000000..8813685 --- /dev/null +++ b/static/scripts/rewards/abis/erc20Abi.ts @@ -0,0 +1,271 @@ +export const erc20Abi = [ + { inputs: [{ internalType: "uint256", name: "chainId_", type: "uint256" }], payable: false, stateMutability: "nonpayable", type: "constructor" }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "src", type: "address" }, + { indexed: true, internalType: "address", name: "guy", type: "address" }, + { indexed: false, internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: true, + inputs: [ + { indexed: true, internalType: "bytes4", name: "sig", type: "bytes4" }, + { indexed: true, internalType: "address", name: "usr", type: "address" }, + { indexed: true, internalType: "bytes32", name: "arg1", type: "bytes32" }, + { indexed: true, internalType: "bytes32", name: "arg2", type: "bytes32" }, + { indexed: false, internalType: "bytes", name: "data", type: "bytes" }, + ], + name: "LogNote", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "src", type: "address" }, + { indexed: true, internalType: "address", name: "dst", type: "address" }, + { indexed: false, internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "Transfer", + type: "event", + }, + { + constant: true, + inputs: [], + name: "DOMAIN_SEPARATOR", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "PERMIT_TYPEHASH", + outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "usr", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "usr", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "burn", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [{ internalType: "address", name: "guy", type: "address" }], + name: "deny", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "usr", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "mint", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "src", type: "address" }, + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "move", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "nonces", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "holder", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "expiry", type: "uint256" }, + { internalType: "bool", name: "allowed", type: "bool" }, + { internalType: "uint8", name: "v", type: "uint8" }, + { internalType: "bytes32", name: "r", type: "bytes32" }, + { internalType: "bytes32", name: "s", type: "bytes32" }, + ], + name: "permit", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "usr", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "pull", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "usr", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "push", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [{ internalType: "address", name: "guy", type: "address" }], + name: "rely", + outputs: [], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: false, + inputs: [ + { internalType: "address", name: "src", type: "address" }, + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "wad", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + payable: false, + stateMutability: "nonpayable", + type: "function", + }, + { + constant: true, + inputs: [], + name: "version", + outputs: [{ internalType: "string", name: "", type: "string" }], + payable: false, + stateMutability: "view", + type: "function", + }, + { + constant: true, + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "wards", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + payable: false, + stateMutability: "view", + type: "function", + }, +]; diff --git a/static/scripts/rewards/abis/index.ts b/static/scripts/rewards/abis/index.ts new file mode 100644 index 0000000..de30ac1 --- /dev/null +++ b/static/scripts/rewards/abis/index.ts @@ -0,0 +1,2 @@ +export * from "./erc20Abi"; +export * from "./permit2Abi"; diff --git a/static/scripts/rewards/abis/nftRewardAbi.ts b/static/scripts/rewards/abis/nftRewardAbi.ts new file mode 100644 index 0000000..eb89aac --- /dev/null +++ b/static/scripts/rewards/abis/nftRewardAbi.ts @@ -0,0 +1,992 @@ +/* eslint-disable sonarjs/no-duplicate-string */ +export const nftRewardAbi = [ + { + inputs: [ + { + internalType: "string", + name: "_tokenName", + type: "string", + }, + { + internalType: "string", + name: "_tokenSymbol", + type: "string", + }, + { + internalType: "address", + name: "_initialOwner", + type: "address", + }, + { + internalType: "address", + name: "_minter", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "ECDSAInvalidSignature", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "length", + type: "uint256", + }, + ], + name: "ECDSAInvalidSignatureLength", + type: "error", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "s", + type: "bytes32", + }, + ], + name: "ECDSAInvalidSignatureS", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address", + }, + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "ERC721IncorrectOwner", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "operator", + type: "address", + }, + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "ERC721InsufficientApproval", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "approver", + type: "address", + }, + ], + name: "ERC721InvalidApprover", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "operator", + type: "address", + }, + ], + name: "ERC721InvalidOperator", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "ERC721InvalidOwner", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "receiver", + type: "address", + }, + ], + name: "ERC721InvalidReceiver", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "ERC721InvalidSender", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "ERC721NonexistentToken", + type: "error", + }, + { + inputs: [], + name: "EnforcedPause", + type: "error", + }, + { + inputs: [], + name: "ExpectedPause", + type: "error", + }, + { + inputs: [], + name: "InvalidShortString", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "OwnableInvalidOwner", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "OwnableUnauthorizedAccount", + type: "error", + }, + { + inputs: [ + { + internalType: "string", + name: "str", + type: "string", + }, + ], + name: "StringTooLong", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "approved", + type: "address", + }, + { + indexed: true, + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "operator", + type: "address", + }, + { + indexed: false, + internalType: "bool", + name: "approved", + type: "bool", + }, + ], + name: "ApprovalForAll", + type: "event", + }, + { + anonymous: false, + inputs: [], + name: "EIP712DomainChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "from", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: true, + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Unpaused", + type: "event", + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "approve", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "balanceOf", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "baseUri", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "eip712Domain", + outputs: [ + { + internalType: "bytes1", + name: "fields", + type: "bytes1", + }, + { + internalType: "string", + name: "name", + type: "string", + }, + { + internalType: "string", + name: "version", + type: "string", + }, + { + internalType: "uint256", + name: "chainId", + type: "uint256", + }, + { + internalType: "address", + name: "verifyingContract", + type: "address", + }, + { + internalType: "bytes32", + name: "salt", + type: "bytes32", + }, + { + internalType: "uint256[]", + name: "extensions", + type: "uint256[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "getApproved", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "beneficiary", + type: "address", + }, + { + internalType: "uint256", + name: "deadline", + type: "uint256", + }, + { + internalType: "bytes32[]", + name: "keys", + type: "bytes32[]", + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + internalType: "string[]", + name: "values", + type: "string[]", + }, + ], + internalType: "struct NftReward.MintRequest", + name: "_mintRequest", + type: "tuple", + }, + ], + name: "getMintRequestDigest", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getTokenDataKeys", + outputs: [ + { + internalType: "bytes32[]", + name: "", + type: "bytes32[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "operator", + type: "address", + }, + ], + name: "isApprovedForAll", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "minter", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + ], + name: "nonceRedeemed", + outputs: [ + { + internalType: "bool", + name: "isRedeemed", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "ownerOf", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "beneficiary", + type: "address", + }, + { + internalType: "uint256", + name: "deadline", + type: "uint256", + }, + { + internalType: "bytes32[]", + name: "keys", + type: "bytes32[]", + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + internalType: "string[]", + name: "values", + type: "string[]", + }, + ], + internalType: "struct NftReward.MintRequest", + name: "_mintRequest", + type: "tuple", + }, + { + internalType: "bytes", + name: "_signature", + type: "bytes", + }, + ], + name: "recover", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "beneficiary", + type: "address", + }, + { + internalType: "uint256", + name: "deadline", + type: "uint256", + }, + { + internalType: "bytes32[]", + name: "keys", + type: "bytes32[]", + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + internalType: "string[]", + name: "values", + type: "string[]", + }, + ], + internalType: "struct NftReward.MintRequest", + name: "_mintRequest", + type: "tuple", + }, + { + internalType: "bytes", + name: "_signature", + type: "bytes", + }, + ], + name: "safeMint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address", + }, + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address", + }, + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + { + internalType: "bytes", + name: "data", + type: "bytes", + }, + ], + name: "safeTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "operator", + type: "address", + }, + { + internalType: "bool", + name: "approved", + type: "bool", + }, + ], + name: "setApprovalForAll", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "string", + name: "_newBaseUri", + type: "string", + }, + ], + name: "setBaseUri", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_newMinter", + type: "address", + }, + ], + name: "setMinter", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes4", + name: "interfaceId", + type: "bytes4", + }, + ], + name: "supportsInterface", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + { + internalType: "bytes32", + name: "key", + type: "bytes32", + }, + ], + name: "tokenData", + outputs: [ + { + internalType: "string", + name: "value", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "tokenDataKey", + type: "bytes32", + }, + ], + name: "tokenDataKeyExists", + outputs: [ + { + internalType: "bool", + name: "isTokenDataKeyExists", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + name: "tokenDataKeys", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "tokenIdCounter", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "tokenURI", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address", + }, + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "transferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "unpause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]; diff --git a/static/scripts/rewards/abis/permit2Abi.ts b/static/scripts/rewards/abis/permit2Abi.ts new file mode 100644 index 0000000..5d17050 --- /dev/null +++ b/static/scripts/rewards/abis/permit2Abi.ts @@ -0,0 +1,353 @@ +// cspell: word lockdown +export const permit2Abi = [ + { inputs: [{ internalType: "uint256", name: "deadline", type: "uint256" }], name: "AllowanceExpired", type: "error" }, + { inputs: [], name: "ExcessiveInvalidation", type: "error" }, + { inputs: [{ internalType: "uint256", name: "amount", type: "uint256" }], name: "InsufficientAllowance", type: "error" }, + { inputs: [{ internalType: "uint256", name: "maxAmount", type: "uint256" }], name: "InvalidAmount", type: "error" }, + { inputs: [], name: "InvalidContractSignature", type: "error" }, + { inputs: [], name: "InvalidNonce", type: "error" }, + { inputs: [], name: "InvalidSignature", type: "error" }, + { inputs: [], name: "InvalidSignatureLength", type: "error" }, + { inputs: [], name: "InvalidSigner", type: "error" }, + { inputs: [], name: "LengthMismatch", type: "error" }, + { inputs: [{ internalType: "uint256", name: "signatureDeadline", type: "uint256" }], name: "SignatureExpired", type: "error" }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: true, internalType: "address", name: "token", type: "address" }, + { indexed: true, internalType: "address", name: "spender", type: "address" }, + { indexed: false, internalType: "uint160", name: "amount", type: "uint160" }, + { indexed: false, internalType: "uint48", name: "expiration", type: "uint48" }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: false, internalType: "address", name: "token", type: "address" }, + { indexed: false, internalType: "address", name: "spender", type: "address" }, + ], + name: "Lockdown", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: true, internalType: "address", name: "token", type: "address" }, + { indexed: true, internalType: "address", name: "spender", type: "address" }, + { indexed: false, internalType: "uint48", name: "newNonce", type: "uint48" }, + { indexed: false, internalType: "uint48", name: "oldNonce", type: "uint48" }, + ], + name: "NonceInvalidation", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: true, internalType: "address", name: "token", type: "address" }, + { indexed: true, internalType: "address", name: "spender", type: "address" }, + { indexed: false, internalType: "uint160", name: "amount", type: "uint160" }, + { indexed: false, internalType: "uint48", name: "expiration", type: "uint48" }, + { indexed: false, internalType: "uint48", name: "nonce", type: "uint48" }, + ], + name: "Permit", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "owner", type: "address" }, + { indexed: false, internalType: "uint256", name: "word", type: "uint256" }, + { indexed: false, internalType: "uint256", name: "mask", type: "uint256" }, + ], + name: "UnorderedNonceInvalidation", + type: "event", + }, + { inputs: [], name: "DOMAIN_SEPARATOR", outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }], stateMutability: "view", type: "function" }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + ], + name: "allowance", + outputs: [ + { internalType: "uint160", name: "amount", type: "uint160" }, + { internalType: "uint48", name: "expiration", type: "uint48" }, + { internalType: "uint48", name: "nonce", type: "uint48" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint160", name: "amount", type: "uint160" }, + { internalType: "uint48", name: "expiration", type: "uint48" }, + ], + name: "approve", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint48", name: "newNonce", type: "uint48" }, + ], + name: "invalidateNonces", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "wordPos", type: "uint256" }, + { internalType: "uint256", name: "mask", type: "uint256" }, + ], + name: "invalidateUnorderedNonces", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + internalType: "struct IAllowanceTransfer.TokenSpenderPair[]", + name: "approvals", + type: "tuple[]", + }, + ], + name: "lockdown", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + ], + name: "nonceBitmap", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { + components: [ + { + components: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint160", name: "amount", type: "uint160" }, + { internalType: "uint48", name: "expiration", type: "uint48" }, + { internalType: "uint48", name: "nonce", type: "uint48" }, + ], + internalType: "struct IAllowanceTransfer.PermitDetails[]", + name: "details", + type: "tuple[]", + }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "sigDeadline", type: "uint256" }, + ], + internalType: "struct IAllowanceTransfer.PermitBatch", + name: "permitBatch", + type: "tuple", + }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "owner", type: "address" }, + { + components: [ + { + components: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint160", name: "amount", type: "uint160" }, + { internalType: "uint48", name: "expiration", type: "uint48" }, + { internalType: "uint48", name: "nonce", type: "uint48" }, + ], + internalType: "struct IAllowanceTransfer.PermitDetails", + name: "details", + type: "tuple", + }, + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "sigDeadline", type: "uint256" }, + ], + internalType: "struct IAllowanceTransfer.PermitSingle", + name: "permitSingle", + type: "tuple", + }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.TokenPermissions", + name: "permitted", + type: "tuple", + }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.PermitTransferFrom", + name: "permit", + type: "tuple", + }, + { + components: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "requestedAmount", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.SignatureTransferDetails", + name: "transferDetails", + type: "tuple", + }, + { internalType: "address", name: "owner", type: "address" }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "permitTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.TokenPermissions", + name: "permitted", + type: "tuple", + }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.PermitTransferFrom", + name: "permit", + type: "tuple", + }, + { + components: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "requestedAmount", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.SignatureTransferDetails", + name: "transferDetails", + type: "tuple", + }, + { internalType: "address", name: "owner", type: "address" }, + { internalType: "bytes32", name: "witness", type: "bytes32" }, + { internalType: "string", name: "witnessTypeString", type: "string" }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "permitWitnessTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + components: [ + { internalType: "address", name: "token", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.TokenPermissions[]", + name: "permitted", + type: "tuple[]", + }, + { internalType: "uint256", name: "nonce", type: "uint256" }, + { internalType: "uint256", name: "deadline", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.PermitBatchTransferFrom", + name: "permit", + type: "tuple", + }, + { + components: [ + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint256", name: "requestedAmount", type: "uint256" }, + ], + internalType: "struct ISignatureTransfer.SignatureTransferDetails[]", + name: "transferDetails", + type: "tuple[]", + }, + { internalType: "address", name: "owner", type: "address" }, + { internalType: "bytes32", name: "witness", type: "bytes32" }, + { internalType: "string", name: "witnessTypeString", type: "string" }, + { internalType: "bytes", name: "signature", type: "bytes" }, + ], + name: "permitWitnessTransferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint160", name: "amount", type: "uint160" }, + { internalType: "address", name: "token", type: "address" }, + ], + internalType: "struct IAllowanceTransfer.AllowanceTransferDetails[]", + name: "transferDetails", + type: "tuple[]", + }, + ], + name: "transferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "from", type: "address" }, + { internalType: "address", name: "to", type: "address" }, + { internalType: "uint160", name: "amount", type: "uint160" }, + { internalType: "address", name: "token", type: "address" }, + ], + name: "transferFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, +]; diff --git a/static/scripts/rewards/cirip/ens-lookup.ts b/static/scripts/rewards/cirip/ens-lookup.ts new file mode 100644 index 0000000..67a772f --- /dev/null +++ b/static/scripts/rewards/cirip/ens-lookup.ts @@ -0,0 +1,67 @@ +import { ethers } from "ethers"; +import abi from "../abis/cirip.json"; +import { fetchEns } from "./fetch-ens"; +import { queryReverseEns } from "./query-reverse-ens"; + +export const UBIQUITY_RPC_ENDPOINT = "https://rpc-pay.ubq.fi/v1/mainnet"; +export const reverseEnsInterface = new ethers.utils.Interface(abi); + +// addEventListener("fetch", event => { +// event.respondWith(handleRequest(event.request).catch(err => new Response(err.stack, { status: 500 }))); +// }); + +export async function ensLookup(addr: string) { + const _address = "/".concat(addr); // quick adapter + + // try { + const start = _address.indexOf("/0x"); + if (start == -1) throw "No ethereum address provided."; + if (_address.length <= 42 + start) { + throw "Invalid ethereum address provided."; + } + const address = _address.substring(start + 1, start + 43).toLowerCase(); + + let reverseRecord = null as null | string; + // let response = ""; + try { + reverseRecord = await queryReverseEns(address); + const responseParsed = JSON.parse(reverseRecord).result; + const _reverseRecord = ethers.utils.defaultAbiCoder.decode([ethers.utils.ParamType.from("string[]")], responseParsed); + reverseRecord = _reverseRecord[0][0]; + } catch (e) { + console.error(e); + // throw "Error contacting ethereum node. \nCause: '" + e + "'. \nResponse: " + response; + } + + const allDomains = await fetchEns(address); + + if (reverseRecord == "") { + reverseRecord = null; + } + + // if reverse record is set, validate addr owns this domain. + if (reverseRecord != null && !allDomains.includes(reverseRecord)) { + console.warn("Failed to validate! Reverse record set to " + reverseRecord + ", but user does not own this name."); + reverseRecord = null; + } + + return { + reverseRecord: reverseRecord, + domains: allDomains, + }; + // new Response(JSON.stringify(response), { + // headers: { + // "Content-Type": "application/json;charset=UTF-8", + // "Access-Control-Allow-Origin": "*", + // }, + // }); + // } catch (e) { + // return new Response("Error: " + e, { + // status: 400, + // headers: { + // "Content-Type": "text/raw;charset=UTF-8", + // "Access-Control-Allow-Origin": "*", + // }, + // }); + // } +} diff --git a/static/scripts/rewards/cirip/fetch-ens.ts b/static/scripts/rewards/cirip/fetch-ens.ts new file mode 100644 index 0000000..ba3ba46 --- /dev/null +++ b/static/scripts/rewards/cirip/fetch-ens.ts @@ -0,0 +1,12 @@ +import { queryGraph } from "./query-graph"; + +export async function fetchEns(address: string) { + const endpoint = "https://api.thegraph.com/subgraphs/name/ensdomains/ens"; + const query = `{ + domains(where:{owner:"${address.toLowerCase()}"}) { + name + } + }`; + const res = await queryGraph(endpoint, query); + return res.data.domains.map((domain: { name: string }) => domain.name); +} diff --git a/static/scripts/rewards/cirip/query-graph.ts b/static/scripts/rewards/cirip/query-graph.ts new file mode 100644 index 0000000..8df99d5 --- /dev/null +++ b/static/scripts/rewards/cirip/query-graph.ts @@ -0,0 +1,12 @@ +export async function queryGraph(endpoint: string | URL | Request, query: string) { + const response = await fetch(endpoint, { + method: "POST", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + body: JSON.stringify({ query }), + }); + + return response.json(); +} diff --git a/static/scripts/rewards/cirip/query-reverse-ens.ts b/static/scripts/rewards/cirip/query-reverse-ens.ts new file mode 100644 index 0000000..5b14fd7 --- /dev/null +++ b/static/scripts/rewards/cirip/query-reverse-ens.ts @@ -0,0 +1,20 @@ +import { reverseEnsInterface, UBIQUITY_RPC_ENDPOINT } from "./ens-lookup"; + +export async function queryReverseEns(address: string) { + const data = reverseEnsInterface.encodeFunctionData("getNames", [[address.substring(2)]]); + + const response = await fetch(UBIQUITY_RPC_ENDPOINT, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + id: "1", + method: "eth_call", + params: [{ to: "0x3671aE578E63FdF66ad4F3E12CC0c0d71Ac7510C", data: data }, "latest"], + }), + }); + + return response.text(); +} diff --git a/static/scripts/rewards/constants.ts b/static/scripts/rewards/constants.ts new file mode 100644 index 0000000..891a651 --- /dev/null +++ b/static/scripts/rewards/constants.ts @@ -0,0 +1,56 @@ +// type RPC = { url: string; tracking?: string; trackingDetails?: string }; +// type Network = { name?: string; rpcs: RPC[]; websiteDead?: boolean; rpcWorking?: boolean }; +// type Networks = { [key: string]: Network }; + +declare const extraRpcs: Record; // @DEV: passed in at build time check build/esbuild-build.ts + +export enum NetworkIds { + Mainnet = 1, + Goerli = 5, + Gnosis = 100, + Anvil = 31337, +} + +export enum Tokens { + DAI = "0x6b175474e89094c44da98b954eedeac495271d0f", + WXDAI = "0xe91d153e0b41518a2ce8dd3d7944fa863463a97d", +} + +export const networkNames = { + [NetworkIds.Mainnet]: "Ethereum Mainnet", + [NetworkIds.Goerli]: "Goerli Testnet", + [NetworkIds.Gnosis]: "Gnosis Chain", + [NetworkIds.Anvil]: "http://127.0.0.1:8545", +}; + +export const networkCurrencies: Record = { + [NetworkIds.Mainnet]: { symbol: "ETH", decimals: 18 }, + [NetworkIds.Goerli]: { symbol: "GoerliETH", decimals: 18 }, + [NetworkIds.Gnosis]: { symbol: "XDAI", decimals: 18 }, + [NetworkIds.Anvil]: { symbol: "XDAI", decimals: 18 }, +}; + +export function getNetworkName(networkId?: number) { + const networkName = networkNames[networkId as keyof typeof networkNames]; + if (!networkName) { + console.error(`Unknown network ID: ${networkId}`); + } + return networkName ?? "Unknown Network"; +} + +export const networkExplorers: Record = { + [NetworkIds.Mainnet]: "https://etherscan.io", + [NetworkIds.Goerli]: "https://goerli.etherscan.io", + [NetworkIds.Gnosis]: "https://gnosisscan.io", + [NetworkIds.Anvil]: "https://gnosisscan.io", +}; + +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]: ["https://rpc.ankr.com/gnosis", ...(extraRpcs[NetworkIds.Gnosis] || [])], + [NetworkIds.Anvil]: ["http://127.0.0.1:8545", ""], +}; + +export const permit2Address = "0x000000000022D473030F116dDEE9F6B43aC78BA3"; +export const nftAddress = "0xAa1bfC0e51969415d64d6dE74f27CDa0587e645b"; diff --git a/static/scripts/rewards/helpers.ts b/static/scripts/rewards/helpers.ts new file mode 100644 index 0000000..b9c3896 --- /dev/null +++ b/static/scripts/rewards/helpers.ts @@ -0,0 +1,80 @@ +import axios from "axios"; +import { Contract, ethers } from "ethers"; +import { erc20Abi } from "./abis"; +import { JsonRpcProvider } from "@ethersproject/providers"; +import { networkRpcs } from "./constants"; + +type DataType = { + jsonrpc: string; + id: number; + result: { + number: string; + timestamp: string; + hash: string; + }; +}; + +function verifyBlock(data: DataType) { + try { + const { jsonrpc, id, result } = data; + const { number, timestamp, hash } = result; + return jsonrpc === "2.0" && id === 1 && parseInt(number, 16) > 0 && parseInt(timestamp, 16) > 0 && hash.match(/[0-9|a-f|A-F|x]/gm)?.join("").length === 66; + } catch (error) { + return false; + } +} + +const RPC_BODY = JSON.stringify({ + jsonrpc: "2.0", + method: "eth_getBlockByNumber", + params: ["latest", false], + id: 1, +}); + +const RPC_HEADER = { + "Content-Type": "application/json", +}; + +export async function getErc20Contract(contractAddress: string, provider: JsonRpcProvider): Promise { + return new ethers.Contract(contractAddress, erc20Abi, provider); +} + +export async function getOptimalProvider(networkId: number) { + if (networkId === 31337) + return new ethers.providers.JsonRpcProvider("http://127.0.0.1:8545", { + name: "http://127.0.0.1:8545", + chainId: 31337, + ensAddress: "", + }); + + const promises = networkRpcs[networkId].map(async (baseURL: string) => { + try { + const startTime = performance.now(); + const API = axios.create({ + baseURL, + headers: RPC_HEADER, + }); + + const { data } = await API.post("", RPC_BODY); + const endTime = performance.now(); + const latency = endTime - startTime; + if (verifyBlock(data)) { + return Promise.resolve({ + latency, + baseURL, + }); + } else { + return Promise.reject(); + } + } catch (error) { + return Promise.reject(); + } + }); + + const { baseURL: optimalRPC } = await Promise.any(promises); + return new ethers.providers.JsonRpcProvider(optimalRPC, { + name: optimalRPC, + chainId: networkId, + ensAddress: "", + }); +} diff --git a/static/scripts/rewards/index.ts b/static/scripts/rewards/index.ts new file mode 100644 index 0000000..9aa754c --- /dev/null +++ b/static/scripts/rewards/index.ts @@ -0,0 +1,20 @@ +import { init } from "./render-transaction/render-transaction"; +import { grid } from "./the-grid"; + +(async function appAsyncWrapper() { + try { + // display commit hash + const commit = await fetch("commit.txt"); + if (commit.ok) { + const commitHash = await commit.text(); + const buildElement = document.querySelector(`#build a`) as HTMLAnchorElement; + buildElement.innerHTML = commitHash; + buildElement.href = `https://github.com/ubiquity/pay.ubq.fi/commit/${commitHash}`; + } + init().catch(console.error); + } catch (error) { + console.error(error); + } +})().catch(console.error); + +grid(document.getElementById("grid") as HTMLElement); diff --git a/static/scripts/rewards/invalidate-component.ts b/static/scripts/rewards/invalidate-component.ts new file mode 100644 index 0000000..8687d32 --- /dev/null +++ b/static/scripts/rewards/invalidate-component.ts @@ -0,0 +1,12 @@ +const invalidateBtnInnerHTML = `
Void
+`; + +// parse string and turn into an html entity +function parseHtml(html: string) { + const button = document.createElement("button"); + button.id = "invalidateBtn"; + button.innerHTML = html; + return button.cloneNode(true) as HTMLButtonElement; +} + +export default parseHtml(invalidateBtnInnerHTML); diff --git a/static/scripts/rewards/render-transaction/index.ts b/static/scripts/rewards/render-transaction/index.ts new file mode 100644 index 0000000..ee56eba --- /dev/null +++ b/static/scripts/rewards/render-transaction/index.ts @@ -0,0 +1,42 @@ +import { networkExplorers } from "../constants"; +import { getOptimalProvider } from "../helpers"; +import { ClaimTx } from "./tx-type"; + +class AppState { + public claimTxs: ClaimTx[] = []; + private _currentIndex = 0; + + get currentIndex(): number { + return this._currentIndex; + } + + get currentTx(): ClaimTx | null { + return this.currentIndex < this.claimTxs.length ? this.claimTxs[this.currentIndex] : null; + } + + async currentNetworkRpc(): Promise { + if (!this.currentTx) { + return (await getOptimalProvider(1)).connection.url; + } + return (await getOptimalProvider(this.currentTx.networkId)).connection.url; + } + + get currentExplorerUrl(): string { + if (!this.currentTx) { + return "https://etherscan.io"; + } + return networkExplorers[this.currentTx.networkId] || "https://etherscan.io"; + } + + nextTx(): ClaimTx | null { + this._currentIndex = Math.min(this.claimTxs.length - 1, this._currentIndex + 1); + return this.currentTx; + } + + previousTx(): ClaimTx | null { + this._currentIndex = Math.max(0, this._currentIndex - 1); + return this.currentTx; + } +} + +export const app = new AppState(); diff --git a/static/scripts/rewards/render-transaction/insert-table-data.ts b/static/scripts/rewards/render-transaction/insert-table-data.ts new file mode 100644 index 0000000..0da3719 --- /dev/null +++ b/static/scripts/rewards/render-transaction/insert-table-data.ts @@ -0,0 +1,129 @@ +import { ethers } from "ethers"; +import { app } from "."; +import { Erc20Permit, Erc721Permit } from "./tx-type"; +import { fetchTreasury } from "../web3/erc20-permit"; +import { renderTokenSymbol } from "./render-token-symbol"; +import { networkExplorers } from "../constants"; + +export function shortenAddress(address: string): string { + return `${address.slice(0, 10)}...${address.slice(-8)}`; +} + +export async function insertErc20PermitTableData( + permit: Erc20Permit, + provider: ethers.providers.JsonRpcProvider, + symbol: string, + decimals: number, + table: Element +) { + const requestedAmountElement = document.getElementById("rewardAmount") as Element; + renderToFields(permit.transferDetails.to, app.currentExplorerUrl); + renderTokenFields(permit.permit.permitted.token, app.currentExplorerUrl); + + renderDetailsFields([ + { 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, + }, + { name: "Balance", value: "Loading..." }, + { name: "Allowance", value: "Loading..." }, + ]); + + renderTokenSymbol({ + requestedAmountElement, + tokenAddress: permit.permit.permitted.token, + ownerAddress: permit.owner, + amount: permit.transferDetails.requestedAmount, + explorerUrl: networkExplorers[permit.networkId], + symbol, + decimals, + }); + + // Optimistically rendered what we can so consider it loaded + table.setAttribute(`data-claim`, "ok"); + table.setAttribute(`data-contract-loaded`, "true"); + table.setAttribute(`data-claim-rendered`, "true"); + + const { balance, allowance } = await fetchTreasury(permit.permit.permitted.token, permit.owner, provider); + + renderDetailsFields([ + { 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, + }, + { name: "Balance", value: balance.gte(0) ? `${ethers.utils.formatUnits(balance, decimals)} ${symbol}` : "N/A" }, + { name: "Allowance", value: allowance.gte(0) ? `${ethers.utils.formatUnits(allowance, decimals)} ${symbol}` : "N/A" }, + ]); +} + +export function insertErc721PermitTableData(permit: Erc721Permit, table: Element): Element { + const requestedAmountElement = document.getElementById("rewardAmount") as Element; + renderToFields(permit.request.beneficiary, app.currentExplorerUrl); + renderTokenFields(permit.nftAddress, app.currentExplorerUrl); + const { GITHUB_REPOSITORY_NAME, GITHUB_CONTRIBUTION_TYPE, GITHUB_ISSUE_ID, GITHUB_ORGANIZATION_NAME, GITHUB_USERNAME } = permit.nftMetadata; + renderDetailsFields([ + { + name: "NFT address", + value: `${permit.nftAddress}`, + }, + { + name: "Expiry", + value: permit.request.deadline.lte(Number.MAX_SAFE_INTEGER.toString()) ? new Date(permit.request.deadline.toNumber()).toLocaleString() : undefined, + }, + { + name: "GitHub Organization", + value: `${GITHUB_ORGANIZATION_NAME}`, + }, + { + name: "GitHub Repository", + value: `${GITHUB_REPOSITORY_NAME}`, + }, + { + name: "GitHub Issue", + value: `${GITHUB_ISSUE_ID}`, + }, + { + name: "GitHub Username", + value: `${GITHUB_USERNAME}`, + }, + { name: "Contribution Type", value: GITHUB_CONTRIBUTION_TYPE.split(",").join(", ") }, + ]); + table.setAttribute(`data-claim-rendered`, "true"); + return requestedAmountElement; +} + +function renderDetailsFields(additionalDetails: { name: string; value: string | undefined }[]) { + const additionalDetailsDiv = document.getElementById("additionalDetailsTable") as Element; + let additionalDetailsHtml = ""; + for (const { name, value } of additionalDetails) { + if (!value) continue; + additionalDetailsHtml += ` +
${name}
+
${value}
+ `; + } + + additionalDetailsDiv.innerHTML = additionalDetailsHtml; +} + +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)}
`; + + const tokenBoth = document.getElementById(`rewardToken`) as Element; + tokenBoth.innerHTML = `${tokenBoth.innerHTML}`; +} + +function renderToFields(receiverAddress: string, explorerUrl: string) { + const toFull = document.querySelector("#To .full") as Element; + const toShort = document.querySelector("#To .short") as Element; + toFull.innerHTML = `
${receiverAddress}
`; + toShort.innerHTML = `
${shortenAddress(receiverAddress)}
`; + + const toBoth = document.getElementById(`rewardRecipient`) as Element; + toBoth.innerHTML = `${toBoth.innerHTML}`; +} diff --git a/static/scripts/rewards/render-transaction/render-ens-name.ts b/static/scripts/rewards/render-transaction/render-ens-name.ts new file mode 100644 index 0000000..8be3262 --- /dev/null +++ b/static/scripts/rewards/render-transaction/render-ens-name.ts @@ -0,0 +1,42 @@ +import { ensLookup } from "../cirip/ens-lookup"; +import { app } from "./index"; + +type EnsParams = + | { + element: Element; + address: string; + tokenAddress: string; + tokenView: true; + } + | { + element: Element; + address: string; + tokenAddress?: undefined; + tokenView?: false; + }; + +export async function renderEnsName({ element, address, tokenAddress, tokenView }: EnsParams): Promise { + let href: string = ""; + try { + const resolved = await ensLookup(address); + let ensName: undefined | string; + if (resolved.reverseRecord) { + ensName = resolved.reverseRecord; + } else if (resolved.domains.length) { + const domain = resolved.domains.shift(); + if (domain) { + ensName = domain; + } + } + if (ensName) { + if (tokenView) { + href = `${app.currentExplorerUrl}/token/${tokenAddress}?a=${address}`; + } else { + href = `${app.currentExplorerUrl}/address/${address}"`; + } + element.innerHTML = `${ensName}`; + } + } catch (error) { + console.error(error); + } +} diff --git a/static/scripts/rewards/render-transaction/render-token-symbol.ts b/static/scripts/rewards/render-transaction/render-token-symbol.ts new file mode 100644 index 0000000..429bda7 --- /dev/null +++ b/static/scripts/rewards/render-transaction/render-token-symbol.ts @@ -0,0 +1,56 @@ +import { BigNumberish, utils } from "ethers"; +import { getErc20Contract } from "../helpers"; +import { JsonRpcProvider } from "@ethersproject/providers"; + +export const tokens = [ + { + name: "WXDAI", + address: "0xe91d153e0b41518a2ce8dd3d7944fa863463a97d", + }, + { + name: "DAI", + address: "0x6b175474e89094c44da98b954eedeac495271d0f", + }, +]; + +export function renderTokenSymbol({ + requestedAmountElement, + tokenAddress, + ownerAddress, + amount, + explorerUrl, + symbol, + decimals, +}: { + requestedAmountElement: Element; + tokenAddress: string; + ownerAddress: string; + amount: BigNumberish; + explorerUrl: string; + symbol: string; + decimals: number; +}) { + return (requestedAmountElement.innerHTML = `${utils.formatUnits( + amount, + decimals + )} ${symbol}`); +} + +export async function renderNftSymbol({ + table, + requestedAmountElement, + tokenAddress, + explorerUrl, + provider, +}: { + table: Element; + requestedAmountElement: Element; + tokenAddress: string; + explorerUrl: string; + provider: JsonRpcProvider; +}): Promise { + const contract = await getErc20Contract(tokenAddress, provider); + const symbol = await contract.symbol(); + table.setAttribute(`data-contract-loaded`, "true"); + requestedAmountElement.innerHTML = `1 ${symbol}`; +} diff --git a/static/scripts/rewards/render-transaction/render-transaction.ts b/static/scripts/rewards/render-transaction/render-transaction.ts new file mode 100644 index 0000000..4f3d015 --- /dev/null +++ b/static/scripts/rewards/render-transaction/render-transaction.ts @@ -0,0 +1,155 @@ +import { JsonRpcProvider } from "@ethersproject/providers"; +import { Type } from "@sinclair/typebox"; +import { Value } from "@sinclair/typebox/value"; +import { networkExplorers } from "../constants"; +import { getOptimalProvider } from "../helpers"; +import { claimButton, hideClaimButton, resetClaimButton } from "../toaster"; +import { claimErc20PermitHandler, generateInvalidatePermitAdminControl, processERC20 } from "../web3/erc20-permit"; +import { claimErc721PermitHandler } from "../web3/erc721-permit"; +import { app } from "./index"; +import { insertErc721PermitTableData } from "./insert-table-data"; +import { renderEnsName } from "./render-ens-name"; +import { renderNftSymbol } from "./render-token-symbol"; +import { setClaimMessage } from "./set-claim-message"; +import { claimTxT } from "./tx-type"; +import { removeAllEventListeners } from "./utils"; +import { handleNetwork } from "../web3/wallet"; + +let optimalRPC: JsonRpcProvider; + +export async function init() { + const table = document.getElementsByTagName(`table`)[0]; + + // decode base64 to get tx data + const urlParams = new URLSearchParams(window.location.search); + const base64encodedTxData = urlParams.get("claim"); + + if (!base64encodedTxData) { + setClaimMessage({ type: "Notice", message: `No claim data found.` }); + table.setAttribute(`data-claim`, "none"); + return false; + } + + try { + const claimTxs = Value.Decode(Type.Array(claimTxT), JSON.parse(atob(base64encodedTxData))); + app.claimTxs = claimTxs; + optimalRPC = await getOptimalProvider(app.currentTx?.networkId ?? app.claimTxs[0].networkId); + + handleNetwork(app.currentTx?.networkId ?? app.claimTxs[0].networkId).catch(console.error); + } catch (error) { + console.error(error); + setClaimMessage({ type: "Error", message: `Invalid claim data passed in URL` }); + table.setAttribute(`data-claim`, "error"); + return false; + } + + let isDetailsVisible = false; + + table.setAttribute(`data-details-visible`, isDetailsVisible.toString()); + + const additionalDetails = document.getElementById(`additionalDetails`) as Element; + additionalDetails.addEventListener("click", () => { + isDetailsVisible = !isDetailsVisible; + table.setAttribute(`data-details-visible`, isDetailsVisible.toString()); + }); + + const rewardsCount = document.getElementById("rewardsCount"); + if (rewardsCount) { + if (!app.claimTxs || app.claimTxs.length <= 1) { + // already hidden + } else { + rewardsCount.innerHTML = `${app.currentIndex + 1}/${app.claimTxs.length} reward`; + + const nextTxButton = document.getElementById("nextTx"); + if (nextTxButton) { + nextTxButton.addEventListener("click", () => { + claimButton.element = removeAllEventListeners(claimButton.element) as HTMLButtonElement; + app.nextTx(); + rewardsCount.innerHTML = `${app.currentIndex + 1}/${app.claimTxs.length} reward`; + table.setAttribute(`data-claim`, "none"); + renderTransaction(optimalRPC, true).catch(console.error); + }); + } + + const prevTxButton = document.getElementById("previousTx"); + if (prevTxButton) { + prevTxButton.addEventListener("click", () => { + claimButton.element = removeAllEventListeners(claimButton.element) as HTMLButtonElement; + app.previousTx(); + rewardsCount.innerHTML = `${app.currentIndex + 1}/${app.claimTxs.length} reward`; + table.setAttribute(`data-claim`, "none"); + renderTransaction(optimalRPC, true).catch(console.error); + }); + } + + setPagination(nextTxButton, prevTxButton); + } + } + + renderTransaction(optimalRPC).catch(console.error); +} + +function setPagination(nextTxButton: Element | null, prevTxButton: Element | null) { + if (!nextTxButton || !prevTxButton) return; + if (app.claimTxs.length > 1) { + prevTxButton.classList.remove("hide-pagination"); + nextTxButton.classList.remove("hide-pagination"); + + prevTxButton.classList.add("show-pagination"); + nextTxButton.classList.add("show-pagination"); + } +} + +type Success = boolean; +export async function renderTransaction(provider: JsonRpcProvider, nextTx?: boolean): Promise { + const table = document.getElementsByTagName(`table`)[0]; + resetClaimButton(); + + if (nextTx) { + app.nextTx(); + if (!app.claimTxs || app.claimTxs.length <= 1) { + // already hidden + } else { + setPagination(document.getElementById("nextTx"), document.getElementById("previousTx")); + + const rewardsCount = document.getElementById("rewardsCount") as Element; + rewardsCount.innerHTML = `${app.currentIndex + 1}/${app.claimTxs.length} reward`; + table.setAttribute(`data-claim`, "none"); + } + } + + if (!app.currentTx) { + hideClaimButton(); + return false; + } + + if (app.currentTx.type === "erc20-permit") { + await processERC20(app.currentTx.permit.permitted.token, provider, app.currentTx, table); + + // insert tx data into table + const toElement = document.getElementById(`rewardRecipient`) as Element; + renderEnsName({ element: toElement, address: app.currentTx.transferDetails.to }).catch(console.error); + + generateInvalidatePermitAdminControl(app.currentTx).catch(console.error); + + claimButton.element.addEventListener("click", claimErc20PermitHandler(app.currentTx, optimalRPC)); + } else if (app.currentTx.type === "erc721-permit") { + const requestedAmountElement = insertErc721PermitTableData(app.currentTx, table); + table.setAttribute(`data-claim`, "ok"); + + renderNftSymbol({ + tokenAddress: app.currentTx.nftAddress, + explorerUrl: networkExplorers[app.currentTx.networkId], + table, + requestedAmountElement, + provider, + }).catch(console.error); + + const toElement = document.getElementById(`rewardRecipient`) as Element; + renderEnsName({ element: toElement, address: app.currentTx.request.beneficiary }).catch(console.error); + + claimButton.element.addEventListener("click", claimErc721PermitHandler(app.currentTx, provider)); + } + + return true; +} diff --git a/static/scripts/rewards/render-transaction/set-claim-message.ts b/static/scripts/rewards/render-transaction/set-claim-message.ts new file mode 100644 index 0000000..51d38d1 --- /dev/null +++ b/static/scripts/rewards/render-transaction/set-claim-message.ts @@ -0,0 +1,6 @@ +export function setClaimMessage({ type, message }: { type: string; message: string }): void { + const claimMessageType = document.querySelector(`table > thead th`) as Element; + const claimMessageBody = document.querySelector(`table > thead td`) as Element; + claimMessageType.innerHTML = `
${type}
`; + claimMessageBody.innerHTML = `
${message}
`; +} diff --git a/static/scripts/rewards/render-transaction/tx-type.ts b/static/scripts/rewards/render-transaction/tx-type.ts new file mode 100644 index 0000000..23df134 --- /dev/null +++ b/static/scripts/rewards/render-transaction/tx-type.ts @@ -0,0 +1,68 @@ +import { StaticDecode, Type as T } from "@sinclair/typebox"; +import { BigNumber } from "ethers"; + +const bigNumberT = T.Transform(T.Union([T.RegExp(/^\d+$/), T.Number()])) + .Decode((value) => BigNumber.from(value)) + .Encode((value) => value.toString()); + +// const networkIdT = T.Transform(T.Union([T.RegExp(/^0x\d+$/), T.Number()])) +// .Decode(value => (typeof value === "number" ? "0x" + value.toString(16) : value)) +// .Encode(value => value); + +const networkIdT = T.Number(); + +const addressT = T.Transform(T.RegExp(/^0x[a-fA-F0-9]{40}$/)) + .Decode((value) => value.toLowerCase()) + .Encode((value) => value); + +const signatureT = T.Transform(T.RegExp(/^0x[a-fA-F0-9]+$/)) + .Decode((value) => value.toLowerCase()) + .Encode((value) => value); + +const erc20PermitT = T.Object({ + type: T.Literal("erc20-permit"), + permit: T.Object({ + permitted: T.Object({ + token: addressT, + amount: bigNumberT, + }), + nonce: bigNumberT, + deadline: bigNumberT, + }), + transferDetails: T.Object({ + to: addressT, + requestedAmount: bigNumberT, + }), + owner: addressT, + signature: signatureT, + networkId: networkIdT, +}); + +export type Erc20Permit = StaticDecode; + +const erc721Permit = T.Object({ + type: T.Literal("erc721-permit"), + request: T.Object({ + beneficiary: addressT, + deadline: bigNumberT, + keys: T.Array(T.String()), + nonce: bigNumberT, + values: T.Array(T.String()), + }), + nftMetadata: T.Object({ + GITHUB_ORGANIZATION_NAME: T.String(), + GITHUB_REPOSITORY_NAME: T.String(), + GITHUB_ISSUE_ID: T.String(), + GITHUB_USERNAME: T.String(), + GITHUB_CONTRIBUTION_TYPE: T.String(), + }), + nftAddress: addressT, + networkId: networkIdT, + signature: signatureT, +}); + +export type Erc721Permit = StaticDecode; + +export const claimTxT = T.Union([erc20PermitT, erc721Permit]); + +export type ClaimTx = StaticDecode; diff --git a/static/scripts/rewards/render-transaction/utils.ts b/static/scripts/rewards/render-transaction/utils.ts new file mode 100644 index 0000000..80281a6 --- /dev/null +++ b/static/scripts/rewards/render-transaction/utils.ts @@ -0,0 +1,5 @@ +export function removeAllEventListeners(element: Element): Element { + const clone = element.cloneNode(true) as Element; + element.replaceWith(clone); + return clone; +} diff --git a/static/scripts/rewards/the-grid.ts b/static/scripts/rewards/the-grid.ts new file mode 100644 index 0000000..bd9832e --- /dev/null +++ b/static/scripts/rewards/the-grid.ts @@ -0,0 +1,160 @@ +export function grid(node = document.body) { + // Create canvas and WebGL context + const canvas = document.createElement("canvas"); + const devicePixelRatio = window.devicePixelRatio || 1; + canvas.width = window.innerWidth * devicePixelRatio; + canvas.height = window.innerHeight * devicePixelRatio; + node.appendChild(canvas); + + const gl = canvas.getContext("webgl") as WebGLRenderingContext; + + // Enable alpha blending + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + + // Define shader sources + const vertexShaderSource = ` + attribute vec2 a_position; + + void main() { + gl_Position = vec4(a_position, 0, 1); + } +`; + + // cspell:ignore mediump + const fragmentShaderSource = ` + precision mediump float; + + uniform vec2 u_resolution; + uniform float u_time; + + float rand(vec2 n) { + return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453); + } + + void main() { + vec3 color = vec3(128.0/255.0, 128.0/255.0, 128.0/255.0); // #808080 + vec2 tilePosition = mod(gl_FragCoord.xy, 24.0); + vec2 tileNumber = floor(gl_FragCoord.xy / 24.0); + + float period = rand(tileNumber) * 9.0 + 1.0; // Random value in the range [1, 10] + float phase = fract(u_time / period / 8.0); // Animation eight times slower + float opacity = (1.0 - abs(phase * 2.0 - 1.0)) * 0.125; // Limit maximum opacity to 0.25 + + vec4 backgroundColor = vec4(color, opacity); + + if (tilePosition.x > 23.0 && tilePosition.y < 1.0) { + gl_FragColor = vec4(color, 1.0); // Full opacity for the dot + } else { + gl_FragColor = backgroundColor; + } + } +`; + + // Define shader creation function + function createShader(gl: WebGLRenderingContext, type: number, source: string) { + const shader = gl.createShader(type); + if (!shader) { + console.error("An error occurred creating the shaders"); + return null; + } + gl.shaderSource(shader, source); + gl.compileShader(shader); + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.error("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)); + gl.deleteShader(shader); + return null; + } + return shader; + } + + // Create vertex and fragment shaders + const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource); + if (!vertexShader) { + console.error("An error occurred creating the vertex shader"); + return; + } + const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource); + if (!fragmentShader) { + console.error("An error occurred creating the fragment shader"); + return; + } + + // Create program, attach shaders, and link + const program = gl.createProgram(); + if (!program) { + console.error("An error occurred creating the program"); + return; + } + + gl.attachShader(program, vertexShader); + gl.attachShader(program, fragmentShader); + gl.linkProgram(program); + + // Verify program link status + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + console.error("Unable to initialize the shader program: " + gl.getProgramInfoLog(program)); + return; + } + + // Use the program + gl.useProgram(program); + + // Get location of time and resolution uniforms + const timeUniformLocation = gl.getUniformLocation(program, "u_time"); + const resolutionUniformLocation = gl.getUniformLocation(program, "u_resolution"); + + // Bind the position buffer and set attribute pointer + const positionBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW); + + const positionAttributeLocation = gl.getAttribLocation(program, "a_position"); + gl.enableVertexAttribArray(positionAttributeLocation); + gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0); + + // Resize function + function resizeCanvasToDisplaySize(canvas: HTMLCanvasElement) { + // Lookup the size the browser is displaying the canvas. + const displayWidth = window.innerWidth; + const displayHeight = window.innerHeight; + + // Check if the canvas is not the same size. + if (canvas.width != displayWidth || canvas.height != displayHeight) { + // Make the canvas the same size + canvas.width = displayWidth; + canvas.height = displayHeight; + + // Update WebGL viewport to match + gl.viewport(0, 0, canvas.width, canvas.height); + } + } + + // Render function + function render() { + resizeCanvasToDisplaySize(canvas); // Check and update canvas size each frame + + // Update resolution uniform + gl.uniform2f(resolutionUniformLocation, canvas.width, canvas.height); + + gl.clearColor(0.0, 0.0, 0.0, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT); + + // Update time uniform + gl.uniform1f(timeUniformLocation, performance.now() / 1000.0); + + // Draw + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); + + // Request next frame + requestAnimationFrame(render); + } + + // Handle window resize + window.addEventListener("resize", () => { + resizeCanvasToDisplaySize(canvas); + }); + + // Start the render loop + render(); +} diff --git a/static/scripts/rewards/toaster.ts b/static/scripts/rewards/toaster.ts new file mode 100644 index 0000000..9294e72 --- /dev/null +++ b/static/scripts/rewards/toaster.ts @@ -0,0 +1,89 @@ +export const toaster = { + create: createToast, + error: errorToast, + icons: { + success: "fa-circle-check", + error: "fa-circle-xmark", + warning: "fa-triangle-exclamation", + info: "fa-circle-info", + }, +}; + +export const claimButton = { + loading: loadingClaimButton, + reset: resetClaimButton, + element: document.getElementById("claimButton") as HTMLButtonElement, +}; + +const notifications = document.querySelector(".notifications") as HTMLUListElement; + +export function createToast(meaning: keyof typeof toaster.icons, text: string) { + const toastDetails = { + timer: 5000, + } as { + timer: number; + timeoutId?: NodeJS.Timeout; + }; + // Getting the icon and text for the toast based on the id passed + const _icon = toaster.icons[meaning]; + const toastContent = document.createElement("li"); // Creating a new 'li' element for the toast + toastContent.className = `toast .${_icon} ${meaning}`; // Setting the classes for the toast + + // Setting the inner HTML for the toast + toastContent.innerHTML = `
${text}
`; + + // attaching a click event listener to the toast to remove it when the close icon is clicked + const i = document.createElement("i"); + i.className = "fa-solid fa-xmark"; + i.onclick = () => removeToast(toastContent, toastDetails.timeoutId); + toastContent.appendChild(i); + + notifications.appendChild(toastContent); // Append the toast to the notification ul + + // Setting a timeout to remove the toast after the specified duration + toastDetails.timeoutId = setTimeout(() => removeToast(toastContent, toastDetails.timeoutId), toastDetails.timer); +} + +function removeToast(toast: HTMLElement, timeoutId?: NodeJS.Timeout) { + toast.classList.add("hide"); + if (timeoutId) { + clearTimeout(timeoutId); // Clearing the timeout for the toast + } + setTimeout(() => toast.remove(), 500); // Removing the toast after 500ms +} + +export function loadingClaimButton(triggerLoader = true) { + claimButton.element.disabled = true; + // Adding this because not all disabling should trigger loading spinner + if (triggerLoader) { + claimButton.element.classList.add("show-cl"); + claimButton.element.classList.remove("hide-cl"); + } +} + +export function resetClaimButton() { + claimButton.element.disabled = false; + claimButton.element.classList.add("hide-cl"); + claimButton.element.classList.remove("show-cl"); +} + +export function hideClaimButton() { + claimButton.element.disabled = true; + claimButton.element.classList.add("hide-cl"); + claimButton.element.classList.remove("show-cl"); +} + +type Err = { stack?: unknown; reason?: string } extends Error ? Error : { stack?: unknown; reason?: string }; + +export function errorToast(error: Err, errorMessage?: string) { + delete error.stack; + const errorData = JSON.stringify(error, null, 2); + if (errorMessage) { + toaster.create("error", errorMessage); + } else if (error?.reason) { + // parse error data to get error message + const parsedError = JSON.parse(errorData); + const _errorMessage = parsedError?.error?.message ?? parsedError?.reason; + toaster.create("error", _errorMessage); + } +} diff --git a/static/scripts/rewards/web3/erc20-permit.ts b/static/scripts/rewards/web3/erc20-permit.ts new file mode 100644 index 0000000..fd26d9f --- /dev/null +++ b/static/scripts/rewards/web3/erc20-permit.ts @@ -0,0 +1,183 @@ +import { BigNumber, BigNumberish, ethers } from "ethers"; +import { permit2Abi } from "../abis"; +import { permit2Address } from "../constants"; +import { getErc20Contract, getOptimalProvider } from "../helpers"; +import { Erc20Permit } from "../render-transaction/tx-type"; +import { toaster, resetClaimButton, errorToast, loadingClaimButton, claimButton } from "../toaster"; +import { renderTransaction } from "../render-transaction/render-transaction"; +import { connectWallet } from "./wallet"; +import invalidateButton from "../invalidate-component"; +import { JsonRpcProvider } from "@ethersproject/providers"; +import { tokens } from "../render-transaction/render-token-symbol"; +import { insertErc20PermitTableData } from "../render-transaction/insert-table-data"; + +export async function processERC20(tokenAddress: string, provider: JsonRpcProvider, permit: Erc20Permit, table: Element) { + let symbol = tokenAddress === tokens[0].address ? tokens[0].name : tokenAddress === tokens[1].address ? tokens[1].name : ""; + let decimals = tokenAddress === tokens[0].address ? 18 : tokenAddress === tokens[1].address ? 18 : -1; + + if (!symbol || decimals === -1) { + try { + const contract = await getErc20Contract(tokenAddress, provider); + symbol = contract.symbol(); + decimals = contract.decimals(); + } catch (err) { + throw new Error(`Error fetching symbol and decimals for token address: ${tokenAddress}`); + } + } + + await insertErc20PermitTableData(permit, provider, symbol, decimals, table); +} + +export async function fetchTreasury(contractAddr: string, owner: string, provider: JsonRpcProvider) { + try { + const contract = await getErc20Contract(contractAddr, provider); + const [balance, allowance] = await Promise.all([contract.balanceOf(owner), contract.allowance(owner, permit2Address)]); + return { balance, allowance } as { balance: BigNumber; allowance: BigNumber }; + } catch (err) { + console.log(err); + } + + return { balance: BigNumber.from(0), allowance: BigNumber.from(0) }; +} + +export function claimErc20PermitHandler(permit: Erc20Permit, provider: JsonRpcProvider) { + return async function handler() { + try { + const signer = await connectWallet(); + if (!signer) { + return; + } + + if (!(await checkPermitClaimable(permit, signer, provider))) { + return; + } + + loadingClaimButton(); + const permit2Contract = new ethers.Contract(permit2Address, permit2Abi, signer); + const tx = await permit2Contract.permitTransferFrom(permit.permit, permit.transferDetails, permit.owner, permit.signature); + toaster.create("info", `Transaction sent`); + const receipt = await tx.wait(); + toaster.create("success", `Claim Complete.`); + console.log(receipt.transactionHash); // @TODO: post to database + + claimButton.element.removeEventListener("click", handler); + renderTransaction(provider).catch(console.error); + } catch (error: unknown) { + if (error instanceof Error) { + console.log(error); + errorToast(error, error.message); + resetClaimButton(); + } + } + }; +} + +export async function checkPermitClaimable(permit: Erc20Permit, signer: ethers.providers.JsonRpcSigner | null, provider: JsonRpcProvider) { + const isClaimed = await isNonceClaimed(permit); + if (isClaimed) { + toaster.create("error", `Your reward for this task has already been claimed or invalidated.`); + return false; + } + + if (permit.permit.deadline.lt(Math.floor(Date.now() / 1000))) { + toaster.create("error", `This reward has expired.`); + return false; + } + + const { balance, allowance } = await fetchTreasury(permit.permit.permitted.token, permit.owner, provider); + const permitted = BigNumber.from(permit.permit.permitted.amount); + const isSolvent = balance.gte(permitted); + const isAllowed = allowance.gte(permitted); + + if (!isSolvent) { + toaster.create("error", `Not enough funds on funding wallet to collect this reward. Please let the financier know.`); + return false; + } + if (!isAllowed) { + toaster.create("error", `Not enough allowance on the funding wallet to collect this reward. Please let the financier know.`); + return false; + } + + if (signer) { + const user = (await signer.getAddress()).toLowerCase(); + 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) { + return; + } + + const user = (await signer.getAddress()).toLowerCase(); + const owner = permit.owner.toLowerCase(); + if (owner !== user) { + return; + } + + const controls = document.getElementById("controls") as HTMLDivElement; + controls.appendChild(invalidateButton); + + invalidateButton.addEventListener("click", async function invalidateButtonClickHandler() { + try { + const signer = await connectWallet(); + if (!signer) { + return; + } + const isClaimed = await isNonceClaimed(permit); + if (isClaimed) { + toaster.create("error", `This reward has already been claimed or invalidated.`); + return; + } + await invalidateNonce(signer, permit.permit.nonce); + } catch (error: unknown) { + if (error instanceof Error) { + console.log(error); + errorToast(error, error.message); + return; + } + } + toaster.create("info", "Nonce invalidation transaction sent"); + }); +} + +//mimics https://github.com/Uniswap/permit2/blob/a7cd186948b44f9096a35035226d7d70b9e24eaf/src/SignatureTransfer.sol#L150 +export async function isNonceClaimed(permit: Erc20Permit): Promise { + const provider = await getOptimalProvider(permit.networkId); + + const permit2Contract = new ethers.Contract(permit2Address, permit2Abi, provider); + + const { wordPos, bitPos } = nonceBitmap(BigNumber.from(permit.permit.nonce)); + const bitmap = await permit2Contract.nonceBitmap(permit.owner, wordPos); + + const bit = BigNumber.from(1).shl(bitPos); + const flipped = BigNumber.from(bitmap).xor(bit); + + return bit.and(flipped).eq(0); +} + +export async function invalidateNonce(signer: ethers.providers.JsonRpcSigner, nonce: BigNumberish): Promise { + const permit2Contract = new ethers.Contract(permit2Address, permit2Abi, signer); + const { wordPos, bitPos } = nonceBitmap(nonce); + // mimics https://github.com/ubiquity/pay.ubq.fi/blob/c9e7ed90718fe977fd9f348db27adf31d91d07fb/scripts/solidity/test/Permit2.t.sol#L428 + const bit = BigNumber.from(1).shl(bitPos); + const sourceBitmap = await permit2Contract.nonceBitmap(await signer.getAddress(), wordPos.toString()); + const mask = sourceBitmap.or(bit); + await permit2Contract.invalidateUnorderedNonces(wordPos, mask); +} + +// mimics https://github.com/Uniswap/permit2/blob/db96e06278b78123970183d28f502217bef156f4/src/SignatureTransfer.sol#L142 +export function nonceBitmap(nonce: BigNumberish): { wordPos: BigNumber; bitPos: number } { + // wordPos is the first 248 bits of the nonce + const wordPos = BigNumber.from(nonce).shr(8); + // bitPos is the last 8 bits of the nonce + const bitPos = BigNumber.from(nonce).and(255).toNumber(); + return { wordPos, bitPos }; +} diff --git a/static/scripts/rewards/web3/erc721-permit.ts b/static/scripts/rewards/web3/erc721-permit.ts new file mode 100644 index 0000000..0dafff6 --- /dev/null +++ b/static/scripts/rewards/web3/erc721-permit.ts @@ -0,0 +1,64 @@ +import { JsonRpcProvider, TransactionResponse } from "@ethersproject/providers"; +import { ethers } from "ethers"; +import { nftRewardAbi } from "../abis/nftRewardAbi"; +import { renderTransaction } from "../render-transaction/render-transaction"; +import { Erc721Permit } from "../render-transaction/tx-type"; +import { claimButton, errorToast, loadingClaimButton, resetClaimButton, toaster } from "../toaster"; +import { connectWallet } from "./wallet"; + +export function claimErc721PermitHandler(permit: Erc721Permit, provider: JsonRpcProvider) { + return async function claimButtonHandler() { + const signer = await connectWallet(); + if (!signer) { + return; + } + + if ((await signer.getAddress()).toLowerCase() !== permit.request.beneficiary) { + toaster.create("warning", `This NFT is not for you.`); + resetClaimButton(); + return; + } + + if (permit.request.deadline.lt(Math.floor(Date.now() / 1000))) { + toaster.create("error", `This NFT has expired.`); + resetClaimButton(); + return; + } + + const isRedeemed = await isNonceRedeemed(permit, provider); + if (isRedeemed) { + toaster.create("error", `This NFT has already been redeemed.`); + resetClaimButton(); + return; + } + + loadingClaimButton(); + try { + const nftContract = new ethers.Contract(permit.nftAddress, nftRewardAbi, signer); + + const tx: TransactionResponse = await nftContract.safeMint(permit.request, permit.signature); + toaster.create("info", `Transaction sent. Waiting for confirmation...`); + const receipt = await tx.wait(); + toaster.create("success", `Claim Complete.`); + console.log(receipt.transactionHash); // @TODO: post to database + + claimButton.element.removeEventListener("click", claimButtonHandler); + + renderTransaction(provider, true).catch((error) => { + console.error(error); + toaster.create("error", `Error rendering transaction: ${error.message}`); + }); + } catch (error: unknown) { + if (error instanceof Error) { + console.error(error); + errorToast(error, error.message ?? error); + resetClaimButton(); + } + } + }; +} + +export async function isNonceRedeemed(nftMint: Erc721Permit, provider: JsonRpcProvider): Promise { + const nftContract = new ethers.Contract(nftMint.nftAddress, nftRewardAbi, provider); + return nftContract.nonceRedeemed(nftMint.request.nonce); +} diff --git a/static/scripts/rewards/web3/wallet.ts b/static/scripts/rewards/web3/wallet.ts new file mode 100644 index 0000000..34766b8 --- /dev/null +++ b/static/scripts/rewards/web3/wallet.ts @@ -0,0 +1,103 @@ +import { JsonRpcSigner } from "@ethersproject/providers"; +import { ethers } from "ethers"; +import { getNetworkName, networkCurrencies, networkExplorers, networkRpcs } from "../constants"; +import invalidateButton from "../invalidate-component"; +import { claimButton, loadingClaimButton, resetClaimButton, toaster } from "../toaster"; + +export async function connectWallet(): Promise { + try { + const provider = new ethers.providers.Web3Provider(window.ethereum, "any"); + await provider.send("eth_requestAccounts", []); + const signer = provider.getSigner(); + resetClaimButton(); + return signer; + } catch (error: unknown) { + if (error instanceof Error) { + if (error?.message?.includes("missing provider")) { + toaster.create("info", "Please use a web3 enabled browser to collect this reward."); + claimButton.element.disabled = true; + } else { + toaster.create("info", "Please connect your wallet to collect this reward."); + claimButton.element.disabled = true; + } + } + return null; + } +} + +export async function handleNetwork(desiredNetworkId: number) { + const web3provider = new ethers.providers.Web3Provider(window.ethereum); + if (!web3provider || !web3provider.provider.isMetaMask) { + toaster.create("info", "Please connect to MetaMask."); + loadingClaimButton(false); + invalidateButton.disabled = true; + } + + const currentNetworkId = (await web3provider.getNetwork()).chainId; + + // watch for network changes + window.ethereum.on("chainChanged", (newNetworkId: T | string) => handleIfOnCorrectNetwork(parseInt(newNetworkId as string, 16), desiredNetworkId)); + + // if its not on ethereum mainnet, gnosis, or goerli, display error + notOnCorrectNetwork(currentNetworkId, desiredNetworkId, web3provider); +} + +function notOnCorrectNetwork(currentNetworkId: number, desiredNetworkId: number, web3provider: ethers.providers.Web3Provider) { + if (currentNetworkId !== desiredNetworkId) { + if (desiredNetworkId == void 0) { + console.error(`You must pass in an EVM network ID in the URL query parameters using the key 'network' e.g. '?network=1'`); + } + const networkName = getNetworkName(desiredNetworkId); + if (!networkName) { + toaster.create("error", `This dApp currently does not support payouts for network ID ${desiredNetworkId}`); + } + loadingClaimButton(false); + invalidateButton.disabled = true; + switchNetwork(web3provider, desiredNetworkId).catch((error) => { + console.error(error); + toaster.create("error", `Please switch to the ${networkName} network to claim this reward.`); + }); + } +} + +function handleIfOnCorrectNetwork(currentNetworkId: number, desiredNetworkId: number) { + if (desiredNetworkId === currentNetworkId) { + // enable the button once on the correct network + resetClaimButton(); + invalidateButton.disabled = false; + } else { + loadingClaimButton(false); + invalidateButton.disabled = true; + } +} + +export async function switchNetwork(provider: ethers.providers.Web3Provider, networkId: number): Promise { + try { + await provider.send("wallet_switchEthereumChain", [{ chainId: "0x" + networkId.toString(16) }]); + return true; + } catch (error: unknown) { + // Add network if it doesn't exist. + const code = (error as { code: number }).code; + if (code == 4902) { + return await addNetwork(provider, networkId); + } + return false; + } +} + +export async function addNetwork(provider: ethers.providers.Web3Provider, networkId: number): Promise { + try { + await provider.send("wallet_addEthereumChain", [ + { + chainId: "0x" + networkId.toString(16), + chainName: getNetworkName(networkId), + rpcUrls: networkRpcs[networkId], + blockExplorerUrls: [networkExplorers[networkId]], + nativeCurrency: networkCurrencies[networkId], + }, + ]); + return true; + } catch (error: unknown) { + return false; + } +} diff --git a/static/styles/audit-report/audit.css b/static/styles/audit-report/audit.css new file mode 100644 index 0000000..ef039e1 --- /dev/null +++ b/static/styles/audit-report/audit.css @@ -0,0 +1,185 @@ +@import url("../rewards/pay.css"); +@import url("../proxima.css"); +@import url("checkbox.css"); +@import url("toggle.css"); +@import url("../fa.css"); + +body { + margin: 0; + padding: 0; +} + +input, +textarea { + all: unset; + outline: 0; + border-radius: 5px; + width: 90vw; + border: 1px solid #d2d2e7; + height: 40px; + padding-left: 10px; + box-sizing: border-box; + text-transform: none; +} + +select { + outline: 0; + border-radius: 5px; + width: 90vw; + border: 1px solid #d2d2e7; + height: 40px; + padding-left: 10px; + box-sizing: border-box; + text-transform: none; +} + +textarea { + height: 140px; + white-space: break-spaces; +} + +input:focus, +textarea:focus { + border-color: #86b7fe; + box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25); +} + +.container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 40px; + padding: 32px 0; +} + +.mb-3 { + display: flex; + flex-direction: column; + gap: 10px; +} + +#getReport { + all: unset; + background: #0d6efd; + border-radius: 6px; + padding: 14px 20px; + color: white; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 5px; + user-select: none; +} + +#getReport:not(:disabled):hover { + background: #0a58ca; +} + +#getReport:disabled { + cursor: default; +} + +.audit-tag { + font-size: 26px; + color: black; + font-weight: 900; +} + +a { + text-transform: none; +} + +a:hover { + color: black; +} + +#searchInput { + margin-bottom: 20px; + width: 100%; +} + +#resultTable { + border-spacing: 0.8em; +} + +.resultContainer tbody:before { + content: "@"; + display: block; + line-height: 10px; + text-indent: -99999px; +} + +.resultContainer { + width: 87vw; + border-spacing: 14px; + border: 1px solid #dfdfdf; + border-radius: 12px; + box-shadow: 0px 0px 6px #0089ff59; + display: flex; + flex-direction: column; + padding: 20px; +} + +td { + text-align: center; +} + +span { + color: white; +} + +.btn-container { + display: flex; + flex-direction: row; + align-self: flex-start; + align-items: center; + justify-content: center; + gap: 24px; +} + +.cache-title { + font-size: 15px; + font-weight: 900; + color: #0072ff; + user-select: none; +} + +.btn-loader { + border: 5px solid #fff; + border-bottom-color: transparent; + border-radius: 50%; + display: inline-block; + box-sizing: border-box; + animation: rotation 1s linear infinite; +} + +@keyframes rotation { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} + +#report-loader { + display: none; +} + +#amountHeader { + position: relative; + cursor: pointer; +} + +#sortArrow { + color: black; + font-size: 16px; + margin-left: 5px; + /* Adjust the spacing between the text and arrows */ + position: absolute; + top: 50%; + transform: translateY(-50%); +} diff --git a/static/styles/audit-report/checkbox.css b/static/styles/audit-report/checkbox.css new file mode 100644 index 0000000..90173bc --- /dev/null +++ b/static/styles/audit-report/checkbox.css @@ -0,0 +1,99 @@ +.tgl { + display: none; +} + +.tg-list-item { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: 8px; +} + +.tgl, +.tgl:after, +.tgl:before, +.tgl *, +.tgl *:after, +.tgl *:before, +.tgl + .tgl-btn { + box-sizing: border-box; +} + +.tgl::-moz-selection, +.tgl:after::-moz-selection, +.tgl:before::-moz-selection, +.tgl *::-moz-selection, +.tgl *:after::-moz-selection, +.tgl *:before::-moz-selection, +.tgl + .tgl-btn::-moz-selection { + background: none; +} + +.tgl::selection, +.tgl:after::selection, +.tgl:before::selection, +.tgl *::selection, +.tgl *:after::selection, +.tgl *:before::selection, +.tgl + .tgl-btn::selection { + background: none; +} + +.tgl + .tgl-btn { + outline: 0; + display: block; + width: 4em; + height: 2em; + position: relative; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.tgl + .tgl-btn:after, +.tgl + .tgl-btn:before { + position: relative; + display: block; + content: ""; + width: 50%; + height: 100%; +} + +.tgl + .tgl-btn:after { + left: 0; +} + +.tgl + .tgl-btn:before { + display: none; +} + +.tgl:checked + .tgl-btn:after { + left: 50%; +} + +.tgl-flat + .tgl-btn { + padding: 2px; + transition: all 0.2s ease; + background: #fff; + border: 4px solid #eaeaeb; + border-radius: 2em; +} + +.tgl-flat + .tgl-btn:after { + transition: all 0.2s ease; + background: #e5e5e5; + content: ""; + border-radius: 1em; +} + +.tgl-flat:checked + .tgl-btn { + border: 4px solid #723ae5; +} + +.tgl-flat:checked + .tgl-btn:after { + left: 50%; + background: #6e67d9; +} diff --git a/static/styles/audit-report/toggle.css b/static/styles/audit-report/toggle.css new file mode 100644 index 0000000..686026b --- /dev/null +++ b/static/styles/audit-report/toggle.css @@ -0,0 +1,132 @@ +:root { + --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; + } +} + +@media screen and (max-width: 1024px) { + html, + body { + font-size: 16px; + } +} + +@media screen and (max-width: 600px) { + html, + body { + font-size: 12px; + } +} + +/* p - decorative, not required */ +p { + 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; +} + +/* input (radio) for toggling. hidden - use labels for clicking on */ +.switches-container input { + 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; +} + +/* 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; */ +} + +/* switch box highlighter */ +.switch { + background: var(--switch-bg-color); + height: 100%; +} + +/* switch box labels + - default setup + - 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; +} + +/* slide the switch box from right to left */ +.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%); +} + +/* 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; +} + +/* 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; +} diff --git a/static/styles/fa.css b/static/styles/fa.css new file mode 100644 index 0000000..4568cf7 --- /dev/null +++ b/static/styles/fa.css @@ -0,0 +1,8798 @@ +/*! + * Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2022 Fonticons, Inc. + */ +.fa { + font-family: var(--fa-style-family, "Font Awesome 6 Free"); + font-weight: var(--fa-style, 900); +} + +.fa, +.fa-brands, +.fa-classic, +.fa-regular, +.fa-sharp, +.fa-solid, +.fab, +.far, +.fas { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: var(--fa-display, inline-block); + font-style: normal; + font-variant: normal; + line-height: 1; + text-rendering: auto; +} + +.fa-classic, +.fa-regular, +.fa-solid, +.far, +.fas { + font-family: "Font Awesome 6 Free"; +} + +.fa-brands, +.fab { + font-family: "Font Awesome 6 Brands"; +} + +.fa-1x { + font-size: 1em; +} + +.fa-2x { + font-size: 2em; +} + +.fa-3x { + font-size: 3em; +} + +.fa-4x { + font-size: 4em; +} + +.fa-5x { + font-size: 5em; +} + +.fa-6x { + font-size: 6em; +} + +.fa-7x { + font-size: 7em; +} + +.fa-8x { + font-size: 8em; +} + +.fa-9x { + font-size: 9em; +} + +.fa-10x { + font-size: 10em; +} + +.fa-2xs { + font-size: 0.625em; + line-height: 0.1em; + vertical-align: 0.225em; +} + +.fa-xs { + font-size: 0.75em; + line-height: 0.08333em; + vertical-align: 0.125em; +} + +.fa-sm { + font-size: 0.875em; + line-height: 0.07143em; + vertical-align: 0.05357em; +} + +.fa-lg { + font-size: 1.25em; + line-height: 0.05em; + vertical-align: -0.075em; +} + +.fa-xl { + font-size: 1.5em; + line-height: 0.04167em; + vertical-align: -0.125em; +} + +.fa-2xl { + font-size: 2em; + line-height: 0.03125em; + vertical-align: -0.1875em; +} + +.fa-fw { + text-align: center; + width: 1.25em; +} + +.fa-ul { + list-style-type: none; + margin-left: var(--fa-li-margin, 2.5em); + padding-left: 0; +} + +.fa-ul > li { + position: relative; +} + +.fa-li { + left: calc(var(--fa-li-width, 2em) * -1); + position: absolute; + text-align: center; + width: var(--fa-li-width, 2em); + line-height: inherit; +} + +.fa-border { + border-radius: var(--fa-border-radius, 0.1em); + border: var(--fa-border-width, 0.08em) var(--fa-border-style, solid) var(--fa-border-color, #eee); + padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); +} + +.fa-pull-left { + float: left; + margin-right: var(--fa-pull-margin, 0.3em); +} + +.fa-pull-right { + float: right; + margin-left: var(--fa-pull-margin, 0.3em); +} + +.fa-beat { + -webkit-animation-name: fa-beat; + animation-name: fa-beat; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); +} + +.fa-bounce { + -webkit-animation-name: fa-bounce; + animation-name: fa-bounce; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); +} + +.fa-fade { + -webkit-animation-name: fa-fade; + animation-name: fa-fade; + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); +} + +.fa-beat-fade, +.fa-fade { + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); +} + +.fa-beat-fade { + -webkit-animation-name: fa-beat-fade; + animation-name: fa-beat-fade; + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); +} + +.fa-flip { + -webkit-animation-name: fa-flip; + animation-name: fa-flip; + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out); + animation-timing-function: var(--fa-animation-timing, ease-in-out); +} + +.fa-shake { + -webkit-animation-name: fa-shake; + animation-name: fa-shake; + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); +} + +.fa-shake, +.fa-spin { + -webkit-animation-delay: var(--fa-animation-delay, 0s); + animation-delay: var(--fa-animation-delay, 0s); + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); +} + +.fa-spin { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-duration: var(--fa-animation-duration, 2s); + animation-duration: var(--fa-animation-duration, 2s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, linear); + animation-timing-function: var(--fa-animation-timing, linear); +} + +.fa-spin-reverse { + --fa-animation-direction: reverse; +} + +.fa-pulse, +.fa-spin-pulse { + -webkit-animation-name: fa-spin; + animation-name: fa-spin; + -webkit-animation-direction: var(--fa-animation-direction, normal); + animation-direction: var(--fa-animation-direction, normal); + -webkit-animation-duration: var(--fa-animation-duration, 1s); + animation-duration: var(--fa-animation-duration, 1s); + -webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + -webkit-animation-timing-function: var(--fa-animation-timing, steps(8)); + animation-timing-function: var(--fa-animation-timing, steps(8)); +} + +@media (prefers-reduced-motion: reduce) { + .fa-beat, + .fa-beat-fade, + .fa-bounce, + .fa-fade, + .fa-flip, + .fa-pulse, + .fa-shake, + .fa-spin, + .fa-spin-pulse { + -webkit-animation-delay: -1ms; + animation-delay: -1ms; + -webkit-animation-duration: 1ms; + animation-duration: 1ms; + -webkit-animation-iteration-count: 1; + animation-iteration-count: 1; + transition-delay: 0s; + transition-duration: 0s; + } +} + +@-webkit-keyframes fa-beat { + 0%, + 90% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); + } +} + +@keyframes fa-beat { + 0%, + 90% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 45% { + -webkit-transform: scale(var(--fa-beat-scale, 1.25)); + transform: scale(var(--fa-beat-scale, 1.25)); + } +} + +@-webkit-keyframes fa-bounce { + 0% { + -webkit-transform: scale(1) translateY(0); + transform: scale(1) translateY(0); + } + + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + } + + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + } + + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + } + + 57% { + -webkit-transform: scale(1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1) translateY(var(--fa-bounce-rebound, -0.125em)); + } + + 64% { + -webkit-transform: scale(1) translateY(0); + transform: scale(1) translateY(0); + } + + to { + -webkit-transform: scale(1) translateY(0); + transform: scale(1) translateY(0); + } +} + +@keyframes fa-bounce { + 0% { + -webkit-transform: scale(1) translateY(0); + transform: scale(1) translateY(0); + } + + 10% { + -webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); + } + + 30% { + -webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); + } + + 50% { + -webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); + } + + 57% { + -webkit-transform: scale(1) translateY(var(--fa-bounce-rebound, -0.125em)); + transform: scale(1) translateY(var(--fa-bounce-rebound, -0.125em)); + } + + 64% { + -webkit-transform: scale(1) translateY(0); + transform: scale(1) translateY(0); + } + + to { + -webkit-transform: scale(1) translateY(0); + transform: scale(1) translateY(0); + } +} + +@-webkit-keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); + } +} + +@keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); + } +} + +@-webkit-keyframes fa-beat-fade { + 0%, + to { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); + } + + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); + } +} + +@keyframes fa-beat-fade { + 0%, + to { + opacity: var(--fa-beat-fade-opacity, 0.4); + -webkit-transform: scale(1); + transform: scale(1); + } + + 50% { + opacity: 1; + -webkit-transform: scale(var(--fa-beat-fade-scale, 1.125)); + transform: scale(var(--fa-beat-fade-scale, 1.125)); + } +} + +@-webkit-keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + } +} + +@keyframes fa-flip { + 50% { + -webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); + } +} + +@-webkit-keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); + } + + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + + 8%, + 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); + } + + 12%, + 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); + } + + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); + } + + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); + } + + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); + } + + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); + } + + 40%, + to { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@keyframes fa-shake { + 0% { + -webkit-transform: rotate(-15deg); + transform: rotate(-15deg); + } + + 4% { + -webkit-transform: rotate(15deg); + transform: rotate(15deg); + } + + 8%, + 24% { + -webkit-transform: rotate(-18deg); + transform: rotate(-18deg); + } + + 12%, + 28% { + -webkit-transform: rotate(18deg); + transform: rotate(18deg); + } + + 16% { + -webkit-transform: rotate(-22deg); + transform: rotate(-22deg); + } + + 20% { + -webkit-transform: rotate(22deg); + transform: rotate(22deg); + } + + 32% { + -webkit-transform: rotate(-12deg); + transform: rotate(-12deg); + } + + 36% { + -webkit-transform: rotate(12deg); + transform: rotate(12deg); + } + + 40%, + to { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(1turn); + transform: rotate(1turn); + } +} + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + + to { + -webkit-transform: rotate(1turn); + transform: rotate(1turn); + } +} + +.fa-rotate-90 { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +.fa-rotate-180 { + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} + +.fa-rotate-270 { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); +} + +.fa-flip-horizontal { + -webkit-transform: scaleX(-1); + transform: scaleX(-1); +} + +.fa-flip-vertical { + -webkit-transform: scaleY(-1); + transform: scaleY(-1); +} + +.fa-flip-both, +.fa-flip-horizontal.fa-flip-vertical { + -webkit-transform: scale(-1); + transform: scale(-1); +} + +.fa-rotate-by { + -webkit-transform: rotate(var(--fa-rotate-angle, none)); + transform: rotate(var(--fa-rotate-angle, none)); +} + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; +} + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; + z-index: var(--fa-stack-z-index, auto); +} + +.fa-stack-1x { + line-height: inherit; +} + +.fa-stack-2x { + font-size: 2em; +} + +.fa-inverse { + color: var(--fa-inverse, #fff); +} + +.fa-0:before { + content: "\30"; +} + +.fa-1:before { + content: "\31"; +} + +.fa-2:before { + content: "\32"; +} + +.fa-3:before { + content: "\33"; +} + +.fa-4:before { + content: "\34"; +} + +.fa-5:before { + content: "\35"; +} + +.fa-6:before { + content: "\36"; +} + +.fa-7:before { + content: "\37"; +} + +.fa-8:before { + content: "\38"; +} + +.fa-9:before { + content: "\39"; +} + +.fa-fill-drip:before { + content: "\f576"; +} + +.fa-arrows-to-circle:before { + content: "\e4bd"; +} + +.fa-chevron-circle-right:before, +.fa-circle-chevron-right:before { + content: "\f138"; +} + +.fa-at:before { + content: "\40"; +} + +.fa-trash-alt:before, +.fa-trash-can:before { + content: "\f2ed"; +} + +.fa-text-height:before { + content: "\f034"; +} + +.fa-user-times:before, +.fa-user-xmark:before { + content: "\f235"; +} + +.fa-stethoscope:before { + content: "\f0f1"; +} + +.fa-comment-alt:before, +.fa-message:before { + content: "\f27a"; +} + +.fa-info:before { + content: "\f129"; +} + +.fa-compress-alt:before, +.fa-down-left-and-up-right-to-center:before { + content: "\f422"; +} + +.fa-explosion:before { + content: "\e4e9"; +} + +.fa-file-alt:before, +.fa-file-lines:before, +.fa-file-text:before { + content: "\f15c"; +} + +.fa-wave-square:before { + content: "\f83e"; +} + +.fa-ring:before { + content: "\f70b"; +} + +.fa-building-un:before { + content: "\e4d9"; +} + +.fa-dice-three:before { + content: "\f527"; +} + +.fa-calendar-alt:before, +.fa-calendar-days:before { + content: "\f073"; +} + +.fa-anchor-circle-check:before { + content: "\e4aa"; +} + +.fa-building-circle-arrow-right:before { + content: "\e4d1"; +} + +.fa-volleyball-ball:before, +.fa-volleyball:before { + content: "\f45f"; +} + +.fa-arrows-up-to-line:before { + content: "\e4c2"; +} + +.fa-sort-desc:before, +.fa-sort-down:before { + content: "\f0dd"; +} + +.fa-circle-minus:before, +.fa-minus-circle:before { + content: "\f056"; +} + +.fa-door-open:before { + content: "\f52b"; +} + +.fa-right-from-bracket:before, +.fa-sign-out-alt:before { + content: "\f2f5"; +} + +.fa-atom:before { + content: "\f5d2"; +} + +.fa-soap:before { + content: "\e06e"; +} + +.fa-heart-music-camera-bolt:before, +.fa-icons:before { + content: "\f86d"; +} + +.fa-microphone-alt-slash:before, +.fa-microphone-lines-slash:before { + content: "\f539"; +} + +.fa-bridge-circle-check:before { + content: "\e4c9"; +} + +.fa-pump-medical:before { + content: "\e06a"; +} + +.fa-fingerprint:before { + content: "\f577"; +} + +.fa-hand-point-right:before { + content: "\f0a4"; +} + +.fa-magnifying-glass-location:before, +.fa-search-location:before { + content: "\f689"; +} + +.fa-forward-step:before, +.fa-step-forward:before { + content: "\f051"; +} + +.fa-face-smile-beam:before, +.fa-smile-beam:before { + content: "\f5b8"; +} + +.fa-flag-checkered:before { + content: "\f11e"; +} + +.fa-football-ball:before, +.fa-football:before { + content: "\f44e"; +} + +.fa-school-circle-exclamation:before { + content: "\e56c"; +} + +.fa-crop:before { + content: "\f125"; +} + +.fa-angle-double-down:before, +.fa-angles-down:before { + content: "\f103"; +} + +.fa-users-rectangle:before { + content: "\e594"; +} + +.fa-people-roof:before { + content: "\e537"; +} + +.fa-people-line:before { + content: "\e534"; +} + +.fa-beer-mug-empty:before, +.fa-beer:before { + content: "\f0fc"; +} + +.fa-diagram-predecessor:before { + content: "\e477"; +} + +.fa-arrow-up-long:before, +.fa-long-arrow-up:before { + content: "\f176"; +} + +.fa-burn:before, +.fa-fire-flame-simple:before { + content: "\f46a"; +} + +.fa-male:before, +.fa-person:before { + content: "\f183"; +} + +.fa-laptop:before { + content: "\f109"; +} + +.fa-file-csv:before { + content: "\f6dd"; +} + +.fa-menorah:before { + content: "\f676"; +} + +.fa-truck-plane:before { + content: "\e58f"; +} + +.fa-record-vinyl:before { + content: "\f8d9"; +} + +.fa-face-grin-stars:before, +.fa-grin-stars:before { + content: "\f587"; +} + +.fa-bong:before { + content: "\f55c"; +} + +.fa-pastafarianism:before, +.fa-spaghetti-monster-flying:before { + content: "\f67b"; +} + +.fa-arrow-down-up-across-line:before { + content: "\e4af"; +} + +.fa-spoon:before, +.fa-utensil-spoon:before { + content: "\f2e5"; +} + +.fa-jar-wheat:before { + content: "\e517"; +} + +.fa-envelopes-bulk:before, +.fa-mail-bulk:before { + content: "\f674"; +} + +.fa-file-circle-exclamation:before { + content: "\e4eb"; +} + +.fa-circle-h:before, +.fa-hospital-symbol:before { + content: "\f47e"; +} + +.fa-pager:before { + content: "\f815"; +} + +.fa-address-book:before, +.fa-contact-book:before { + content: "\f2b9"; +} + +.fa-strikethrough:before { + content: "\f0cc"; +} + +.fa-k:before { + content: "\4b"; +} + +.fa-landmark-flag:before { + content: "\e51c"; +} + +.fa-pencil-alt:before, +.fa-pencil:before { + content: "\f303"; +} + +.fa-backward:before { + content: "\f04a"; +} + +.fa-caret-right:before { + content: "\f0da"; +} + +.fa-comments:before { + content: "\f086"; +} + +.fa-file-clipboard:before, +.fa-paste:before { + content: "\f0ea"; +} + +.fa-code-pull-request:before { + content: "\e13c"; +} + +.fa-clipboard-list:before { + content: "\f46d"; +} + +.fa-truck-loading:before, +.fa-truck-ramp-box:before { + content: "\f4de"; +} + +.fa-user-check:before { + content: "\f4fc"; +} + +.fa-vial-virus:before { + content: "\e597"; +} + +.fa-sheet-plastic:before { + content: "\e571"; +} + +.fa-blog:before { + content: "\f781"; +} + +.fa-user-ninja:before { + content: "\f504"; +} + +.fa-person-arrow-up-from-line:before { + content: "\e539"; +} + +.fa-scroll-torah:before, +.fa-torah:before { + content: "\f6a0"; +} + +.fa-broom-ball:before, +.fa-quidditch-broom-ball:before, +.fa-quidditch:before { + content: "\f458"; +} + +.fa-toggle-off:before { + content: "\f204"; +} + +.fa-archive:before, +.fa-box-archive:before { + content: "\f187"; +} + +.fa-person-drowning:before { + content: "\e545"; +} + +.fa-arrow-down-9-1:before, +.fa-sort-numeric-desc:before, +.fa-sort-numeric-down-alt:before { + content: "\f886"; +} + +.fa-face-grin-tongue-squint:before, +.fa-grin-tongue-squint:before { + content: "\f58a"; +} + +.fa-spray-can:before { + content: "\f5bd"; +} + +.fa-truck-monster:before { + content: "\f63b"; +} + +.fa-w:before { + content: "\57"; +} + +.fa-earth-africa:before, +.fa-globe-africa:before { + content: "\f57c"; +} + +.fa-rainbow:before { + content: "\f75b"; +} + +.fa-circle-notch:before { + content: "\f1ce"; +} + +.fa-tablet-alt:before, +.fa-tablet-screen-button:before { + content: "\f3fa"; +} + +.fa-paw:before { + content: "\f1b0"; +} + +.fa-cloud:before { + content: "\f0c2"; +} + +.fa-trowel-bricks:before { + content: "\e58a"; +} + +.fa-face-flushed:before, +.fa-flushed:before { + content: "\f579"; +} + +.fa-hospital-user:before { + content: "\f80d"; +} + +.fa-tent-arrow-left-right:before { + content: "\e57f"; +} + +.fa-gavel:before, +.fa-legal:before { + content: "\f0e3"; +} + +.fa-binoculars:before { + content: "\f1e5"; +} + +.fa-microphone-slash:before { + content: "\f131"; +} + +.fa-box-tissue:before { + content: "\e05b"; +} + +.fa-motorcycle:before { + content: "\f21c"; +} + +.fa-bell-concierge:before, +.fa-concierge-bell:before { + content: "\f562"; +} + +.fa-pen-ruler:before, +.fa-pencil-ruler:before { + content: "\f5ae"; +} + +.fa-people-arrows-left-right:before, +.fa-people-arrows:before { + content: "\e068"; +} + +.fa-mars-and-venus-burst:before { + content: "\e523"; +} + +.fa-caret-square-right:before, +.fa-square-caret-right:before { + content: "\f152"; +} + +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} + +.fa-sun-plant-wilt:before { + content: "\e57a"; +} + +.fa-toilets-portable:before { + content: "\e584"; +} + +.fa-hockey-puck:before { + content: "\f453"; +} + +.fa-table:before { + content: "\f0ce"; +} + +.fa-magnifying-glass-arrow-right:before { + content: "\e521"; +} + +.fa-digital-tachograph:before, +.fa-tachograph-digital:before { + content: "\f566"; +} + +.fa-users-slash:before { + content: "\e073"; +} + +.fa-clover:before { + content: "\e139"; +} + +.fa-mail-reply:before, +.fa-reply:before { + content: "\f3e5"; +} + +.fa-star-and-crescent:before { + content: "\f699"; +} + +.fa-house-fire:before { + content: "\e50c"; +} + +.fa-minus-square:before, +.fa-square-minus:before { + content: "\f146"; +} + +.fa-helicopter:before { + content: "\f533"; +} + +.fa-compass:before { + content: "\f14e"; +} + +.fa-caret-square-down:before, +.fa-square-caret-down:before { + content: "\f150"; +} + +.fa-file-circle-question:before { + content: "\e4ef"; +} + +.fa-laptop-code:before { + content: "\f5fc"; +} + +.fa-swatchbook:before { + content: "\f5c3"; +} + +.fa-prescription-bottle:before { + content: "\f485"; +} + +.fa-bars:before, +.fa-navicon:before { + content: "\f0c9"; +} + +.fa-people-group:before { + content: "\e533"; +} + +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: "\f253"; +} + +.fa-heart-broken:before, +.fa-heart-crack:before { + content: "\f7a9"; +} + +.fa-external-link-square-alt:before, +.fa-square-up-right:before { + content: "\f360"; +} + +.fa-face-kiss-beam:before, +.fa-kiss-beam:before { + content: "\f597"; +} + +.fa-film:before { + content: "\f008"; +} + +.fa-ruler-horizontal:before { + content: "\f547"; +} + +.fa-people-robbery:before { + content: "\e536"; +} + +.fa-lightbulb:before { + content: "\f0eb"; +} + +.fa-caret-left:before { + content: "\f0d9"; +} + +.fa-circle-exclamation:before, +.fa-exclamation-circle:before { + content: "\f06a"; +} + +.fa-school-circle-xmark:before { + content: "\e56d"; +} + +.fa-arrow-right-from-bracket:before, +.fa-sign-out:before { + content: "\f08b"; +} + +.fa-chevron-circle-down:before, +.fa-circle-chevron-down:before { + content: "\f13a"; +} + +.fa-unlock-alt:before, +.fa-unlock-keyhole:before { + content: "\f13e"; +} + +.fa-cloud-showers-heavy:before { + content: "\f740"; +} + +.fa-headphones-alt:before, +.fa-headphones-simple:before { + content: "\f58f"; +} + +.fa-sitemap:before { + content: "\f0e8"; +} + +.fa-circle-dollar-to-slot:before, +.fa-donate:before { + content: "\f4b9"; +} + +.fa-memory:before { + content: "\f538"; +} + +.fa-road-spikes:before { + content: "\e568"; +} + +.fa-fire-burner:before { + content: "\e4f1"; +} + +.fa-flag:before { + content: "\f024"; +} + +.fa-hanukiah:before { + content: "\f6e6"; +} + +.fa-feather:before { + content: "\f52d"; +} + +.fa-volume-down:before, +.fa-volume-low:before { + content: "\f027"; +} + +.fa-comment-slash:before { + content: "\f4b3"; +} + +.fa-cloud-sun-rain:before { + content: "\f743"; +} + +.fa-compress:before { + content: "\f066"; +} + +.fa-wheat-alt:before, +.fa-wheat-awn:before { + content: "\e2cd"; +} + +.fa-ankh:before { + content: "\f644"; +} + +.fa-hands-holding-child:before { + content: "\e4fa"; +} + +.fa-asterisk:before { + content: "\2a"; +} + +.fa-check-square:before, +.fa-square-check:before { + content: "\f14a"; +} + +.fa-peseta-sign:before { + content: "\e221"; +} + +.fa-header:before, +.fa-heading:before { + content: "\f1dc"; +} + +.fa-ghost:before { + content: "\f6e2"; +} + +.fa-list-squares:before, +.fa-list:before { + content: "\f03a"; +} + +.fa-phone-square-alt:before, +.fa-square-phone-flip:before { + content: "\f87b"; +} + +.fa-cart-plus:before { + content: "\f217"; +} + +.fa-gamepad:before { + content: "\f11b"; +} + +.fa-circle-dot:before, +.fa-dot-circle:before { + content: "\f192"; +} + +.fa-dizzy:before, +.fa-face-dizzy:before { + content: "\f567"; +} + +.fa-egg:before { + content: "\f7fb"; +} + +.fa-house-medical-circle-xmark:before { + content: "\e513"; +} + +.fa-campground:before { + content: "\f6bb"; +} + +.fa-folder-plus:before { + content: "\f65e"; +} + +.fa-futbol-ball:before, +.fa-futbol:before, +.fa-soccer-ball:before { + content: "\f1e3"; +} + +.fa-paint-brush:before, +.fa-paintbrush:before { + content: "\f1fc"; +} + +.fa-lock:before { + content: "\f023"; +} + +.fa-gas-pump:before { + content: "\f52f"; +} + +.fa-hot-tub-person:before, +.fa-hot-tub:before { + content: "\f593"; +} + +.fa-map-location:before, +.fa-map-marked:before { + content: "\f59f"; +} + +.fa-house-flood-water:before { + content: "\e50e"; +} + +.fa-tree:before { + content: "\f1bb"; +} + +.fa-bridge-lock:before { + content: "\e4cc"; +} + +.fa-sack-dollar:before { + content: "\f81d"; +} + +.fa-edit:before, +.fa-pen-to-square:before { + content: "\f044"; +} + +.fa-car-side:before { + content: "\f5e4"; +} + +.fa-share-alt:before, +.fa-share-nodes:before { + content: "\f1e0"; +} + +.fa-heart-circle-minus:before { + content: "\e4ff"; +} + +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: "\f252"; +} + +.fa-microscope:before { + content: "\f610"; +} + +.fa-sink:before { + content: "\e06d"; +} + +.fa-bag-shopping:before, +.fa-shopping-bag:before { + content: "\f290"; +} + +.fa-arrow-down-z-a:before, +.fa-sort-alpha-desc:before, +.fa-sort-alpha-down-alt:before { + content: "\f881"; +} + +.fa-mitten:before { + content: "\f7b5"; +} + +.fa-person-rays:before { + content: "\e54d"; +} + +.fa-users:before { + content: "\f0c0"; +} + +.fa-eye-slash:before { + content: "\f070"; +} + +.fa-flask-vial:before { + content: "\e4f3"; +} + +.fa-hand-paper:before, +.fa-hand:before { + content: "\f256"; +} + +.fa-om:before { + content: "\f679"; +} + +.fa-worm:before { + content: "\e599"; +} + +.fa-house-circle-xmark:before { + content: "\e50b"; +} + +.fa-plug:before { + content: "\f1e6"; +} + +.fa-chevron-up:before { + content: "\f077"; +} + +.fa-hand-spock:before { + content: "\f259"; +} + +.fa-stopwatch:before { + content: "\f2f2"; +} + +.fa-face-kiss:before, +.fa-kiss:before { + content: "\f596"; +} + +.fa-bridge-circle-xmark:before { + content: "\e4cb"; +} + +.fa-face-grin-tongue:before, +.fa-grin-tongue:before { + content: "\f589"; +} + +.fa-chess-bishop:before { + content: "\f43a"; +} + +.fa-face-grin-wink:before, +.fa-grin-wink:before { + content: "\f58c"; +} + +.fa-deaf:before, +.fa-deafness:before, +.fa-ear-deaf:before, +.fa-hard-of-hearing:before { + content: "\f2a4"; +} + +.fa-road-circle-check:before { + content: "\e564"; +} + +.fa-dice-five:before { + content: "\f523"; +} + +.fa-rss-square:before, +.fa-square-rss:before { + content: "\f143"; +} + +.fa-land-mine-on:before { + content: "\e51b"; +} + +.fa-i-cursor:before { + content: "\f246"; +} + +.fa-stamp:before { + content: "\f5bf"; +} + +.fa-stairs:before { + content: "\e289"; +} + +.fa-i:before { + content: "\49"; +} + +.fa-hryvnia-sign:before, +.fa-hryvnia:before { + content: "\f6f2"; +} + +.fa-pills:before { + content: "\f484"; +} + +.fa-face-grin-wide:before, +.fa-grin-alt:before { + content: "\f581"; +} + +.fa-tooth:before { + content: "\f5c9"; +} + +.fa-v:before { + content: "\56"; +} + +.fa-bangladeshi-taka-sign:before { + content: "\e2e6"; +} + +.fa-bicycle:before { + content: "\f206"; +} + +.fa-rod-asclepius:before, +.fa-rod-snake:before, +.fa-staff-aesculapius:before, +.fa-staff-snake:before { + content: "\e579"; +} + +.fa-head-side-cough-slash:before { + content: "\e062"; +} + +.fa-ambulance:before, +.fa-truck-medical:before { + content: "\f0f9"; +} + +.fa-wheat-awn-circle-exclamation:before { + content: "\e598"; +} + +.fa-snowman:before { + content: "\f7d0"; +} + +.fa-mortar-pestle:before { + content: "\f5a7"; +} + +.fa-road-barrier:before { + content: "\e562"; +} + +.fa-school:before { + content: "\f549"; +} + +.fa-igloo:before { + content: "\f7ae"; +} + +.fa-joint:before { + content: "\f595"; +} + +.fa-angle-right:before { + content: "\f105"; +} + +.fa-horse:before { + content: "\f6f0"; +} + +.fa-q:before { + content: "\51"; +} + +.fa-g:before { + content: "\47"; +} + +.fa-notes-medical:before { + content: "\f481"; +} + +.fa-temperature-2:before, +.fa-temperature-half:before, +.fa-thermometer-2:before, +.fa-thermometer-half:before { + content: "\f2c9"; +} + +.fa-dong-sign:before { + content: "\e169"; +} + +.fa-capsules:before { + content: "\f46b"; +} + +.fa-poo-bolt:before, +.fa-poo-storm:before { + content: "\f75a"; +} + +.fa-face-frown-open:before, +.fa-frown-open:before { + content: "\f57a"; +} + +.fa-hand-point-up:before { + content: "\f0a6"; +} + +.fa-money-bill:before { + content: "\f0d6"; +} + +.fa-bookmark:before { + content: "\f02e"; +} + +.fa-align-justify:before { + content: "\f039"; +} + +.fa-umbrella-beach:before { + content: "\f5ca"; +} + +.fa-helmet-un:before { + content: "\e503"; +} + +.fa-bullseye:before { + content: "\f140"; +} + +.fa-bacon:before { + content: "\f7e5"; +} + +.fa-hand-point-down:before { + content: "\f0a7"; +} + +.fa-arrow-up-from-bracket:before { + content: "\e09a"; +} + +.fa-folder-blank:before, +.fa-folder:before { + content: "\f07b"; +} + +.fa-file-medical-alt:before, +.fa-file-waveform:before { + content: "\f478"; +} + +.fa-radiation:before { + content: "\f7b9"; +} + +.fa-chart-simple:before { + content: "\e473"; +} + +.fa-mars-stroke:before { + content: "\f229"; +} + +.fa-vial:before { + content: "\f492"; +} + +.fa-dashboard:before, +.fa-gauge-med:before, +.fa-gauge:before, +.fa-tachometer-alt-average:before { + content: "\f624"; +} + +.fa-magic-wand-sparkles:before, +.fa-wand-magic-sparkles:before { + content: "\e2ca"; +} + +.fa-e:before { + content: "\45"; +} + +.fa-pen-alt:before, +.fa-pen-clip:before { + content: "\f305"; +} + +.fa-bridge-circle-exclamation:before { + content: "\e4ca"; +} + +.fa-user:before { + content: "\f007"; +} + +.fa-school-circle-check:before { + content: "\e56b"; +} + +.fa-dumpster:before { + content: "\f793"; +} + +.fa-shuttle-van:before, +.fa-van-shuttle:before { + content: "\f5b6"; +} + +.fa-building-user:before { + content: "\e4da"; +} + +.fa-caret-square-left:before, +.fa-square-caret-left:before { + content: "\f191"; +} + +.fa-highlighter:before { + content: "\f591"; +} + +.fa-key:before { + content: "\f084"; +} + +.fa-bullhorn:before { + content: "\f0a1"; +} + +.fa-globe:before { + content: "\f0ac"; +} + +.fa-synagogue:before { + content: "\f69b"; +} + +.fa-person-half-dress:before { + content: "\e548"; +} + +.fa-road-bridge:before { + content: "\e563"; +} + +.fa-location-arrow:before { + content: "\f124"; +} + +.fa-c:before { + content: "\43"; +} + +.fa-tablet-button:before { + content: "\f10a"; +} + +.fa-building-lock:before { + content: "\e4d6"; +} + +.fa-pizza-slice:before { + content: "\f818"; +} + +.fa-money-bill-wave:before { + content: "\f53a"; +} + +.fa-area-chart:before, +.fa-chart-area:before { + content: "\f1fe"; +} + +.fa-house-flag:before { + content: "\e50d"; +} + +.fa-person-circle-minus:before { + content: "\e540"; +} + +.fa-ban:before, +.fa-cancel:before { + content: "\f05e"; +} + +.fa-camera-rotate:before { + content: "\e0d8"; +} + +.fa-air-freshener:before, +.fa-spray-can-sparkles:before { + content: "\f5d0"; +} + +.fa-star:before { + content: "\f005"; +} + +.fa-repeat:before { + content: "\f363"; +} + +.fa-cross:before { + content: "\f654"; +} + +.fa-box:before { + content: "\f466"; +} + +.fa-venus-mars:before { + content: "\f228"; +} + +.fa-arrow-pointer:before, +.fa-mouse-pointer:before { + content: "\f245"; +} + +.fa-expand-arrows-alt:before, +.fa-maximize:before { + content: "\f31e"; +} + +.fa-charging-station:before { + content: "\f5e7"; +} + +.fa-shapes:before, +.fa-triangle-circle-square:before { + content: "\f61f"; +} + +.fa-random:before, +.fa-shuffle:before { + content: "\f074"; +} + +.fa-person-running:before, +.fa-running:before { + content: "\f70c"; +} + +.fa-mobile-retro:before { + content: "\e527"; +} + +.fa-grip-lines-vertical:before { + content: "\f7a5"; +} + +.fa-spider:before { + content: "\f717"; +} + +.fa-hands-bound:before { + content: "\e4f9"; +} + +.fa-file-invoice-dollar:before { + content: "\f571"; +} + +.fa-plane-circle-exclamation:before { + content: "\e556"; +} + +.fa-x-ray:before { + content: "\f497"; +} + +.fa-spell-check:before { + content: "\f891"; +} + +.fa-slash:before { + content: "\f715"; +} + +.fa-computer-mouse:before, +.fa-mouse:before { + content: "\f8cc"; +} + +.fa-arrow-right-to-bracket:before, +.fa-sign-in:before { + content: "\f090"; +} + +.fa-shop-slash:before, +.fa-store-alt-slash:before { + content: "\e070"; +} + +.fa-server:before { + content: "\f233"; +} + +.fa-virus-covid-slash:before { + content: "\e4a9"; +} + +.fa-shop-lock:before { + content: "\e4a5"; +} + +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: "\f251"; +} + +.fa-blender-phone:before { + content: "\f6b6"; +} + +.fa-building-wheat:before { + content: "\e4db"; +} + +.fa-person-breastfeeding:before { + content: "\e53a"; +} + +.fa-right-to-bracket:before, +.fa-sign-in-alt:before { + content: "\f2f6"; +} + +.fa-venus:before { + content: "\f221"; +} + +.fa-passport:before { + content: "\f5ab"; +} + +.fa-heart-pulse:before, +.fa-heartbeat:before { + content: "\f21e"; +} + +.fa-people-carry-box:before, +.fa-people-carry:before { + content: "\f4ce"; +} + +.fa-temperature-high:before { + content: "\f769"; +} + +.fa-microchip:before { + content: "\f2db"; +} + +.fa-crown:before { + content: "\f521"; +} + +.fa-weight-hanging:before { + content: "\f5cd"; +} + +.fa-xmarks-lines:before { + content: "\e59a"; +} + +.fa-file-prescription:before { + content: "\f572"; +} + +.fa-weight-scale:before, +.fa-weight:before { + content: "\f496"; +} + +.fa-user-friends:before, +.fa-user-group:before { + content: "\f500"; +} + +.fa-arrow-up-a-z:before, +.fa-sort-alpha-up:before { + content: "\f15e"; +} + +.fa-chess-knight:before { + content: "\f441"; +} + +.fa-face-laugh-squint:before, +.fa-laugh-squint:before { + content: "\f59b"; +} + +.fa-wheelchair:before { + content: "\f193"; +} + +.fa-arrow-circle-up:before, +.fa-circle-arrow-up:before { + content: "\f0aa"; +} + +.fa-toggle-on:before { + content: "\f205"; +} + +.fa-person-walking:before, +.fa-walking:before { + content: "\f554"; +} + +.fa-l:before { + content: "\4c"; +} + +.fa-fire:before { + content: "\f06d"; +} + +.fa-bed-pulse:before, +.fa-procedures:before { + content: "\f487"; +} + +.fa-shuttle-space:before, +.fa-space-shuttle:before { + content: "\f197"; +} + +.fa-face-laugh:before, +.fa-laugh:before { + content: "\f599"; +} + +.fa-folder-open:before { + content: "\f07c"; +} + +.fa-heart-circle-plus:before { + content: "\e500"; +} + +.fa-code-fork:before { + content: "\e13b"; +} + +.fa-city:before { + content: "\f64f"; +} + +.fa-microphone-alt:before, +.fa-microphone-lines:before { + content: "\f3c9"; +} + +.fa-pepper-hot:before { + content: "\f816"; +} + +.fa-unlock:before { + content: "\f09c"; +} + +.fa-colon-sign:before { + content: "\e140"; +} + +.fa-headset:before { + content: "\f590"; +} + +.fa-store-slash:before { + content: "\e071"; +} + +.fa-road-circle-xmark:before { + content: "\e566"; +} + +.fa-user-minus:before { + content: "\f503"; +} + +.fa-mars-stroke-up:before, +.fa-mars-stroke-v:before { + content: "\f22a"; +} + +.fa-champagne-glasses:before, +.fa-glass-cheers:before { + content: "\f79f"; +} + +.fa-clipboard:before { + content: "\f328"; +} + +.fa-house-circle-exclamation:before { + content: "\e50a"; +} + +.fa-file-arrow-up:before, +.fa-file-upload:before { + content: "\f574"; +} + +.fa-wifi-3:before, +.fa-wifi-strong:before, +.fa-wifi:before { + content: "\f1eb"; +} + +.fa-bath:before, +.fa-bathtub:before { + content: "\f2cd"; +} + +.fa-underline:before { + content: "\f0cd"; +} + +.fa-user-edit:before, +.fa-user-pen:before { + content: "\f4ff"; +} + +.fa-signature:before { + content: "\f5b7"; +} + +.fa-stroopwafel:before { + content: "\f551"; +} + +.fa-bold:before { + content: "\f032"; +} + +.fa-anchor-lock:before { + content: "\e4ad"; +} + +.fa-building-ngo:before { + content: "\e4d7"; +} + +.fa-manat-sign:before { + content: "\e1d5"; +} + +.fa-not-equal:before { + content: "\f53e"; +} + +.fa-border-style:before, +.fa-border-top-left:before { + content: "\f853"; +} + +.fa-map-location-dot:before, +.fa-map-marked-alt:before { + content: "\f5a0"; +} + +.fa-jedi:before { + content: "\f669"; +} + +.fa-poll:before, +.fa-square-poll-vertical:before { + content: "\f681"; +} + +.fa-mug-hot:before { + content: "\f7b6"; +} + +.fa-battery-car:before, +.fa-car-battery:before { + content: "\f5df"; +} + +.fa-gift:before { + content: "\f06b"; +} + +.fa-dice-two:before { + content: "\f528"; +} + +.fa-chess-queen:before { + content: "\f445"; +} + +.fa-glasses:before { + content: "\f530"; +} + +.fa-chess-board:before { + content: "\f43c"; +} + +.fa-building-circle-check:before { + content: "\e4d2"; +} + +.fa-person-chalkboard:before { + content: "\e53d"; +} + +.fa-mars-stroke-h:before, +.fa-mars-stroke-right:before { + content: "\f22b"; +} + +.fa-hand-back-fist:before, +.fa-hand-rock:before { + content: "\f255"; +} + +.fa-caret-square-up:before, +.fa-square-caret-up:before { + content: "\f151"; +} + +.fa-cloud-showers-water:before { + content: "\e4e4"; +} + +.fa-bar-chart:before, +.fa-chart-bar:before { + content: "\f080"; +} + +.fa-hands-bubbles:before, +.fa-hands-wash:before { + content: "\e05e"; +} + +.fa-less-than-equal:before { + content: "\f537"; +} + +.fa-train:before { + content: "\f238"; +} + +.fa-eye-low-vision:before, +.fa-low-vision:before { + content: "\f2a8"; +} + +.fa-crow:before { + content: "\f520"; +} + +.fa-sailboat:before { + content: "\e445"; +} + +.fa-window-restore:before { + content: "\f2d2"; +} + +.fa-plus-square:before, +.fa-square-plus:before { + content: "\f0fe"; +} + +.fa-torii-gate:before { + content: "\f6a1"; +} + +.fa-frog:before { + content: "\f52e"; +} + +.fa-bucket:before { + content: "\e4cf"; +} + +.fa-image:before { + content: "\f03e"; +} + +.fa-microphone:before { + content: "\f130"; +} + +.fa-cow:before { + content: "\f6c8"; +} + +.fa-caret-up:before { + content: "\f0d8"; +} + +.fa-screwdriver:before { + content: "\f54a"; +} + +.fa-folder-closed:before { + content: "\e185"; +} + +.fa-house-tsunami:before { + content: "\e515"; +} + +.fa-square-nfi:before { + content: "\e576"; +} + +.fa-arrow-up-from-ground-water:before { + content: "\e4b5"; +} + +.fa-glass-martini-alt:before, +.fa-martini-glass:before { + content: "\f57b"; +} + +.fa-rotate-back:before, +.fa-rotate-backward:before, +.fa-rotate-left:before, +.fa-undo-alt:before { + content: "\f2ea"; +} + +.fa-columns:before, +.fa-table-columns:before { + content: "\f0db"; +} + +.fa-lemon:before { + content: "\f094"; +} + +.fa-head-side-mask:before { + content: "\e063"; +} + +.fa-handshake:before { + content: "\f2b5"; +} + +.fa-gem:before { + content: "\f3a5"; +} + +.fa-dolly-box:before, +.fa-dolly:before { + content: "\f472"; +} + +.fa-smoking:before { + content: "\f48d"; +} + +.fa-compress-arrows-alt:before, +.fa-minimize:before { + content: "\f78c"; +} + +.fa-monument:before { + content: "\f5a6"; +} + +.fa-snowplow:before { + content: "\f7d2"; +} + +.fa-angle-double-right:before, +.fa-angles-right:before { + content: "\f101"; +} + +.fa-cannabis:before { + content: "\f55f"; +} + +.fa-circle-play:before, +.fa-play-circle:before { + content: "\f144"; +} + +.fa-tablets:before { + content: "\f490"; +} + +.fa-ethernet:before { + content: "\f796"; +} + +.fa-eur:before, +.fa-euro-sign:before, +.fa-euro:before { + content: "\f153"; +} + +.fa-chair:before { + content: "\f6c0"; +} + +.fa-check-circle:before, +.fa-circle-check:before { + content: "\f058"; +} + +.fa-circle-stop:before, +.fa-stop-circle:before { + content: "\f28d"; +} + +.fa-compass-drafting:before, +.fa-drafting-compass:before { + content: "\f568"; +} + +.fa-plate-wheat:before { + content: "\e55a"; +} + +.fa-icicles:before { + content: "\f7ad"; +} + +.fa-person-shelter:before { + content: "\e54f"; +} + +.fa-neuter:before { + content: "\f22c"; +} + +.fa-id-badge:before { + content: "\f2c1"; +} + +.fa-marker:before { + content: "\f5a1"; +} + +.fa-face-laugh-beam:before, +.fa-laugh-beam:before { + content: "\f59a"; +} + +.fa-helicopter-symbol:before { + content: "\e502"; +} + +.fa-universal-access:before { + content: "\f29a"; +} + +.fa-chevron-circle-up:before, +.fa-circle-chevron-up:before { + content: "\f139"; +} + +.fa-lari-sign:before { + content: "\e1c8"; +} + +.fa-volcano:before { + content: "\f770"; +} + +.fa-person-walking-dashed-line-arrow-right:before { + content: "\e553"; +} + +.fa-gbp:before, +.fa-pound-sign:before, +.fa-sterling-sign:before { + content: "\f154"; +} + +.fa-viruses:before { + content: "\e076"; +} + +.fa-square-person-confined:before { + content: "\e577"; +} + +.fa-user-tie:before { + content: "\f508"; +} + +.fa-arrow-down-long:before, +.fa-long-arrow-down:before { + content: "\f175"; +} + +.fa-tent-arrow-down-to-line:before { + content: "\e57e"; +} + +.fa-certificate:before { + content: "\f0a3"; +} + +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} + +.fa-suitcase:before { + content: "\f0f2"; +} + +.fa-person-skating:before, +.fa-skating:before { + content: "\f7c5"; +} + +.fa-filter-circle-dollar:before, +.fa-funnel-dollar:before { + content: "\f662"; +} + +.fa-camera-retro:before { + content: "\f083"; +} + +.fa-arrow-circle-down:before, +.fa-circle-arrow-down:before { + content: "\f0ab"; +} + +.fa-arrow-right-to-file:before, +.fa-file-import:before { + content: "\f56f"; +} + +.fa-external-link-square:before, +.fa-square-arrow-up-right:before { + content: "\f14c"; +} + +.fa-box-open:before { + content: "\f49e"; +} + +.fa-scroll:before { + content: "\f70e"; +} + +.fa-spa:before { + content: "\f5bb"; +} + +.fa-location-pin-lock:before { + content: "\e51f"; +} + +.fa-pause:before { + content: "\f04c"; +} + +.fa-hill-avalanche:before { + content: "\e507"; +} + +.fa-temperature-0:before, +.fa-temperature-empty:before, +.fa-thermometer-0:before, +.fa-thermometer-empty:before { + content: "\f2cb"; +} + +.fa-bomb:before { + content: "\f1e2"; +} + +.fa-registered:before { + content: "\f25d"; +} + +.fa-address-card:before, +.fa-contact-card:before, +.fa-vcard:before { + content: "\f2bb"; +} + +.fa-balance-scale-right:before, +.fa-scale-unbalanced-flip:before { + content: "\f516"; +} + +.fa-subscript:before { + content: "\f12c"; +} + +.fa-diamond-turn-right:before, +.fa-directions:before { + content: "\f5eb"; +} + +.fa-burst:before { + content: "\e4dc"; +} + +.fa-house-laptop:before, +.fa-laptop-house:before { + content: "\e066"; +} + +.fa-face-tired:before, +.fa-tired:before { + content: "\f5c8"; +} + +.fa-money-bills:before { + content: "\e1f3"; +} + +.fa-smog:before { + content: "\f75f"; +} + +.fa-crutch:before { + content: "\f7f7"; +} + +.fa-cloud-arrow-up:before, +.fa-cloud-upload-alt:before, +.fa-cloud-upload:before { + content: "\f0ee"; +} + +.fa-palette:before { + content: "\f53f"; +} + +.fa-arrows-turn-right:before { + content: "\e4c0"; +} + +.fa-vest:before { + content: "\e085"; +} + +.fa-ferry:before { + content: "\e4ea"; +} + +.fa-arrows-down-to-people:before { + content: "\e4b9"; +} + +.fa-seedling:before, +.fa-sprout:before { + content: "\f4d8"; +} + +.fa-arrows-alt-h:before, +.fa-left-right:before { + content: "\f337"; +} + +.fa-boxes-packing:before { + content: "\e4c7"; +} + +.fa-arrow-circle-left:before, +.fa-circle-arrow-left:before { + content: "\f0a8"; +} + +.fa-group-arrows-rotate:before { + content: "\e4f6"; +} + +.fa-bowl-food:before { + content: "\e4c6"; +} + +.fa-candy-cane:before { + content: "\f786"; +} + +.fa-arrow-down-wide-short:before, +.fa-sort-amount-asc:before, +.fa-sort-amount-down:before { + content: "\f160"; +} + +.fa-cloud-bolt:before, +.fa-thunderstorm:before { + content: "\f76c"; +} + +.fa-remove-format:before, +.fa-text-slash:before { + content: "\f87d"; +} + +.fa-face-smile-wink:before, +.fa-smile-wink:before { + content: "\f4da"; +} + +.fa-file-word:before { + content: "\f1c2"; +} + +.fa-file-powerpoint:before { + content: "\f1c4"; +} + +.fa-arrows-h:before, +.fa-arrows-left-right:before { + content: "\f07e"; +} + +.fa-house-lock:before { + content: "\e510"; +} + +.fa-cloud-arrow-down:before, +.fa-cloud-download-alt:before, +.fa-cloud-download:before { + content: "\f0ed"; +} + +.fa-children:before { + content: "\e4e1"; +} + +.fa-blackboard:before, +.fa-chalkboard:before { + content: "\f51b"; +} + +.fa-user-alt-slash:before, +.fa-user-large-slash:before { + content: "\f4fa"; +} + +.fa-envelope-open:before { + content: "\f2b6"; +} + +.fa-handshake-alt-slash:before, +.fa-handshake-simple-slash:before { + content: "\e05f"; +} + +.fa-mattress-pillow:before { + content: "\e525"; +} + +.fa-guarani-sign:before { + content: "\e19a"; +} + +.fa-arrows-rotate:before, +.fa-refresh:before, +.fa-sync:before { + content: "\f021"; +} + +.fa-fire-extinguisher:before { + content: "\f134"; +} + +.fa-cruzeiro-sign:before { + content: "\e152"; +} + +.fa-greater-than-equal:before { + content: "\f532"; +} + +.fa-shield-alt:before, +.fa-shield-halved:before { + content: "\f3ed"; +} + +.fa-atlas:before, +.fa-book-atlas:before { + content: "\f558"; +} + +.fa-virus:before { + content: "\e074"; +} + +.fa-envelope-circle-check:before { + content: "\e4e8"; +} + +.fa-layer-group:before { + content: "\f5fd"; +} + +.fa-arrows-to-dot:before { + content: "\e4be"; +} + +.fa-archway:before { + content: "\f557"; +} + +.fa-heart-circle-check:before { + content: "\e4fd"; +} + +.fa-house-chimney-crack:before, +.fa-house-damage:before { + content: "\f6f1"; +} + +.fa-file-archive:before, +.fa-file-zipper:before { + content: "\f1c6"; +} + +.fa-square:before { + content: "\f0c8"; +} + +.fa-glass-martini:before, +.fa-martini-glass-empty:before { + content: "\f000"; +} + +.fa-couch:before { + content: "\f4b8"; +} + +.fa-cedi-sign:before { + content: "\e0df"; +} + +.fa-italic:before { + content: "\f033"; +} + +.fa-church:before { + content: "\f51d"; +} + +.fa-comments-dollar:before { + content: "\f653"; +} + +.fa-democrat:before { + content: "\f747"; +} + +.fa-z:before { + content: "\5a"; +} + +.fa-person-skiing:before, +.fa-skiing:before { + content: "\f7c9"; +} + +.fa-road-lock:before { + content: "\e567"; +} + +.fa-a:before { + content: "\41"; +} + +.fa-temperature-arrow-down:before, +.fa-temperature-down:before { + content: "\e03f"; +} + +.fa-feather-alt:before, +.fa-feather-pointed:before { + content: "\f56b"; +} + +.fa-p:before { + content: "\50"; +} + +.fa-snowflake:before { + content: "\f2dc"; +} + +.fa-newspaper:before { + content: "\f1ea"; +} + +.fa-ad:before, +.fa-rectangle-ad:before { + content: "\f641"; +} + +.fa-arrow-circle-right:before, +.fa-circle-arrow-right:before { + content: "\f0a9"; +} + +.fa-filter-circle-xmark:before { + content: "\e17b"; +} + +.fa-locust:before { + content: "\e520"; +} + +.fa-sort:before, +.fa-unsorted:before { + content: "\f0dc"; +} + +.fa-list-1-2:before, +.fa-list-numeric:before, +.fa-list-ol:before { + content: "\f0cb"; +} + +.fa-person-dress-burst:before { + content: "\e544"; +} + +.fa-money-check-alt:before, +.fa-money-check-dollar:before { + content: "\f53d"; +} + +.fa-vector-square:before { + content: "\f5cb"; +} + +.fa-bread-slice:before { + content: "\f7ec"; +} + +.fa-language:before { + content: "\f1ab"; +} + +.fa-face-kiss-wink-heart:before, +.fa-kiss-wink-heart:before { + content: "\f598"; +} + +.fa-filter:before { + content: "\f0b0"; +} + +.fa-question:before { + content: "\3f"; +} + +.fa-file-signature:before { + content: "\f573"; +} + +.fa-arrows-alt:before, +.fa-up-down-left-right:before { + content: "\f0b2"; +} + +.fa-house-chimney-user:before { + content: "\e065"; +} + +.fa-hand-holding-heart:before { + content: "\f4be"; +} + +.fa-puzzle-piece:before { + content: "\f12e"; +} + +.fa-money-check:before { + content: "\f53c"; +} + +.fa-star-half-alt:before, +.fa-star-half-stroke:before { + content: "\f5c0"; +} + +.fa-code:before { + content: "\f121"; +} + +.fa-glass-whiskey:before, +.fa-whiskey-glass:before { + content: "\f7a0"; +} + +.fa-building-circle-exclamation:before { + content: "\e4d3"; +} + +.fa-magnifying-glass-chart:before { + content: "\e522"; +} + +.fa-arrow-up-right-from-square:before, +.fa-external-link:before { + content: "\f08e"; +} + +.fa-cubes-stacked:before { + content: "\e4e6"; +} + +.fa-krw:before, +.fa-won-sign:before, +.fa-won:before { + content: "\f159"; +} + +.fa-virus-covid:before { + content: "\e4a8"; +} + +.fa-austral-sign:before { + content: "\e0a9"; +} + +.fa-f:before { + content: "\46"; +} + +.fa-leaf:before { + content: "\f06c"; +} + +.fa-road:before { + content: "\f018"; +} + +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} + +.fa-person-circle-plus:before { + content: "\e541"; +} + +.fa-chart-pie:before, +.fa-pie-chart:before { + content: "\f200"; +} + +.fa-bolt-lightning:before { + content: "\e0b7"; +} + +.fa-sack-xmark:before { + content: "\e56a"; +} + +.fa-file-excel:before { + content: "\f1c3"; +} + +.fa-file-contract:before { + content: "\f56c"; +} + +.fa-fish-fins:before { + content: "\e4f2"; +} + +.fa-building-flag:before { + content: "\e4d5"; +} + +.fa-face-grin-beam:before, +.fa-grin-beam:before { + content: "\f582"; +} + +.fa-object-ungroup:before { + content: "\f248"; +} + +.fa-poop:before { + content: "\f619"; +} + +.fa-location-pin:before, +.fa-map-marker:before { + content: "\f041"; +} + +.fa-kaaba:before { + content: "\f66b"; +} + +.fa-toilet-paper:before { + content: "\f71e"; +} + +.fa-hard-hat:before, +.fa-hat-hard:before, +.fa-helmet-safety:before { + content: "\f807"; +} + +.fa-eject:before { + content: "\f052"; +} + +.fa-arrow-alt-circle-right:before, +.fa-circle-right:before { + content: "\f35a"; +} + +.fa-plane-circle-check:before { + content: "\e555"; +} + +.fa-face-rolling-eyes:before, +.fa-meh-rolling-eyes:before { + content: "\f5a5"; +} + +.fa-object-group:before { + content: "\f247"; +} + +.fa-chart-line:before, +.fa-line-chart:before { + content: "\f201"; +} + +.fa-mask-ventilator:before { + content: "\e524"; +} + +.fa-arrow-right:before { + content: "\f061"; +} + +.fa-map-signs:before, +.fa-signs-post:before { + content: "\f277"; +} + +.fa-cash-register:before { + content: "\f788"; +} + +.fa-person-circle-question:before { + content: "\e542"; +} + +.fa-h:before { + content: "\48"; +} + +.fa-tarp:before { + content: "\e57b"; +} + +.fa-screwdriver-wrench:before, +.fa-tools:before { + content: "\f7d9"; +} + +.fa-arrows-to-eye:before { + content: "\e4bf"; +} + +.fa-plug-circle-bolt:before { + content: "\e55b"; +} + +.fa-heart:before { + content: "\f004"; +} + +.fa-mars-and-venus:before { + content: "\f224"; +} + +.fa-home-user:before, +.fa-house-user:before { + content: "\e1b0"; +} + +.fa-dumpster-fire:before { + content: "\f794"; +} + +.fa-house-crack:before { + content: "\e3b1"; +} + +.fa-cocktail:before, +.fa-martini-glass-citrus:before { + content: "\f561"; +} + +.fa-face-surprise:before, +.fa-surprise:before { + content: "\f5c2"; +} + +.fa-bottle-water:before { + content: "\e4c5"; +} + +.fa-circle-pause:before, +.fa-pause-circle:before { + content: "\f28b"; +} + +.fa-toilet-paper-slash:before { + content: "\e072"; +} + +.fa-apple-alt:before, +.fa-apple-whole:before { + content: "\f5d1"; +} + +.fa-kitchen-set:before { + content: "\e51a"; +} + +.fa-r:before { + content: "\52"; +} + +.fa-temperature-1:before, +.fa-temperature-quarter:before, +.fa-thermometer-1:before, +.fa-thermometer-quarter:before { + content: "\f2ca"; +} + +.fa-cube:before { + content: "\f1b2"; +} + +.fa-bitcoin-sign:before { + content: "\e0b4"; +} + +.fa-shield-dog:before { + content: "\e573"; +} + +.fa-solar-panel:before { + content: "\f5ba"; +} + +.fa-lock-open:before { + content: "\f3c1"; +} + +.fa-elevator:before { + content: "\e16d"; +} + +.fa-money-bill-transfer:before { + content: "\e528"; +} + +.fa-money-bill-trend-up:before { + content: "\e529"; +} + +.fa-house-flood-water-circle-arrow-right:before { + content: "\e50f"; +} + +.fa-poll-h:before, +.fa-square-poll-horizontal:before { + content: "\f682"; +} + +.fa-circle:before { + content: "\f111"; +} + +.fa-backward-fast:before, +.fa-fast-backward:before { + content: "\f049"; +} + +.fa-recycle:before { + content: "\f1b8"; +} + +.fa-user-astronaut:before { + content: "\f4fb"; +} + +.fa-plane-slash:before { + content: "\e069"; +} + +.fa-trademark:before { + content: "\f25c"; +} + +.fa-basketball-ball:before, +.fa-basketball:before { + content: "\f434"; +} + +.fa-satellite-dish:before { + content: "\f7c0"; +} + +.fa-arrow-alt-circle-up:before, +.fa-circle-up:before { + content: "\f35b"; +} + +.fa-mobile-alt:before, +.fa-mobile-screen-button:before { + content: "\f3cd"; +} + +.fa-volume-high:before, +.fa-volume-up:before { + content: "\f028"; +} + +.fa-users-rays:before { + content: "\e593"; +} + +.fa-wallet:before { + content: "\f555"; +} + +.fa-clipboard-check:before { + content: "\f46c"; +} + +.fa-file-audio:before { + content: "\f1c7"; +} + +.fa-burger:before, +.fa-hamburger:before { + content: "\f805"; +} + +.fa-wrench:before { + content: "\f0ad"; +} + +.fa-bugs:before { + content: "\e4d0"; +} + +.fa-rupee-sign:before, +.fa-rupee:before { + content: "\f156"; +} + +.fa-file-image:before { + content: "\f1c5"; +} + +.fa-circle-question:before, +.fa-question-circle:before { + content: "\f059"; +} + +.fa-plane-departure:before { + content: "\f5b0"; +} + +.fa-handshake-slash:before { + content: "\e060"; +} + +.fa-book-bookmark:before { + content: "\e0bb"; +} + +.fa-code-branch:before { + content: "\f126"; +} + +.fa-hat-cowboy:before { + content: "\f8c0"; +} + +.fa-bridge:before { + content: "\e4c8"; +} + +.fa-phone-alt:before, +.fa-phone-flip:before { + content: "\f879"; +} + +.fa-truck-front:before { + content: "\e2b7"; +} + +.fa-cat:before { + content: "\f6be"; +} + +.fa-anchor-circle-exclamation:before { + content: "\e4ab"; +} + +.fa-truck-field:before { + content: "\e58d"; +} + +.fa-route:before { + content: "\f4d7"; +} + +.fa-clipboard-question:before { + content: "\e4e3"; +} + +.fa-panorama:before { + content: "\e209"; +} + +.fa-comment-medical:before { + content: "\f7f5"; +} + +.fa-teeth-open:before { + content: "\f62f"; +} + +.fa-file-circle-minus:before { + content: "\e4ed"; +} + +.fa-tags:before { + content: "\f02c"; +} + +.fa-wine-glass:before { + content: "\f4e3"; +} + +.fa-fast-forward:before, +.fa-forward-fast:before { + content: "\f050"; +} + +.fa-face-meh-blank:before, +.fa-meh-blank:before { + content: "\f5a4"; +} + +.fa-parking:before, +.fa-square-parking:before { + content: "\f540"; +} + +.fa-house-signal:before { + content: "\e012"; +} + +.fa-bars-progress:before, +.fa-tasks-alt:before { + content: "\f828"; +} + +.fa-faucet-drip:before { + content: "\e006"; +} + +.fa-cart-flatbed:before, +.fa-dolly-flatbed:before { + content: "\f474"; +} + +.fa-ban-smoking:before, +.fa-smoking-ban:before { + content: "\f54d"; +} + +.fa-terminal:before { + content: "\f120"; +} + +.fa-mobile-button:before { + content: "\f10b"; +} + +.fa-house-medical-flag:before { + content: "\e514"; +} + +.fa-basket-shopping:before, +.fa-shopping-basket:before { + content: "\f291"; +} + +.fa-tape:before { + content: "\f4db"; +} + +.fa-bus-alt:before, +.fa-bus-simple:before { + content: "\f55e"; +} + +.fa-eye:before { + content: "\f06e"; +} + +.fa-face-sad-cry:before, +.fa-sad-cry:before { + content: "\f5b3"; +} + +.fa-audio-description:before { + content: "\f29e"; +} + +.fa-person-military-to-person:before { + content: "\e54c"; +} + +.fa-file-shield:before { + content: "\e4f0"; +} + +.fa-user-slash:before { + content: "\f506"; +} + +.fa-pen:before { + content: "\f304"; +} + +.fa-tower-observation:before { + content: "\e586"; +} + +.fa-file-code:before { + content: "\f1c9"; +} + +.fa-signal-5:before, +.fa-signal-perfect:before, +.fa-signal:before { + content: "\f012"; +} + +.fa-bus:before { + content: "\f207"; +} + +.fa-heart-circle-xmark:before { + content: "\e501"; +} + +.fa-home-lg:before, +.fa-house-chimney:before { + content: "\e3af"; +} + +.fa-window-maximize:before { + content: "\f2d0"; +} + +.fa-face-frown:before, +.fa-frown:before { + content: "\f119"; +} + +.fa-prescription:before { + content: "\f5b1"; +} + +.fa-shop:before, +.fa-store-alt:before { + content: "\f54f"; +} + +.fa-floppy-disk:before, +.fa-save:before { + content: "\f0c7"; +} + +.fa-vihara:before { + content: "\f6a7"; +} + +.fa-balance-scale-left:before, +.fa-scale-unbalanced:before { + content: "\f515"; +} + +.fa-sort-asc:before, +.fa-sort-up:before { + content: "\f0de"; +} + +.fa-comment-dots:before, +.fa-commenting:before { + content: "\f4ad"; +} + +.fa-plant-wilt:before { + content: "\e5aa"; +} + +.fa-diamond:before { + content: "\f219"; +} + +.fa-face-grin-squint:before, +.fa-grin-squint:before { + content: "\f585"; +} + +.fa-hand-holding-dollar:before, +.fa-hand-holding-usd:before { + content: "\f4c0"; +} + +.fa-bacterium:before { + content: "\e05a"; +} + +.fa-hand-pointer:before { + content: "\f25a"; +} + +.fa-drum-steelpan:before { + content: "\f56a"; +} + +.fa-hand-scissors:before { + content: "\f257"; +} + +.fa-hands-praying:before, +.fa-praying-hands:before { + content: "\f684"; +} + +.fa-arrow-right-rotate:before, +.fa-arrow-rotate-forward:before, +.fa-arrow-rotate-right:before, +.fa-redo:before { + content: "\f01e"; +} + +.fa-biohazard:before { + content: "\f780"; +} + +.fa-location-crosshairs:before, +.fa-location:before { + content: "\f601"; +} + +.fa-mars-double:before { + content: "\f227"; +} + +.fa-child-dress:before { + content: "\e59c"; +} + +.fa-users-between-lines:before { + content: "\e591"; +} + +.fa-lungs-virus:before { + content: "\e067"; +} + +.fa-face-grin-tears:before, +.fa-grin-tears:before { + content: "\f588"; +} + +.fa-phone:before { + content: "\f095"; +} + +.fa-calendar-times:before, +.fa-calendar-xmark:before { + content: "\f273"; +} + +.fa-child-reaching:before { + content: "\e59d"; +} + +.fa-head-side-virus:before { + content: "\e064"; +} + +.fa-user-cog:before, +.fa-user-gear:before { + content: "\f4fe"; +} + +.fa-arrow-up-1-9:before, +.fa-sort-numeric-up:before { + content: "\f163"; +} + +.fa-door-closed:before { + content: "\f52a"; +} + +.fa-shield-virus:before { + content: "\e06c"; +} + +.fa-dice-six:before { + content: "\f526"; +} + +.fa-mosquito-net:before { + content: "\e52c"; +} + +.fa-bridge-water:before { + content: "\e4ce"; +} + +.fa-person-booth:before { + content: "\f756"; +} + +.fa-text-width:before { + content: "\f035"; +} + +.fa-hat-wizard:before { + content: "\f6e8"; +} + +.fa-pen-fancy:before { + content: "\f5ac"; +} + +.fa-digging:before, +.fa-person-digging:before { + content: "\f85e"; +} + +.fa-trash:before { + content: "\f1f8"; +} + +.fa-gauge-simple-med:before, +.fa-gauge-simple:before, +.fa-tachometer-average:before { + content: "\f629"; +} + +.fa-book-medical:before { + content: "\f7e6"; +} + +.fa-poo:before { + content: "\f2fe"; +} + +.fa-quote-right-alt:before, +.fa-quote-right:before { + content: "\f10e"; +} + +.fa-shirt:before, +.fa-t-shirt:before, +.fa-tshirt:before { + content: "\f553"; +} + +.fa-cubes:before { + content: "\f1b3"; +} + +.fa-divide:before { + content: "\f529"; +} + +.fa-tenge-sign:before, +.fa-tenge:before { + content: "\f7d7"; +} + +.fa-headphones:before { + content: "\f025"; +} + +.fa-hands-holding:before { + content: "\f4c2"; +} + +.fa-hands-clapping:before { + content: "\e1a8"; +} + +.fa-republican:before { + content: "\f75e"; +} + +.fa-arrow-left:before { + content: "\f060"; +} + +.fa-person-circle-xmark:before { + content: "\e543"; +} + +.fa-ruler:before { + content: "\f545"; +} + +.fa-align-left:before { + content: "\f036"; +} + +.fa-dice-d6:before { + content: "\f6d1"; +} + +.fa-restroom:before { + content: "\f7bd"; +} + +.fa-j:before { + content: "\4a"; +} + +.fa-users-viewfinder:before { + content: "\e595"; +} + +.fa-file-video:before { + content: "\f1c8"; +} + +.fa-external-link-alt:before, +.fa-up-right-from-square:before { + content: "\f35d"; +} + +.fa-table-cells:before, +.fa-th:before { + content: "\f00a"; +} + +.fa-file-pdf:before { + content: "\f1c1"; +} + +.fa-bible:before, +.fa-book-bible:before { + content: "\f647"; +} + +.fa-o:before { + content: "\4f"; +} + +.fa-medkit:before, +.fa-suitcase-medical:before { + content: "\f0fa"; +} + +.fa-user-secret:before { + content: "\f21b"; +} + +.fa-otter:before { + content: "\f700"; +} + +.fa-female:before, +.fa-person-dress:before { + content: "\f182"; +} + +.fa-comment-dollar:before { + content: "\f651"; +} + +.fa-briefcase-clock:before, +.fa-business-time:before { + content: "\f64a"; +} + +.fa-table-cells-large:before, +.fa-th-large:before { + content: "\f009"; +} + +.fa-book-tanakh:before, +.fa-tanakh:before { + content: "\f827"; +} + +.fa-phone-volume:before, +.fa-volume-control-phone:before { + content: "\f2a0"; +} + +.fa-hat-cowboy-side:before { + content: "\f8c1"; +} + +.fa-clipboard-user:before { + content: "\f7f3"; +} + +.fa-child:before { + content: "\f1ae"; +} + +.fa-lira-sign:before { + content: "\f195"; +} + +.fa-satellite:before { + content: "\f7bf"; +} + +.fa-plane-lock:before { + content: "\e558"; +} + +.fa-tag:before { + content: "\f02b"; +} + +.fa-comment:before { + content: "\f075"; +} + +.fa-birthday-cake:before, +.fa-cake-candles:before, +.fa-cake:before { + content: "\f1fd"; +} + +.fa-envelope:before { + content: "\f0e0"; +} + +.fa-angle-double-up:before, +.fa-angles-up:before { + content: "\f102"; +} + +.fa-paperclip:before { + content: "\f0c6"; +} + +.fa-arrow-right-to-city:before { + content: "\e4b3"; +} + +.fa-ribbon:before { + content: "\f4d6"; +} + +.fa-lungs:before { + content: "\f604"; +} + +.fa-arrow-up-9-1:before, +.fa-sort-numeric-up-alt:before { + content: "\f887"; +} + +.fa-litecoin-sign:before { + content: "\e1d3"; +} + +.fa-border-none:before { + content: "\f850"; +} + +.fa-circle-nodes:before { + content: "\e4e2"; +} + +.fa-parachute-box:before { + content: "\f4cd"; +} + +.fa-indent:before { + content: "\f03c"; +} + +.fa-truck-field-un:before { + content: "\e58e"; +} + +.fa-hourglass-empty:before, +.fa-hourglass:before { + content: "\f254"; +} + +.fa-mountain:before { + content: "\f6fc"; +} + +.fa-user-doctor:before, +.fa-user-md:before { + content: "\f0f0"; +} + +.fa-circle-info:before, +.fa-info-circle:before { + content: "\f05a"; +} + +.fa-cloud-meatball:before { + content: "\f73b"; +} + +.fa-camera-alt:before, +.fa-camera:before { + content: "\f030"; +} + +.fa-square-virus:before { + content: "\e578"; +} + +.fa-meteor:before { + content: "\f753"; +} + +.fa-car-on:before { + content: "\e4dd"; +} + +.fa-sleigh:before { + content: "\f7cc"; +} + +.fa-arrow-down-1-9:before, +.fa-sort-numeric-asc:before, +.fa-sort-numeric-down:before { + content: "\f162"; +} + +.fa-hand-holding-droplet:before, +.fa-hand-holding-water:before { + content: "\f4c1"; +} + +.fa-water:before { + content: "\f773"; +} + +.fa-calendar-check:before { + content: "\f274"; +} + +.fa-braille:before { + content: "\f2a1"; +} + +.fa-prescription-bottle-alt:before, +.fa-prescription-bottle-medical:before { + content: "\f486"; +} + +.fa-landmark:before { + content: "\f66f"; +} + +.fa-truck:before { + content: "\f0d1"; +} + +.fa-crosshairs:before { + content: "\f05b"; +} + +.fa-person-cane:before { + content: "\e53c"; +} + +.fa-tent:before { + content: "\e57d"; +} + +.fa-vest-patches:before { + content: "\e086"; +} + +.fa-check-double:before { + content: "\f560"; +} + +.fa-arrow-down-a-z:before, +.fa-sort-alpha-asc:before, +.fa-sort-alpha-down:before { + content: "\f15d"; +} + +.fa-money-bill-wheat:before { + content: "\e52a"; +} + +.fa-cookie:before { + content: "\f563"; +} + +.fa-arrow-left-rotate:before, +.fa-arrow-rotate-back:before, +.fa-arrow-rotate-backward:before, +.fa-arrow-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} + +.fa-hard-drive:before, +.fa-hdd:before { + content: "\f0a0"; +} + +.fa-face-grin-squint-tears:before, +.fa-grin-squint-tears:before { + content: "\f586"; +} + +.fa-dumbbell:before { + content: "\f44b"; +} + +.fa-list-alt:before, +.fa-rectangle-list:before { + content: "\f022"; +} + +.fa-tarp-droplet:before { + content: "\e57c"; +} + +.fa-house-medical-circle-check:before { + content: "\e511"; +} + +.fa-person-skiing-nordic:before, +.fa-skiing-nordic:before { + content: "\f7ca"; +} + +.fa-calendar-plus:before { + content: "\f271"; +} + +.fa-plane-arrival:before { + content: "\f5af"; +} + +.fa-arrow-alt-circle-left:before, +.fa-circle-left:before { + content: "\f359"; +} + +.fa-subway:before, +.fa-train-subway:before { + content: "\f239"; +} + +.fa-chart-gantt:before { + content: "\e0e4"; +} + +.fa-indian-rupee-sign:before, +.fa-indian-rupee:before, +.fa-inr:before { + content: "\e1bc"; +} + +.fa-crop-alt:before, +.fa-crop-simple:before { + content: "\f565"; +} + +.fa-money-bill-1:before, +.fa-money-bill-alt:before { + content: "\f3d1"; +} + +.fa-left-long:before, +.fa-long-arrow-alt-left:before { + content: "\f30a"; +} + +.fa-dna:before { + content: "\f471"; +} + +.fa-virus-slash:before { + content: "\e075"; +} + +.fa-minus:before, +.fa-subtract:before { + content: "\f068"; +} + +.fa-chess:before { + content: "\f439"; +} + +.fa-arrow-left-long:before, +.fa-long-arrow-left:before { + content: "\f177"; +} + +.fa-plug-circle-check:before { + content: "\e55c"; +} + +.fa-street-view:before { + content: "\f21d"; +} + +.fa-franc-sign:before { + content: "\e18f"; +} + +.fa-volume-off:before { + content: "\f026"; +} + +.fa-american-sign-language-interpreting:before, +.fa-asl-interpreting:before, +.fa-hands-american-sign-language-interpreting:before, +.fa-hands-asl-interpreting:before { + content: "\f2a3"; +} + +.fa-cog:before, +.fa-gear:before { + content: "\f013"; +} + +.fa-droplet-slash:before, +.fa-tint-slash:before { + content: "\f5c7"; +} + +.fa-mosque:before { + content: "\f678"; +} + +.fa-mosquito:before { + content: "\e52b"; +} + +.fa-star-of-david:before { + content: "\f69a"; +} + +.fa-person-military-rifle:before { + content: "\e54b"; +} + +.fa-cart-shopping:before, +.fa-shopping-cart:before { + content: "\f07a"; +} + +.fa-vials:before { + content: "\f493"; +} + +.fa-plug-circle-plus:before { + content: "\e55f"; +} + +.fa-place-of-worship:before { + content: "\f67f"; +} + +.fa-grip-vertical:before { + content: "\f58e"; +} + +.fa-arrow-turn-up:before, +.fa-level-up:before { + content: "\f148"; +} + +.fa-u:before { + content: "\55"; +} + +.fa-square-root-alt:before, +.fa-square-root-variable:before { + content: "\f698"; +} + +.fa-clock-four:before, +.fa-clock:before { + content: "\f017"; +} + +.fa-backward-step:before, +.fa-step-backward:before { + content: "\f048"; +} + +.fa-pallet:before { + content: "\f482"; +} + +.fa-faucet:before { + content: "\e005"; +} + +.fa-baseball-bat-ball:before { + content: "\f432"; +} + +.fa-s:before { + content: "\53"; +} + +.fa-timeline:before { + content: "\e29c"; +} + +.fa-keyboard:before { + content: "\f11c"; +} + +.fa-caret-down:before { + content: "\f0d7"; +} + +.fa-clinic-medical:before, +.fa-house-chimney-medical:before { + content: "\f7f2"; +} + +.fa-temperature-3:before, +.fa-temperature-three-quarters:before, +.fa-thermometer-3:before, +.fa-thermometer-three-quarters:before { + content: "\f2c8"; +} + +.fa-mobile-android-alt:before, +.fa-mobile-screen:before { + content: "\f3cf"; +} + +.fa-plane-up:before { + content: "\e22d"; +} + +.fa-piggy-bank:before { + content: "\f4d3"; +} + +.fa-battery-3:before, +.fa-battery-half:before { + content: "\f242"; +} + +.fa-mountain-city:before { + content: "\e52e"; +} + +.fa-coins:before { + content: "\f51e"; +} + +.fa-khanda:before { + content: "\f66d"; +} + +.fa-sliders-h:before, +.fa-sliders:before { + content: "\f1de"; +} + +.fa-folder-tree:before { + content: "\f802"; +} + +.fa-network-wired:before { + content: "\f6ff"; +} + +.fa-map-pin:before { + content: "\f276"; +} + +.fa-hamsa:before { + content: "\f665"; +} + +.fa-cent-sign:before { + content: "\e3f5"; +} + +.fa-flask:before { + content: "\f0c3"; +} + +.fa-person-pregnant:before { + content: "\e31e"; +} + +.fa-wand-sparkles:before { + content: "\f72b"; +} + +.fa-ellipsis-v:before, +.fa-ellipsis-vertical:before { + content: "\f142"; +} + +.fa-ticket:before { + content: "\f145"; +} + +.fa-power-off:before { + content: "\f011"; +} + +.fa-long-arrow-alt-right:before, +.fa-right-long:before { + content: "\f30b"; +} + +.fa-flag-usa:before { + content: "\f74d"; +} + +.fa-laptop-file:before { + content: "\e51d"; +} + +.fa-teletype:before, +.fa-tty:before { + content: "\f1e4"; +} + +.fa-diagram-next:before { + content: "\e476"; +} + +.fa-person-rifle:before { + content: "\e54e"; +} + +.fa-house-medical-circle-exclamation:before { + content: "\e512"; +} + +.fa-closed-captioning:before { + content: "\f20a"; +} + +.fa-hiking:before, +.fa-person-hiking:before { + content: "\f6ec"; +} + +.fa-venus-double:before { + content: "\f226"; +} + +.fa-images:before { + content: "\f302"; +} + +.fa-calculator:before { + content: "\f1ec"; +} + +.fa-people-pulling:before { + content: "\e535"; +} + +.fa-n:before { + content: "\4e"; +} + +.fa-cable-car:before, +.fa-tram:before { + content: "\f7da"; +} + +.fa-cloud-rain:before { + content: "\f73d"; +} + +.fa-building-circle-xmark:before { + content: "\e4d4"; +} + +.fa-ship:before { + content: "\f21a"; +} + +.fa-arrows-down-to-line:before { + content: "\e4b8"; +} + +.fa-download:before { + content: "\f019"; +} + +.fa-face-grin:before, +.fa-grin:before { + content: "\f580"; +} + +.fa-backspace:before, +.fa-delete-left:before { + content: "\f55a"; +} + +.fa-eye-dropper-empty:before, +.fa-eye-dropper:before, +.fa-eyedropper:before { + content: "\f1fb"; +} + +.fa-file-circle-check:before { + content: "\e5a0"; +} + +.fa-forward:before { + content: "\f04e"; +} + +.fa-mobile-android:before, +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f3ce"; +} + +.fa-face-meh:before, +.fa-meh:before { + content: "\f11a"; +} + +.fa-align-center:before { + content: "\f037"; +} + +.fa-book-dead:before, +.fa-book-skull:before { + content: "\f6b7"; +} + +.fa-drivers-license:before, +.fa-id-card:before { + content: "\f2c2"; +} + +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} + +.fa-heart-circle-exclamation:before { + content: "\e4fe"; +} + +.fa-home-alt:before, +.fa-home-lg-alt:before, +.fa-home:before, +.fa-house:before { + content: "\f015"; +} + +.fa-calendar-week:before { + content: "\f784"; +} + +.fa-laptop-medical:before { + content: "\f812"; +} + +.fa-b:before { + content: "\42"; +} + +.fa-file-medical:before { + content: "\f477"; +} + +.fa-dice-one:before { + content: "\f525"; +} + +.fa-kiwi-bird:before { + content: "\f535"; +} + +.fa-arrow-right-arrow-left:before, +.fa-exchange:before { + content: "\f0ec"; +} + +.fa-redo-alt:before, +.fa-rotate-forward:before, +.fa-rotate-right:before { + content: "\f2f9"; +} + +.fa-cutlery:before, +.fa-utensils:before { + content: "\f2e7"; +} + +.fa-arrow-up-wide-short:before, +.fa-sort-amount-up:before { + content: "\f161"; +} + +.fa-mill-sign:before { + content: "\e1ed"; +} + +.fa-bowl-rice:before { + content: "\e2eb"; +} + +.fa-skull:before { + content: "\f54c"; +} + +.fa-broadcast-tower:before, +.fa-tower-broadcast:before { + content: "\f519"; +} + +.fa-truck-pickup:before { + content: "\f63c"; +} + +.fa-long-arrow-alt-up:before, +.fa-up-long:before { + content: "\f30c"; +} + +.fa-stop:before { + content: "\f04d"; +} + +.fa-code-merge:before { + content: "\f387"; +} + +.fa-upload:before { + content: "\f093"; +} + +.fa-hurricane:before { + content: "\f751"; +} + +.fa-mound:before { + content: "\e52d"; +} + +.fa-toilet-portable:before { + content: "\e583"; +} + +.fa-compact-disc:before { + content: "\f51f"; +} + +.fa-file-arrow-down:before, +.fa-file-download:before { + content: "\f56d"; +} + +.fa-caravan:before { + content: "\f8ff"; +} + +.fa-shield-cat:before { + content: "\e572"; +} + +.fa-bolt:before, +.fa-zap:before { + content: "\f0e7"; +} + +.fa-glass-water:before { + content: "\e4f4"; +} + +.fa-oil-well:before { + content: "\e532"; +} + +.fa-vault:before { + content: "\e2c5"; +} + +.fa-mars:before { + content: "\f222"; +} + +.fa-toilet:before { + content: "\f7d8"; +} + +.fa-plane-circle-xmark:before { + content: "\e557"; +} + +.fa-cny:before, +.fa-jpy:before, +.fa-rmb:before, +.fa-yen-sign:before, +.fa-yen:before { + content: "\f157"; +} + +.fa-rouble:before, +.fa-rub:before, +.fa-ruble-sign:before, +.fa-ruble:before { + content: "\f158"; +} + +.fa-sun:before { + content: "\f185"; +} + +.fa-guitar:before { + content: "\f7a6"; +} + +.fa-face-laugh-wink:before, +.fa-laugh-wink:before { + content: "\f59c"; +} + +.fa-horse-head:before { + content: "\f7ab"; +} + +.fa-bore-hole:before { + content: "\e4c3"; +} + +.fa-industry:before { + content: "\f275"; +} + +.fa-arrow-alt-circle-down:before, +.fa-circle-down:before { + content: "\f358"; +} + +.fa-arrows-turn-to-dots:before { + content: "\e4c1"; +} + +.fa-florin-sign:before { + content: "\e184"; +} + +.fa-arrow-down-short-wide:before, +.fa-sort-amount-desc:before, +.fa-sort-amount-down-alt:before { + content: "\f884"; +} + +.fa-less-than:before { + content: "\3c"; +} + +.fa-angle-down:before { + content: "\f107"; +} + +.fa-car-tunnel:before { + content: "\e4de"; +} + +.fa-head-side-cough:before { + content: "\e061"; +} + +.fa-grip-lines:before { + content: "\f7a4"; +} + +.fa-thumbs-down:before { + content: "\f165"; +} + +.fa-user-lock:before { + content: "\f502"; +} + +.fa-arrow-right-long:before, +.fa-long-arrow-right:before { + content: "\f178"; +} + +.fa-anchor-circle-xmark:before { + content: "\e4ac"; +} + +.fa-ellipsis-h:before, +.fa-ellipsis:before { + content: "\f141"; +} + +.fa-chess-pawn:before { + content: "\f443"; +} + +.fa-first-aid:before, +.fa-kit-medical:before { + content: "\f479"; +} + +.fa-person-through-window:before { + content: "\e5a9"; +} + +.fa-toolbox:before { + content: "\f552"; +} + +.fa-hands-holding-circle:before { + content: "\e4fb"; +} + +.fa-bug:before { + content: "\f188"; +} + +.fa-credit-card-alt:before, +.fa-credit-card:before { + content: "\f09d"; +} + +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} + +.fa-hand-holding-hand:before { + content: "\e4f7"; +} + +.fa-book-open-reader:before, +.fa-book-reader:before { + content: "\f5da"; +} + +.fa-mountain-sun:before { + content: "\e52f"; +} + +.fa-arrows-left-right-to-line:before { + content: "\e4ba"; +} + +.fa-dice-d20:before { + content: "\f6cf"; +} + +.fa-truck-droplet:before { + content: "\e58c"; +} + +.fa-file-circle-xmark:before { + content: "\e5a1"; +} + +.fa-temperature-arrow-up:before, +.fa-temperature-up:before { + content: "\e040"; +} + +.fa-medal:before { + content: "\f5a2"; +} + +.fa-bed:before { + content: "\f236"; +} + +.fa-h-square:before, +.fa-square-h:before { + content: "\f0fd"; +} + +.fa-podcast:before { + content: "\f2ce"; +} + +.fa-temperature-4:before, +.fa-temperature-full:before, +.fa-thermometer-4:before, +.fa-thermometer-full:before { + content: "\f2c7"; +} + +.fa-bell:before { + content: "\f0f3"; +} + +.fa-superscript:before { + content: "\f12b"; +} + +.fa-plug-circle-xmark:before { + content: "\e560"; +} + +.fa-star-of-life:before { + content: "\f621"; +} + +.fa-phone-slash:before { + content: "\f3dd"; +} + +.fa-paint-roller:before { + content: "\f5aa"; +} + +.fa-hands-helping:before, +.fa-handshake-angle:before { + content: "\f4c4"; +} + +.fa-location-dot:before, +.fa-map-marker-alt:before { + content: "\f3c5"; +} + +.fa-file:before { + content: "\f15b"; +} + +.fa-greater-than:before { + content: "\3e"; +} + +.fa-person-swimming:before, +.fa-swimmer:before { + content: "\f5c4"; +} + +.fa-arrow-down:before { + content: "\f063"; +} + +.fa-droplet:before, +.fa-tint:before { + content: "\f043"; +} + +.fa-eraser:before { + content: "\f12d"; +} + +.fa-earth-america:before, +.fa-earth-americas:before, +.fa-earth:before, +.fa-globe-americas:before { + content: "\f57d"; +} + +.fa-person-burst:before { + content: "\e53b"; +} + +.fa-dove:before { + content: "\f4ba"; +} + +.fa-battery-0:before, +.fa-battery-empty:before { + content: "\f244"; +} + +.fa-socks:before { + content: "\f696"; +} + +.fa-inbox:before { + content: "\f01c"; +} + +.fa-section:before { + content: "\e447"; +} + +.fa-gauge-high:before, +.fa-tachometer-alt-fast:before, +.fa-tachometer-alt:before { + content: "\f625"; +} + +.fa-envelope-open-text:before { + content: "\f658"; +} + +.fa-hospital-alt:before, +.fa-hospital-wide:before, +.fa-hospital:before { + content: "\f0f8"; +} + +.fa-wine-bottle:before { + content: "\f72f"; +} + +.fa-chess-rook:before { + content: "\f447"; +} + +.fa-bars-staggered:before, +.fa-reorder:before, +.fa-stream:before { + content: "\f550"; +} + +.fa-dharmachakra:before { + content: "\f655"; +} + +.fa-hotdog:before { + content: "\f80f"; +} + +.fa-blind:before, +.fa-person-walking-with-cane:before { + content: "\f29d"; +} + +.fa-drum:before { + content: "\f569"; +} + +.fa-ice-cream:before { + content: "\f810"; +} + +.fa-heart-circle-bolt:before { + content: "\e4fc"; +} + +.fa-fax:before { + content: "\f1ac"; +} + +.fa-paragraph:before { + content: "\f1dd"; +} + +.fa-check-to-slot:before, +.fa-vote-yea:before { + content: "\f772"; +} + +.fa-star-half:before { + content: "\f089"; +} + +.fa-boxes-alt:before, +.fa-boxes-stacked:before, +.fa-boxes:before { + content: "\f468"; +} + +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} + +.fa-assistive-listening-systems:before, +.fa-ear-listen:before { + content: "\f2a2"; +} + +.fa-tree-city:before { + content: "\e587"; +} + +.fa-play:before { + content: "\f04b"; +} + +.fa-font:before { + content: "\f031"; +} + +.fa-rupiah-sign:before { + content: "\e23d"; +} + +.fa-magnifying-glass:before, +.fa-search:before { + content: "\f002"; +} + +.fa-ping-pong-paddle-ball:before, +.fa-table-tennis-paddle-ball:before, +.fa-table-tennis:before { + content: "\f45d"; +} + +.fa-diagnoses:before, +.fa-person-dots-from-line:before { + content: "\f470"; +} + +.fa-trash-can-arrow-up:before, +.fa-trash-restore-alt:before { + content: "\f82a"; +} + +.fa-naira-sign:before { + content: "\e1f6"; +} + +.fa-cart-arrow-down:before { + content: "\f218"; +} + +.fa-walkie-talkie:before { + content: "\f8ef"; +} + +.fa-file-edit:before, +.fa-file-pen:before { + content: "\f31c"; +} + +.fa-receipt:before { + content: "\f543"; +} + +.fa-pen-square:before, +.fa-pencil-square:before, +.fa-square-pen:before { + content: "\f14b"; +} + +.fa-suitcase-rolling:before { + content: "\f5c1"; +} + +.fa-person-circle-exclamation:before { + content: "\e53f"; +} + +.fa-chevron-down:before { + content: "\f078"; +} + +.fa-battery-5:before, +.fa-battery-full:before, +.fa-battery:before { + content: "\f240"; +} + +.fa-skull-crossbones:before { + content: "\f714"; +} + +.fa-code-compare:before { + content: "\e13a"; +} + +.fa-list-dots:before, +.fa-list-ul:before { + content: "\f0ca"; +} + +.fa-school-lock:before { + content: "\e56f"; +} + +.fa-tower-cell:before { + content: "\e585"; +} + +.fa-down-long:before, +.fa-long-arrow-alt-down:before { + content: "\f309"; +} + +.fa-ranking-star:before { + content: "\e561"; +} + +.fa-chess-king:before { + content: "\f43f"; +} + +.fa-person-harassing:before { + content: "\e549"; +} + +.fa-brazilian-real-sign:before { + content: "\e46c"; +} + +.fa-landmark-alt:before, +.fa-landmark-dome:before { + content: "\f752"; +} + +.fa-arrow-up:before { + content: "\f062"; +} + +.fa-television:before, +.fa-tv-alt:before, +.fa-tv:before { + content: "\f26c"; +} + +.fa-shrimp:before { + content: "\e448"; +} + +.fa-list-check:before, +.fa-tasks:before { + content: "\f0ae"; +} + +.fa-jug-detergent:before { + content: "\e519"; +} + +.fa-circle-user:before, +.fa-user-circle:before { + content: "\f2bd"; +} + +.fa-user-shield:before { + content: "\f505"; +} + +.fa-wind:before { + content: "\f72e"; +} + +.fa-car-burst:before, +.fa-car-crash:before { + content: "\f5e1"; +} + +.fa-y:before { + content: "\59"; +} + +.fa-person-snowboarding:before, +.fa-snowboarding:before { + content: "\f7ce"; +} + +.fa-shipping-fast:before, +.fa-truck-fast:before { + content: "\f48b"; +} + +.fa-fish:before { + content: "\f578"; +} + +.fa-user-graduate:before { + content: "\f501"; +} + +.fa-adjust:before, +.fa-circle-half-stroke:before { + content: "\f042"; +} + +.fa-clapperboard:before { + content: "\e131"; +} + +.fa-circle-radiation:before, +.fa-radiation-alt:before { + content: "\f7ba"; +} + +.fa-baseball-ball:before, +.fa-baseball:before { + content: "\f433"; +} + +.fa-jet-fighter-up:before { + content: "\e518"; +} + +.fa-diagram-project:before, +.fa-project-diagram:before { + content: "\f542"; +} + +.fa-copy:before { + content: "\f0c5"; +} + +.fa-volume-mute:before, +.fa-volume-times:before, +.fa-volume-xmark:before { + content: "\f6a9"; +} + +.fa-hand-sparkles:before { + content: "\e05d"; +} + +.fa-grip-horizontal:before, +.fa-grip:before { + content: "\f58d"; +} + +.fa-share-from-square:before, +.fa-share-square:before { + content: "\f14d"; +} + +.fa-child-combatant:before, +.fa-child-rifle:before { + content: "\e4e0"; +} + +.fa-gun:before { + content: "\e19b"; +} + +.fa-phone-square:before, +.fa-square-phone:before { + content: "\f098"; +} + +.fa-add:before, +.fa-plus:before { + content: "\2b"; +} + +.fa-expand:before { + content: "\f065"; +} + +.fa-computer:before { + content: "\e4e5"; +} + +.fa-close:before, +.fa-multiply:before, +.fa-remove:before, +.fa-times:before, +.fa-xmark:before { + content: "\f00d"; +} + +.fa-arrows-up-down-left-right:before, +.fa-arrows:before { + content: "\f047"; +} + +.fa-chalkboard-teacher:before, +.fa-chalkboard-user:before { + content: "\f51c"; +} + +.fa-peso-sign:before { + content: "\e222"; +} + +.fa-building-shield:before { + content: "\e4d8"; +} + +.fa-baby:before { + content: "\f77c"; +} + +.fa-users-line:before { + content: "\e592"; +} + +.fa-quote-left-alt:before, +.fa-quote-left:before { + content: "\f10d"; +} + +.fa-tractor:before { + content: "\f722"; +} + +.fa-trash-arrow-up:before, +.fa-trash-restore:before { + content: "\f829"; +} + +.fa-arrow-down-up-lock:before { + content: "\e4b0"; +} + +.fa-lines-leaning:before { + content: "\e51e"; +} + +.fa-ruler-combined:before { + content: "\f546"; +} + +.fa-copyright:before { + content: "\f1f9"; +} + +.fa-equals:before { + content: "\3d"; +} + +.fa-blender:before { + content: "\f517"; +} + +.fa-teeth:before { + content: "\f62e"; +} + +.fa-ils:before, +.fa-shekel-sign:before, +.fa-shekel:before, +.fa-sheqel-sign:before, +.fa-sheqel:before { + content: "\f20b"; +} + +.fa-map:before { + content: "\f279"; +} + +.fa-rocket:before { + content: "\f135"; +} + +.fa-photo-film:before, +.fa-photo-video:before { + content: "\f87c"; +} + +.fa-folder-minus:before { + content: "\f65d"; +} + +.fa-store:before { + content: "\f54e"; +} + +.fa-arrow-trend-up:before { + content: "\e098"; +} + +.fa-plug-circle-minus:before { + content: "\e55e"; +} + +.fa-sign-hanging:before, +.fa-sign:before { + content: "\f4d9"; +} + +.fa-bezier-curve:before { + content: "\f55b"; +} + +.fa-bell-slash:before { + content: "\f1f6"; +} + +.fa-tablet-android:before, +.fa-tablet:before { + content: "\f3fb"; +} + +.fa-school-flag:before { + content: "\e56e"; +} + +.fa-fill:before { + content: "\f575"; +} + +.fa-angle-up:before { + content: "\f106"; +} + +.fa-drumstick-bite:before { + content: "\f6d7"; +} + +.fa-holly-berry:before { + content: "\f7aa"; +} + +.fa-chevron-left:before { + content: "\f053"; +} + +.fa-bacteria:before { + content: "\e059"; +} + +.fa-hand-lizard:before { + content: "\f258"; +} + +.fa-notdef:before { + content: "\e1fe"; +} + +.fa-disease:before { + content: "\f7fa"; +} + +.fa-briefcase-medical:before { + content: "\f469"; +} + +.fa-genderless:before { + content: "\f22d"; +} + +.fa-chevron-right:before { + content: "\f054"; +} + +.fa-retweet:before { + content: "\f079"; +} + +.fa-car-alt:before, +.fa-car-rear:before { + content: "\f5de"; +} + +.fa-pump-soap:before { + content: "\e06b"; +} + +.fa-video-slash:before { + content: "\f4e2"; +} + +.fa-battery-2:before, +.fa-battery-quarter:before { + content: "\f243"; +} + +.fa-radio:before { + content: "\f8d7"; +} + +.fa-baby-carriage:before, +.fa-carriage-baby:before { + content: "\f77d"; +} + +.fa-traffic-light:before { + content: "\f637"; +} + +.fa-thermometer:before { + content: "\f491"; +} + +.fa-vr-cardboard:before { + content: "\f729"; +} + +.fa-hand-middle-finger:before { + content: "\f806"; +} + +.fa-percent:before, +.fa-percentage:before { + content: "\25"; +} + +.fa-truck-moving:before { + content: "\f4df"; +} + +.fa-glass-water-droplet:before { + content: "\e4f5"; +} + +.fa-display:before { + content: "\e163"; +} + +.fa-face-smile:before, +.fa-smile:before { + content: "\f118"; +} + +.fa-thumb-tack:before, +.fa-thumbtack:before { + content: "\f08d"; +} + +.fa-trophy:before { + content: "\f091"; +} + +.fa-person-praying:before, +.fa-pray:before { + content: "\f683"; +} + +.fa-hammer:before { + content: "\f6e3"; +} + +.fa-hand-peace:before { + content: "\f25b"; +} + +.fa-rotate:before, +.fa-sync-alt:before { + content: "\f2f1"; +} + +.fa-spinner:before { + content: "\f110"; +} + +.fa-robot:before { + content: "\f544"; +} + +.fa-peace:before { + content: "\f67c"; +} + +.fa-cogs:before, +.fa-gears:before { + content: "\f085"; +} + +.fa-warehouse:before { + content: "\f494"; +} + +.fa-arrow-up-right-dots:before { + content: "\e4b7"; +} + +.fa-splotch:before { + content: "\f5bc"; +} + +.fa-face-grin-hearts:before, +.fa-grin-hearts:before { + content: "\f584"; +} + +.fa-dice-four:before { + content: "\f524"; +} + +.fa-sim-card:before { + content: "\f7c4"; +} + +.fa-transgender-alt:before, +.fa-transgender:before { + content: "\f225"; +} + +.fa-mercury:before { + content: "\f223"; +} + +.fa-arrow-turn-down:before, +.fa-level-down:before { + content: "\f149"; +} + +.fa-person-falling-burst:before { + content: "\e547"; +} + +.fa-award:before { + content: "\f559"; +} + +.fa-ticket-alt:before, +.fa-ticket-simple:before { + content: "\f3ff"; +} + +.fa-building:before { + content: "\f1ad"; +} + +.fa-angle-double-left:before, +.fa-angles-left:before { + content: "\f100"; +} + +.fa-qrcode:before { + content: "\f029"; +} + +.fa-clock-rotate-left:before, +.fa-history:before { + content: "\f1da"; +} + +.fa-face-grin-beam-sweat:before, +.fa-grin-beam-sweat:before { + content: "\f583"; +} + +.fa-arrow-right-from-file:before, +.fa-file-export:before { + content: "\f56e"; +} + +.fa-shield-blank:before, +.fa-shield:before { + content: "\f132"; +} + +.fa-arrow-up-short-wide:before, +.fa-sort-amount-up-alt:before { + content: "\f885"; +} + +.fa-house-medical:before { + content: "\e3b2"; +} + +.fa-golf-ball-tee:before, +.fa-golf-ball:before { + content: "\f450"; +} + +.fa-chevron-circle-left:before, +.fa-circle-chevron-left:before { + content: "\f137"; +} + +.fa-house-chimney-window:before { + content: "\e00d"; +} + +.fa-pen-nib:before { + content: "\f5ad"; +} + +.fa-tent-arrow-turn-left:before { + content: "\e580"; +} + +.fa-tents:before { + content: "\e582"; +} + +.fa-magic:before, +.fa-wand-magic:before { + content: "\f0d0"; +} + +.fa-dog:before { + content: "\f6d3"; +} + +.fa-carrot:before { + content: "\f787"; +} + +.fa-moon:before { + content: "\f186"; +} + +.fa-wine-glass-alt:before, +.fa-wine-glass-empty:before { + content: "\f5ce"; +} + +.fa-cheese:before { + content: "\f7ef"; +} + +.fa-yin-yang:before { + content: "\f6ad"; +} + +.fa-music:before { + content: "\f001"; +} + +.fa-code-commit:before { + content: "\f386"; +} + +.fa-temperature-low:before { + content: "\f76b"; +} + +.fa-biking:before, +.fa-person-biking:before { + content: "\f84a"; +} + +.fa-broom:before { + content: "\f51a"; +} + +.fa-shield-heart:before { + content: "\e574"; +} + +.fa-gopuram:before { + content: "\f664"; +} + +.fa-earth-oceania:before, +.fa-globe-oceania:before { + content: "\e47b"; +} + +.fa-square-xmark:before, +.fa-times-square:before, +.fa-xmark-square:before { + content: "\f2d3"; +} + +.fa-hashtag:before { + content: "\23"; +} + +.fa-expand-alt:before, +.fa-up-right-and-down-left-from-center:before { + content: "\f424"; +} + +.fa-oil-can:before { + content: "\f613"; +} + +.fa-t:before { + content: "\54"; +} + +.fa-hippo:before { + content: "\f6ed"; +} + +.fa-chart-column:before { + content: "\e0e3"; +} + +.fa-infinity:before { + content: "\f534"; +} + +.fa-vial-circle-check:before { + content: "\e596"; +} + +.fa-person-arrow-down-to-line:before { + content: "\e538"; +} + +.fa-voicemail:before { + content: "\f897"; +} + +.fa-fan:before { + content: "\f863"; +} + +.fa-person-walking-luggage:before { + content: "\e554"; +} + +.fa-arrows-alt-v:before, +.fa-up-down:before { + content: "\f338"; +} + +.fa-cloud-moon-rain:before { + content: "\f73c"; +} + +.fa-calendar:before { + content: "\f133"; +} + +.fa-trailer:before { + content: "\e041"; +} + +.fa-bahai:before, +.fa-haykal:before { + content: "\f666"; +} + +.fa-sd-card:before { + content: "\f7c2"; +} + +.fa-dragon:before { + content: "\f6d5"; +} + +.fa-shoe-prints:before { + content: "\f54b"; +} + +.fa-circle-plus:before, +.fa-plus-circle:before { + content: "\f055"; +} + +.fa-face-grin-tongue-wink:before, +.fa-grin-tongue-wink:before { + content: "\f58b"; +} + +.fa-hand-holding:before { + content: "\f4bd"; +} + +.fa-plug-circle-exclamation:before { + content: "\e55d"; +} + +.fa-chain-broken:before, +.fa-chain-slash:before, +.fa-link-slash:before, +.fa-unlink:before { + content: "\f127"; +} + +.fa-clone:before { + content: "\f24d"; +} + +.fa-person-walking-arrow-loop-left:before { + content: "\e551"; +} + +.fa-arrow-up-z-a:before, +.fa-sort-alpha-up-alt:before { + content: "\f882"; +} + +.fa-fire-alt:before, +.fa-fire-flame-curved:before { + content: "\f7e4"; +} + +.fa-tornado:before { + content: "\f76f"; +} + +.fa-file-circle-plus:before { + content: "\e494"; +} + +.fa-book-quran:before, +.fa-quran:before { + content: "\f687"; +} + +.fa-anchor:before { + content: "\f13d"; +} + +.fa-border-all:before { + content: "\f84c"; +} + +.fa-angry:before, +.fa-face-angry:before { + content: "\f556"; +} + +.fa-cookie-bite:before { + content: "\f564"; +} + +.fa-arrow-trend-down:before { + content: "\e097"; +} + +.fa-feed:before, +.fa-rss:before { + content: "\f09e"; +} + +.fa-draw-polygon:before { + content: "\f5ee"; +} + +.fa-balance-scale:before, +.fa-scale-balanced:before { + content: "\f24e"; +} + +.fa-gauge-simple-high:before, +.fa-tachometer-fast:before, +.fa-tachometer:before { + content: "\f62a"; +} + +.fa-shower:before { + content: "\f2cc"; +} + +.fa-desktop-alt:before, +.fa-desktop:before { + content: "\f390"; +} + +.fa-m:before { + content: "\4d"; +} + +.fa-table-list:before, +.fa-th-list:before { + content: "\f00b"; +} + +.fa-comment-sms:before, +.fa-sms:before { + content: "\f7cd"; +} + +.fa-book:before { + content: "\f02d"; +} + +.fa-user-plus:before { + content: "\f234"; +} + +.fa-check:before { + content: "\f00c"; +} + +.fa-battery-4:before, +.fa-battery-three-quarters:before { + content: "\f241"; +} + +.fa-house-circle-check:before { + content: "\e509"; +} + +.fa-angle-left:before { + content: "\f104"; +} + +.fa-diagram-successor:before { + content: "\e47a"; +} + +.fa-truck-arrow-right:before { + content: "\e58b"; +} + +.fa-arrows-split-up-and-left:before { + content: "\e4bc"; +} + +.fa-fist-raised:before, +.fa-hand-fist:before { + content: "\f6de"; +} + +.fa-cloud-moon:before { + content: "\f6c3"; +} + +.fa-briefcase:before { + content: "\f0b1"; +} + +.fa-person-falling:before { + content: "\e546"; +} + +.fa-image-portrait:before, +.fa-portrait:before { + content: "\f3e0"; +} + +.fa-user-tag:before { + content: "\f507"; +} + +.fa-rug:before { + content: "\e569"; +} + +.fa-earth-europe:before, +.fa-globe-europe:before { + content: "\f7a2"; +} + +.fa-cart-flatbed-suitcase:before, +.fa-luggage-cart:before { + content: "\f59d"; +} + +.fa-rectangle-times:before, +.fa-rectangle-xmark:before, +.fa-times-rectangle:before, +.fa-window-close:before { + content: "\f410"; +} + +.fa-baht-sign:before { + content: "\e0ac"; +} + +.fa-book-open:before { + content: "\f518"; +} + +.fa-book-journal-whills:before, +.fa-journal-whills:before { + content: "\f66a"; +} + +.fa-handcuffs:before { + content: "\e4f8"; +} + +.fa-exclamation-triangle:before, +.fa-triangle-exclamation:before, +.fa-warning:before { + content: "\f071"; +} + +.fa-database:before { + content: "\f1c0"; +} + +.fa-arrow-turn-right:before, +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} + +.fa-bottle-droplet:before { + content: "\e4c4"; +} + +.fa-mask-face:before { + content: "\e1d7"; +} + +.fa-hill-rockslide:before { + content: "\e508"; +} + +.fa-exchange-alt:before, +.fa-right-left:before { + content: "\f362"; +} + +.fa-paper-plane:before { + content: "\f1d8"; +} + +.fa-road-circle-exclamation:before { + content: "\e565"; +} + +.fa-dungeon:before { + content: "\f6d9"; +} + +.fa-align-right:before { + content: "\f038"; +} + +.fa-money-bill-1-wave:before, +.fa-money-bill-wave-alt:before { + content: "\f53b"; +} + +.fa-life-ring:before { + content: "\f1cd"; +} + +.fa-hands:before, +.fa-sign-language:before, +.fa-signing:before { + content: "\f2a7"; +} + +.fa-calendar-day:before { + content: "\f783"; +} + +.fa-ladder-water:before, +.fa-swimming-pool:before, +.fa-water-ladder:before { + content: "\f5c5"; +} + +.fa-arrows-up-down:before, +.fa-arrows-v:before { + content: "\f07d"; +} + +.fa-face-grimace:before, +.fa-grimace:before { + content: "\f57f"; +} + +.fa-wheelchair-alt:before, +.fa-wheelchair-move:before { + content: "\e2ce"; +} + +.fa-level-down-alt:before, +.fa-turn-down:before { + content: "\f3be"; +} + +.fa-person-walking-arrow-right:before { + content: "\e552"; +} + +.fa-envelope-square:before, +.fa-square-envelope:before { + content: "\f199"; +} + +.fa-dice:before { + content: "\f522"; +} + +.fa-bowling-ball:before { + content: "\f436"; +} + +.fa-brain:before { + content: "\f5dc"; +} + +.fa-band-aid:before, +.fa-bandage:before { + content: "\f462"; +} + +.fa-calendar-minus:before { + content: "\f272"; +} + +.fa-circle-xmark:before, +.fa-times-circle:before, +.fa-xmark-circle:before { + content: "\f057"; +} + +.fa-gifts:before { + content: "\f79c"; +} + +.fa-hotel:before { + content: "\f594"; +} + +.fa-earth-asia:before, +.fa-globe-asia:before { + content: "\f57e"; +} + +.fa-id-card-alt:before, +.fa-id-card-clip:before { + content: "\f47f"; +} + +.fa-magnifying-glass-plus:before, +.fa-search-plus:before { + content: "\f00e"; +} + +.fa-thumbs-up:before { + content: "\f164"; +} + +.fa-user-clock:before { + content: "\f4fd"; +} + +.fa-allergies:before, +.fa-hand-dots:before { + content: "\f461"; +} + +.fa-file-invoice:before { + content: "\f570"; +} + +.fa-window-minimize:before { + content: "\f2d1"; +} + +.fa-coffee:before, +.fa-mug-saucer:before { + content: "\f0f4"; +} + +.fa-brush:before { + content: "\f55d"; +} + +.fa-mask:before { + content: "\f6fa"; +} + +.fa-magnifying-glass-minus:before, +.fa-search-minus:before { + content: "\f010"; +} + +.fa-ruler-vertical:before { + content: "\f548"; +} + +.fa-user-alt:before, +.fa-user-large:before { + content: "\f406"; +} + +.fa-train-tram:before { + content: "\e5b4"; +} + +.fa-user-nurse:before { + content: "\f82f"; +} + +.fa-syringe:before { + content: "\f48e"; +} + +.fa-cloud-sun:before { + content: "\f6c4"; +} + +.fa-stopwatch-20:before { + content: "\e06f"; +} + +.fa-square-full:before { + content: "\f45c"; +} + +.fa-magnet:before { + content: "\f076"; +} + +.fa-jar:before { + content: "\e516"; +} + +.fa-note-sticky:before, +.fa-sticky-note:before { + content: "\f249"; +} + +.fa-bug-slash:before { + content: "\e490"; +} + +.fa-arrow-up-from-water-pump:before { + content: "\e4b6"; +} + +.fa-bone:before { + content: "\f5d7"; +} + +.fa-user-injured:before { + content: "\f728"; +} + +.fa-face-sad-tear:before, +.fa-sad-tear:before { + content: "\f5b4"; +} + +.fa-plane:before { + content: "\f072"; +} + +.fa-tent-arrows-down:before { + content: "\e581"; +} + +.fa-exclamation:before { + content: "\21"; +} + +.fa-arrows-spin:before { + content: "\e4bb"; +} + +.fa-print:before { + content: "\f02f"; +} + +.fa-try:before, +.fa-turkish-lira-sign:before, +.fa-turkish-lira:before { + content: "\e2bb"; +} + +.fa-dollar-sign:before, +.fa-dollar:before, +.fa-usd:before { + content: "\24"; +} + +.fa-x:before { + content: "\58"; +} + +.fa-magnifying-glass-dollar:before, +.fa-search-dollar:before { + content: "\f688"; +} + +.fa-users-cog:before, +.fa-users-gear:before { + content: "\f509"; +} + +.fa-person-military-pointing:before { + content: "\e54a"; +} + +.fa-bank:before, +.fa-building-columns:before, +.fa-institution:before, +.fa-museum:before, +.fa-university:before { + content: "\f19c"; +} + +.fa-umbrella:before { + content: "\f0e9"; +} + +.fa-trowel:before { + content: "\e589"; +} + +.fa-d:before { + content: "\44"; +} + +.fa-stapler:before { + content: "\e5af"; +} + +.fa-masks-theater:before, +.fa-theater-masks:before { + content: "\f630"; +} + +.fa-kip-sign:before { + content: "\e1c4"; +} + +.fa-hand-point-left:before { + content: "\f0a5"; +} + +.fa-handshake-alt:before, +.fa-handshake-simple:before { + content: "\f4c6"; +} + +.fa-fighter-jet:before, +.fa-jet-fighter:before { + content: "\f0fb"; +} + +.fa-share-alt-square:before, +.fa-square-share-nodes:before { + content: "\f1e1"; +} + +.fa-barcode:before { + content: "\f02a"; +} + +.fa-plus-minus:before { + content: "\e43c"; +} + +.fa-video-camera:before, +.fa-video:before { + content: "\f03d"; +} + +.fa-graduation-cap:before, +.fa-mortar-board:before { + content: "\f19d"; +} + +.fa-hand-holding-medical:before { + content: "\e05c"; +} + +.fa-person-circle-check:before { + content: "\e53e"; +} + +.fa-level-up-alt:before, +.fa-turn-up:before { + content: "\f3bf"; +} + +.fa-sr-only, +.fa-sr-only-focusable:not(:focus), +.sr-only, +.sr-only-focusable:not(:focus) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +:host, +:root { + --fa-style-family-brands: "Font Awesome 6 Brands"; + --fa-font-brands: normal 400 1em/1 "Font Awesome 6 Brands"; +} + +@font-face { + font-family: "Font Awesome 6 Brands"; + font-style: normal; + font-weight: 400; + font-display: block; + src: + url(./webfonts/fa-brands-400.woff2) format("woff2"), + url(./webfonts/fa-brands-400.ttf) format("truetype"); +} + +.fa-brands, +.fab { + font-weight: 400; +} + +.fa-monero:before { + content: "\f3d0"; +} + +.fa-hooli:before { + content: "\f427"; +} + +.fa-yelp:before { + content: "\f1e9"; +} + +.fa-cc-visa:before { + content: "\f1f0"; +} + +.fa-lastfm:before { + content: "\f202"; +} + +.fa-shopware:before { + content: "\f5b5"; +} + +.fa-creative-commons-nc:before { + content: "\f4e8"; +} + +.fa-aws:before { + content: "\f375"; +} + +.fa-redhat:before { + content: "\f7bc"; +} + +.fa-yoast:before { + content: "\f2b1"; +} + +.fa-cloudflare:before { + content: "\e07d"; +} + +.fa-ups:before { + content: "\f7e0"; +} + +.fa-wpexplorer:before { + content: "\f2de"; +} + +.fa-dyalog:before { + content: "\f399"; +} + +.fa-bity:before { + content: "\f37a"; +} + +.fa-stackpath:before { + content: "\f842"; +} + +.fa-buysellads:before { + content: "\f20d"; +} + +.fa-first-order:before { + content: "\f2b0"; +} + +.fa-modx:before { + content: "\f285"; +} + +.fa-guilded:before { + content: "\e07e"; +} + +.fa-vnv:before { + content: "\f40b"; +} + +.fa-js-square:before, +.fa-square-js:before { + content: "\f3b9"; +} + +.fa-microsoft:before { + content: "\f3ca"; +} + +.fa-qq:before { + content: "\f1d6"; +} + +.fa-orcid:before { + content: "\f8d2"; +} + +.fa-java:before { + content: "\f4e4"; +} + +.fa-invision:before { + content: "\f7b0"; +} + +.fa-creative-commons-pd-alt:before { + content: "\f4ed"; +} + +.fa-centercode:before { + content: "\f380"; +} + +.fa-glide-g:before { + content: "\f2a6"; +} + +.fa-drupal:before { + content: "\f1a9"; +} + +.fa-hire-a-helper:before { + content: "\f3b0"; +} + +.fa-creative-commons-by:before { + content: "\f4e7"; +} + +.fa-unity:before { + content: "\e049"; +} + +.fa-whmcs:before { + content: "\f40d"; +} + +.fa-rocketchat:before { + content: "\f3e8"; +} + +.fa-vk:before { + content: "\f189"; +} + +.fa-untappd:before { + content: "\f405"; +} + +.fa-mailchimp:before { + content: "\f59e"; +} + +.fa-css3-alt:before { + content: "\f38b"; +} + +.fa-reddit-square:before, +.fa-square-reddit:before { + content: "\f1a2"; +} + +.fa-vimeo-v:before { + content: "\f27d"; +} + +.fa-contao:before { + content: "\f26d"; +} + +.fa-square-font-awesome:before { + content: "\e5ad"; +} + +.fa-deskpro:before { + content: "\f38f"; +} + +.fa-sistrix:before { + content: "\f3ee"; +} + +.fa-instagram-square:before, +.fa-square-instagram:before { + content: "\e055"; +} + +.fa-battle-net:before { + content: "\f835"; +} + +.fa-the-red-yeti:before { + content: "\f69d"; +} + +.fa-hacker-news-square:before, +.fa-square-hacker-news:before { + content: "\f3af"; +} + +.fa-edge:before { + content: "\f282"; +} + +.fa-napster:before { + content: "\f3d2"; +} + +.fa-snapchat-square:before, +.fa-square-snapchat:before { + content: "\f2ad"; +} + +.fa-google-plus-g:before { + content: "\f0d5"; +} + +.fa-artstation:before { + content: "\f77a"; +} + +.fa-markdown:before { + content: "\f60f"; +} + +.fa-sourcetree:before { + content: "\f7d3"; +} + +.fa-google-plus:before { + content: "\f2b3"; +} + +.fa-diaspora:before { + content: "\f791"; +} + +.fa-foursquare:before { + content: "\f180"; +} + +.fa-stack-overflow:before { + content: "\f16c"; +} + +.fa-github-alt:before { + content: "\f113"; +} + +.fa-phoenix-squadron:before { + content: "\f511"; +} + +.fa-pagelines:before { + content: "\f18c"; +} + +.fa-algolia:before { + content: "\f36c"; +} + +.fa-red-river:before { + content: "\f3e3"; +} + +.fa-creative-commons-sa:before { + content: "\f4ef"; +} + +.fa-safari:before { + content: "\f267"; +} + +.fa-google:before { + content: "\f1a0"; +} + +.fa-font-awesome-alt:before, +.fa-square-font-awesome-stroke:before { + content: "\f35c"; +} + +.fa-atlassian:before { + content: "\f77b"; +} + +.fa-linkedin-in:before { + content: "\f0e1"; +} + +.fa-digital-ocean:before { + content: "\f391"; +} + +.fa-nimblr:before { + content: "\f5a8"; +} + +.fa-chromecast:before { + content: "\f838"; +} + +.fa-evernote:before { + content: "\f839"; +} + +.fa-hacker-news:before { + content: "\f1d4"; +} + +.fa-creative-commons-sampling:before { + content: "\f4f0"; +} + +.fa-adversal:before { + content: "\f36a"; +} + +.fa-creative-commons:before { + content: "\f25e"; +} + +.fa-watchman-monitoring:before { + content: "\e087"; +} + +.fa-fonticons:before { + content: "\f280"; +} + +.fa-weixin:before { + content: "\f1d7"; +} + +.fa-shirtsinbulk:before { + content: "\f214"; +} + +.fa-codepen:before { + content: "\f1cb"; +} + +.fa-git-alt:before { + content: "\f841"; +} + +.fa-lyft:before { + content: "\f3c3"; +} + +.fa-rev:before { + content: "\f5b2"; +} + +.fa-windows:before { + content: "\f17a"; +} + +.fa-wizards-of-the-coast:before { + content: "\f730"; +} + +.fa-square-viadeo:before, +.fa-viadeo-square:before { + content: "\f2aa"; +} + +.fa-meetup:before { + content: "\f2e0"; +} + +.fa-centos:before { + content: "\f789"; +} + +.fa-adn:before { + content: "\f170"; +} + +.fa-cloudsmith:before { + content: "\f384"; +} + +.fa-pied-piper-alt:before { + content: "\f1a8"; +} + +.fa-dribbble-square:before, +.fa-square-dribbble:before { + content: "\f397"; +} + +.fa-codiepie:before { + content: "\f284"; +} + +.fa-node:before { + content: "\f419"; +} + +.fa-mix:before { + content: "\f3cb"; +} + +.fa-steam:before { + content: "\f1b6"; +} + +.fa-cc-apple-pay:before { + content: "\f416"; +} + +.fa-scribd:before { + content: "\f28a"; +} + +.fa-openid:before { + content: "\f19b"; +} + +.fa-instalod:before { + content: "\e081"; +} + +.fa-expeditedssl:before { + content: "\f23e"; +} + +.fa-sellcast:before { + content: "\f2da"; +} + +.fa-square-twitter:before, +.fa-twitter-square:before { + content: "\f081"; +} + +.fa-r-project:before { + content: "\f4f7"; +} + +.fa-delicious:before { + content: "\f1a5"; +} + +.fa-freebsd:before { + content: "\f3a4"; +} + +.fa-vuejs:before { + content: "\f41f"; +} + +.fa-accusoft:before { + content: "\f369"; +} + +.fa-ioxhost:before { + content: "\f208"; +} + +.fa-fonticons-fi:before { + content: "\f3a2"; +} + +.fa-app-store:before { + content: "\f36f"; +} + +.fa-cc-mastercard:before { + content: "\f1f1"; +} + +.fa-itunes-note:before { + content: "\f3b5"; +} + +.fa-golang:before { + content: "\e40f"; +} + +.fa-kickstarter:before { + content: "\f3bb"; +} + +.fa-grav:before { + content: "\f2d6"; +} + +.fa-weibo:before { + content: "\f18a"; +} + +.fa-uncharted:before { + content: "\e084"; +} + +.fa-firstdraft:before { + content: "\f3a1"; +} + +.fa-square-youtube:before, +.fa-youtube-square:before { + content: "\f431"; +} + +.fa-wikipedia-w:before { + content: "\f266"; +} + +.fa-rendact:before, +.fa-wpressr:before { + content: "\f3e4"; +} + +.fa-angellist:before { + content: "\f209"; +} + +.fa-galactic-republic:before { + content: "\f50c"; +} + +.fa-nfc-directional:before { + content: "\e530"; +} + +.fa-skype:before { + content: "\f17e"; +} + +.fa-joget:before { + content: "\f3b7"; +} + +.fa-fedora:before { + content: "\f798"; +} + +.fa-stripe-s:before { + content: "\f42a"; +} + +.fa-meta:before { + content: "\e49b"; +} + +.fa-laravel:before { + content: "\f3bd"; +} + +.fa-hotjar:before { + content: "\f3b1"; +} + +.fa-bluetooth-b:before { + content: "\f294"; +} + +.fa-sticker-mule:before { + content: "\f3f7"; +} + +.fa-creative-commons-zero:before { + content: "\f4f3"; +} + +.fa-hips:before { + content: "\f452"; +} + +.fa-behance:before { + content: "\f1b4"; +} + +.fa-reddit:before { + content: "\f1a1"; +} + +.fa-discord:before { + content: "\f392"; +} + +.fa-chrome:before { + content: "\f268"; +} + +.fa-app-store-ios:before { + content: "\f370"; +} + +.fa-cc-discover:before { + content: "\f1f2"; +} + +.fa-wpbeginner:before { + content: "\f297"; +} + +.fa-confluence:before { + content: "\f78d"; +} + +.fa-mdb:before { + content: "\f8ca"; +} + +.fa-dochub:before { + content: "\f394"; +} + +.fa-accessible-icon:before { + content: "\f368"; +} + +.fa-ebay:before { + content: "\f4f4"; +} + +.fa-amazon:before { + content: "\f270"; +} + +.fa-unsplash:before { + content: "\e07c"; +} + +.fa-yarn:before { + content: "\f7e3"; +} + +.fa-square-steam:before, +.fa-steam-square:before { + content: "\f1b7"; +} + +.fa-500px:before { + content: "\f26e"; +} + +.fa-square-vimeo:before, +.fa-vimeo-square:before { + content: "\f194"; +} + +.fa-asymmetrik:before { + content: "\f372"; +} + +.fa-font-awesome-flag:before, +.fa-font-awesome-logo-full:before, +.fa-font-awesome:before { + content: "\f2b4"; +} + +.fa-gratipay:before { + content: "\f184"; +} + +.fa-apple:before { + content: "\f179"; +} + +.fa-hive:before { + content: "\e07f"; +} + +.fa-gitkraken:before { + content: "\f3a6"; +} + +.fa-keybase:before { + content: "\f4f5"; +} + +.fa-apple-pay:before { + content: "\f415"; +} + +.fa-padlet:before { + content: "\e4a0"; +} + +.fa-amazon-pay:before { + content: "\f42c"; +} + +.fa-github-square:before, +.fa-square-github:before { + content: "\f092"; +} + +.fa-stumbleupon:before { + content: "\f1a4"; +} + +.fa-fedex:before { + content: "\f797"; +} + +.fa-phoenix-framework:before { + content: "\f3dc"; +} + +.fa-shopify:before { + content: "\e057"; +} + +.fa-neos:before { + content: "\f612"; +} + +.fa-hackerrank:before { + content: "\f5f7"; +} + +.fa-researchgate:before { + content: "\f4f8"; +} + +.fa-swift:before { + content: "\f8e1"; +} + +.fa-angular:before { + content: "\f420"; +} + +.fa-speakap:before { + content: "\f3f3"; +} + +.fa-angrycreative:before { + content: "\f36e"; +} + +.fa-y-combinator:before { + content: "\f23b"; +} + +.fa-empire:before { + content: "\f1d1"; +} + +.fa-envira:before { + content: "\f299"; +} + +.fa-gitlab-square:before, +.fa-square-gitlab:before { + content: "\e5ae"; +} + +.fa-studiovinari:before { + content: "\f3f8"; +} + +.fa-pied-piper:before { + content: "\f2ae"; +} + +.fa-wordpress:before { + content: "\f19a"; +} + +.fa-product-hunt:before { + content: "\f288"; +} + +.fa-firefox:before { + content: "\f269"; +} + +.fa-linode:before { + content: "\f2b8"; +} + +.fa-goodreads:before { + content: "\f3a8"; +} + +.fa-odnoklassniki-square:before, +.fa-square-odnoklassniki:before { + content: "\f264"; +} + +.fa-jsfiddle:before { + content: "\f1cc"; +} + +.fa-sith:before { + content: "\f512"; +} + +.fa-themeisle:before { + content: "\f2b2"; +} + +.fa-page4:before { + content: "\f3d7"; +} + +.fa-hashnode:before { + content: "\e499"; +} + +.fa-react:before { + content: "\f41b"; +} + +.fa-cc-paypal:before { + content: "\f1f4"; +} + +.fa-squarespace:before { + content: "\f5be"; +} + +.fa-cc-stripe:before { + content: "\f1f5"; +} + +.fa-creative-commons-share:before { + content: "\f4f2"; +} + +.fa-bitcoin:before { + content: "\f379"; +} + +.fa-keycdn:before { + content: "\f3ba"; +} + +.fa-opera:before { + content: "\f26a"; +} + +.fa-itch-io:before { + content: "\f83a"; +} + +.fa-umbraco:before { + content: "\f8e8"; +} + +.fa-galactic-senate:before { + content: "\f50d"; +} + +.fa-ubuntu:before { + content: "\f7df"; +} + +.fa-draft2digital:before { + content: "\f396"; +} + +.fa-stripe:before { + content: "\f429"; +} + +.fa-houzz:before { + content: "\f27c"; +} + +.fa-gg:before { + content: "\f260"; +} + +.fa-dhl:before { + content: "\f790"; +} + +.fa-pinterest-square:before, +.fa-square-pinterest:before { + content: "\f0d3"; +} + +.fa-xing:before { + content: "\f168"; +} + +.fa-blackberry:before { + content: "\f37b"; +} + +.fa-creative-commons-pd:before { + content: "\f4ec"; +} + +.fa-playstation:before { + content: "\f3df"; +} + +.fa-quinscape:before { + content: "\f459"; +} + +.fa-less:before { + content: "\f41d"; +} + +.fa-blogger-b:before { + content: "\f37d"; +} + +.fa-opencart:before { + content: "\f23d"; +} + +.fa-vine:before { + content: "\f1ca"; +} + +.fa-paypal:before { + content: "\f1ed"; +} + +.fa-gitlab:before { + content: "\f296"; +} + +.fa-typo3:before { + content: "\f42b"; +} + +.fa-reddit-alien:before { + content: "\f281"; +} + +.fa-yahoo:before { + content: "\f19e"; +} + +.fa-dailymotion:before { + content: "\e052"; +} + +.fa-affiliatetheme:before { + content: "\f36b"; +} + +.fa-pied-piper-pp:before { + content: "\f1a7"; +} + +.fa-bootstrap:before { + content: "\f836"; +} + +.fa-odnoklassniki:before { + content: "\f263"; +} + +.fa-nfc-symbol:before { + content: "\e531"; +} + +.fa-ethereum:before { + content: "\f42e"; +} + +.fa-speaker-deck:before { + content: "\f83c"; +} + +.fa-creative-commons-nc-eu:before { + content: "\f4e9"; +} + +.fa-patreon:before { + content: "\f3d9"; +} + +.fa-avianex:before { + content: "\f374"; +} + +.fa-ello:before { + content: "\f5f1"; +} + +.fa-gofore:before { + content: "\f3a7"; +} + +.fa-bimobject:before { + content: "\f378"; +} + +.fa-facebook-f:before { + content: "\f39e"; +} + +.fa-google-plus-square:before, +.fa-square-google-plus:before { + content: "\f0d4"; +} + +.fa-mandalorian:before { + content: "\f50f"; +} + +.fa-first-order-alt:before { + content: "\f50a"; +} + +.fa-osi:before { + content: "\f41a"; +} + +.fa-google-wallet:before { + content: "\f1ee"; +} + +.fa-d-and-d-beyond:before { + content: "\f6ca"; +} + +.fa-periscope:before { + content: "\f3da"; +} + +.fa-fulcrum:before { + content: "\f50b"; +} + +.fa-cloudscale:before { + content: "\f383"; +} + +.fa-forumbee:before { + content: "\f211"; +} + +.fa-mizuni:before { + content: "\f3cc"; +} + +.fa-schlix:before { + content: "\f3ea"; +} + +.fa-square-xing:before, +.fa-xing-square:before { + content: "\f169"; +} + +.fa-bandcamp:before { + content: "\f2d5"; +} + +.fa-wpforms:before { + content: "\f298"; +} + +.fa-cloudversify:before { + content: "\f385"; +} + +.fa-usps:before { + content: "\f7e1"; +} + +.fa-megaport:before { + content: "\f5a3"; +} + +.fa-magento:before { + content: "\f3c4"; +} + +.fa-spotify:before { + content: "\f1bc"; +} + +.fa-optin-monster:before { + content: "\f23c"; +} + +.fa-fly:before { + content: "\f417"; +} + +.fa-aviato:before { + content: "\f421"; +} + +.fa-itunes:before { + content: "\f3b4"; +} + +.fa-cuttlefish:before { + content: "\f38c"; +} + +.fa-blogger:before { + content: "\f37c"; +} + +.fa-flickr:before { + content: "\f16e"; +} + +.fa-viber:before { + content: "\f409"; +} + +.fa-soundcloud:before { + content: "\f1be"; +} + +.fa-digg:before { + content: "\f1a6"; +} + +.fa-tencent-weibo:before { + content: "\f1d5"; +} + +.fa-symfony:before { + content: "\f83d"; +} + +.fa-maxcdn:before { + content: "\f136"; +} + +.fa-etsy:before { + content: "\f2d7"; +} + +.fa-facebook-messenger:before { + content: "\f39f"; +} + +.fa-audible:before { + content: "\f373"; +} + +.fa-think-peaks:before { + content: "\f731"; +} + +.fa-bilibili:before { + content: "\e3d9"; +} + +.fa-erlang:before { + content: "\f39d"; +} + +.fa-cotton-bureau:before { + content: "\f89e"; +} + +.fa-dashcube:before { + content: "\f210"; +} + +.fa-42-group:before, +.fa-innosoft:before { + content: "\e080"; +} + +.fa-stack-exchange:before { + content: "\f18d"; +} + +.fa-elementor:before { + content: "\f430"; +} + +.fa-pied-piper-square:before, +.fa-square-pied-piper:before { + content: "\e01e"; +} + +.fa-creative-commons-nd:before { + content: "\f4eb"; +} + +.fa-palfed:before { + content: "\f3d8"; +} + +.fa-superpowers:before { + content: "\f2dd"; +} + +.fa-resolving:before { + content: "\f3e7"; +} + +.fa-xbox:before { + content: "\f412"; +} + +.fa-searchengin:before { + content: "\f3eb"; +} + +.fa-tiktok:before { + content: "\e07b"; +} + +.fa-facebook-square:before, +.fa-square-facebook:before { + content: "\f082"; +} + +.fa-renren:before { + content: "\f18b"; +} + +.fa-linux:before { + content: "\f17c"; +} + +.fa-glide:before { + content: "\f2a5"; +} + +.fa-linkedin:before { + content: "\f08c"; +} + +.fa-hubspot:before { + content: "\f3b2"; +} + +.fa-deploydog:before { + content: "\f38e"; +} + +.fa-twitch:before { + content: "\f1e8"; +} + +.fa-ravelry:before { + content: "\f2d9"; +} + +.fa-mixer:before { + content: "\e056"; +} + +.fa-lastfm-square:before, +.fa-square-lastfm:before { + content: "\f203"; +} + +.fa-vimeo:before { + content: "\f40a"; +} + +.fa-mendeley:before { + content: "\f7b3"; +} + +.fa-uniregistry:before { + content: "\f404"; +} + +.fa-figma:before { + content: "\f799"; +} + +.fa-creative-commons-remix:before { + content: "\f4ee"; +} + +.fa-cc-amazon-pay:before { + content: "\f42d"; +} + +.fa-dropbox:before { + content: "\f16b"; +} + +.fa-instagram:before { + content: "\f16d"; +} + +.fa-cmplid:before { + content: "\e360"; +} + +.fa-facebook:before { + content: "\f09a"; +} + +.fa-gripfire:before { + content: "\f3ac"; +} + +.fa-jedi-order:before { + content: "\f50e"; +} + +.fa-uikit:before { + content: "\f403"; +} + +.fa-fort-awesome-alt:before { + content: "\f3a3"; +} + +.fa-phabricator:before { + content: "\f3db"; +} + +.fa-ussunnah:before { + content: "\f407"; +} + +.fa-earlybirds:before { + content: "\f39a"; +} + +.fa-trade-federation:before { + content: "\f513"; +} + +.fa-autoprefixer:before { + content: "\f41c"; +} + +.fa-whatsapp:before { + content: "\f232"; +} + +.fa-slideshare:before { + content: "\f1e7"; +} + +.fa-google-play:before { + content: "\f3ab"; +} + +.fa-viadeo:before { + content: "\f2a9"; +} + +.fa-line:before { + content: "\f3c0"; +} + +.fa-google-drive:before { + content: "\f3aa"; +} + +.fa-servicestack:before { + content: "\f3ec"; +} + +.fa-simplybuilt:before { + content: "\f215"; +} + +.fa-bitbucket:before { + content: "\f171"; +} + +.fa-imdb:before { + content: "\f2d8"; +} + +.fa-deezer:before { + content: "\e077"; +} + +.fa-raspberry-pi:before { + content: "\f7bb"; +} + +.fa-jira:before { + content: "\f7b1"; +} + +.fa-docker:before { + content: "\f395"; +} + +.fa-screenpal:before { + content: "\e570"; +} + +.fa-bluetooth:before { + content: "\f293"; +} + +.fa-gitter:before { + content: "\f426"; +} + +.fa-d-and-d:before { + content: "\f38d"; +} + +.fa-microblog:before { + content: "\e01a"; +} + +.fa-cc-diners-club:before { + content: "\f24c"; +} + +.fa-gg-circle:before { + content: "\f261"; +} + +.fa-pied-piper-hat:before { + content: "\f4e5"; +} + +.fa-kickstarter-k:before { + content: "\f3bc"; +} + +.fa-yandex:before { + content: "\f413"; +} + +.fa-readme:before { + content: "\f4d5"; +} + +.fa-html5:before { + content: "\f13b"; +} + +.fa-sellsy:before { + content: "\f213"; +} + +.fa-sass:before { + content: "\f41e"; +} + +.fa-wirsindhandwerk:before, +.fa-wsh:before { + content: "\e2d0"; +} + +.fa-buromobelexperte:before { + content: "\f37f"; +} + +.fa-salesforce:before { + content: "\f83b"; +} + +.fa-octopus-deploy:before { + content: "\e082"; +} + +.fa-medapps:before { + content: "\f3c6"; +} + +.fa-ns8:before { + content: "\f3d5"; +} + +.fa-pinterest-p:before { + content: "\f231"; +} + +.fa-apper:before { + content: "\f371"; +} + +.fa-fort-awesome:before { + content: "\f286"; +} + +.fa-waze:before { + content: "\f83f"; +} + +.fa-cc-jcb:before { + content: "\f24b"; +} + +.fa-snapchat-ghost:before, +.fa-snapchat:before { + content: "\f2ab"; +} + +.fa-fantasy-flight-games:before { + content: "\f6dc"; +} + +.fa-rust:before { + content: "\e07a"; +} + +.fa-wix:before { + content: "\f5cf"; +} + +.fa-behance-square:before, +.fa-square-behance:before { + content: "\f1b5"; +} + +.fa-supple:before { + content: "\f3f9"; +} + +.fa-rebel:before { + content: "\f1d0"; +} + +.fa-css3:before { + content: "\f13c"; +} + +.fa-staylinked:before { + content: "\f3f5"; +} + +.fa-kaggle:before { + content: "\f5fa"; +} + +.fa-space-awesome:before { + content: "\e5ac"; +} + +.fa-deviantart:before { + content: "\f1bd"; +} + +.fa-cpanel:before { + content: "\f388"; +} + +.fa-goodreads-g:before { + content: "\f3a9"; +} + +.fa-git-square:before, +.fa-square-git:before { + content: "\f1d2"; +} + +.fa-square-tumblr:before, +.fa-tumblr-square:before { + content: "\f174"; +} + +.fa-trello:before { + content: "\f181"; +} + +.fa-creative-commons-nc-jp:before { + content: "\f4ea"; +} + +.fa-get-pocket:before { + content: "\f265"; +} + +.fa-perbyte:before { + content: "\e083"; +} + +.fa-grunt:before { + content: "\f3ad"; +} + +.fa-weebly:before { + content: "\f5cc"; +} + +.fa-connectdevelop:before { + content: "\f20e"; +} + +.fa-leanpub:before { + content: "\f212"; +} + +.fa-black-tie:before { + content: "\f27e"; +} + +.fa-themeco:before { + content: "\f5c6"; +} + +.fa-python:before { + content: "\f3e2"; +} + +.fa-android:before { + content: "\f17b"; +} + +.fa-bots:before { + content: "\e340"; +} + +.fa-free-code-camp:before { + content: "\f2c5"; +} + +.fa-hornbill:before { + content: "\f592"; +} + +.fa-js:before { + content: "\f3b8"; +} + +.fa-ideal:before { + content: "\e013"; +} + +.fa-git:before { + content: "\f1d3"; +} + +.fa-dev:before { + content: "\f6cc"; +} + +.fa-sketch:before { + content: "\f7c6"; +} + +.fa-yandex-international:before { + content: "\f414"; +} + +.fa-cc-amex:before { + content: "\f1f3"; +} + +.fa-uber:before { + content: "\f402"; +} + +.fa-github:before { + content: "\f09b"; +} + +.fa-php:before { + content: "\f457"; +} + +.fa-alipay:before { + content: "\f642"; +} + +.fa-youtube:before { + content: "\f167"; +} + +.fa-skyatlas:before { + content: "\f216"; +} + +.fa-firefox-browser:before { + content: "\e007"; +} + +.fa-replyd:before { + content: "\f3e6"; +} + +.fa-suse:before { + content: "\f7d6"; +} + +.fa-jenkins:before { + content: "\f3b6"; +} + +.fa-twitter:before { + content: "\f099"; +} + +.fa-rockrms:before { + content: "\f3e9"; +} + +.fa-pinterest:before { + content: "\f0d2"; +} + +.fa-buffer:before { + content: "\f837"; +} + +.fa-npm:before { + content: "\f3d4"; +} + +.fa-yammer:before { + content: "\f840"; +} + +.fa-btc:before { + content: "\f15a"; +} + +.fa-dribbble:before { + content: "\f17d"; +} + +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} + +.fa-internet-explorer:before { + content: "\f26b"; +} + +.fa-telegram-plane:before, +.fa-telegram:before { + content: "\f2c6"; +} + +.fa-old-republic:before { + content: "\f510"; +} + +.fa-square-whatsapp:before, +.fa-whatsapp-square:before { + content: "\f40c"; +} + +.fa-node-js:before { + content: "\f3d3"; +} + +.fa-edge-legacy:before { + content: "\e078"; +} + +.fa-slack-hash:before, +.fa-slack:before { + content: "\f198"; +} + +.fa-medrt:before { + content: "\f3c8"; +} + +.fa-usb:before { + content: "\f287"; +} + +.fa-tumblr:before { + content: "\f173"; +} + +.fa-vaadin:before { + content: "\f408"; +} + +.fa-quora:before { + content: "\f2c4"; +} + +.fa-reacteurope:before { + content: "\f75d"; +} + +.fa-medium-m:before, +.fa-medium:before { + content: "\f23a"; +} + +.fa-amilia:before { + content: "\f36d"; +} + +.fa-mixcloud:before { + content: "\f289"; +} + +.fa-flipboard:before { + content: "\f44d"; +} + +.fa-viacoin:before { + content: "\f237"; +} + +.fa-critical-role:before { + content: "\f6c9"; +} + +.fa-sitrox:before { + content: "\e44a"; +} + +.fa-discourse:before { + content: "\f393"; +} + +.fa-joomla:before { + content: "\f1aa"; +} + +.fa-mastodon:before { + content: "\f4f6"; +} + +.fa-airbnb:before { + content: "\f834"; +} + +.fa-wolf-pack-battalion:before { + content: "\f514"; +} + +.fa-buy-n-large:before { + content: "\f8a6"; +} + +.fa-gulp:before { + content: "\f3ae"; +} + +.fa-creative-commons-sampling-plus:before { + content: "\f4f1"; +} + +.fa-strava:before { + content: "\f428"; +} + +.fa-ember:before { + content: "\f423"; +} + +.fa-canadian-maple-leaf:before { + content: "\f785"; +} + +.fa-teamspeak:before { + content: "\f4f9"; +} + +.fa-pushed:before { + content: "\f3e1"; +} + +.fa-wordpress-simple:before { + content: "\f411"; +} + +.fa-nutritionix:before { + content: "\f3d6"; +} + +.fa-wodu:before { + content: "\e088"; +} + +.fa-google-pay:before { + content: "\e079"; +} + +.fa-intercom:before { + content: "\f7af"; +} + +.fa-zhihu:before { + content: "\f63f"; +} + +.fa-korvue:before { + content: "\f42f"; +} + +.fa-pix:before { + content: "\e43a"; +} + +.fa-steam-symbol:before { + content: "\f3f6"; +} + +:host, +:root { + --fa-font-regular: normal 400 1em/1 "Font Awesome 6 Free"; +} + +@font-face { + font-family: "Font Awesome 6 Free"; + font-style: normal; + font-weight: 400; + font-display: block; + src: + url(./webfonts/fa-regular-400.woff2) format("woff2"), + url(./webfonts/fa-regular-400.ttf) format("truetype"); +} + +.fa-regular, +.far { + font-weight: 400; +} + +:host, +:root { + --fa-style-family-classic: "Font Awesome 6 Free"; + --fa-font-solid: normal 900 1em/1 "Font Awesome 6 Free"; +} + +@font-face { + font-family: "Font Awesome 6 Free"; + font-style: normal; + font-weight: 900; + font-display: block; + src: + url(./webfonts/fa-solid-900.woff2) format("woff2"), + url(./webfonts/fa-solid-900.ttf) format("truetype"); +} + +.fa-solid, +.fas { + font-weight: 900; +} + +@font-face { + font-family: "Font Awesome 5 Brands"; + font-display: block; + font-weight: 400; + src: + url(./webfonts/fa-brands-400.woff2) format("woff2"), + url(./webfonts/fa-brands-400.ttf) format("truetype"); +} + +@font-face { + font-family: "Font Awesome 5 Free"; + font-display: block; + font-weight: 900; + src: + url(./webfonts/fa-solid-900.woff2) format("woff2"), + url(./webfonts/fa-solid-900.ttf) format("truetype"); +} + +@font-face { + font-family: "Font Awesome 5 Free"; + font-display: block; + font-weight: 400; + src: + url(./webfonts/fa-regular-400.woff2) format("woff2"), + url(./webfonts/fa-regular-400.ttf) format("truetype"); +} + +@font-face { + font-family: "FontAwesome"; + font-display: block; + src: + url(./webfonts/fa-solid-900.woff2) format("woff2"), + url(./webfonts/fa-solid-900.ttf) format("truetype"); +} + +@font-face { + font-family: "FontAwesome"; + font-display: block; + src: + url(./webfonts/fa-brands-400.woff2) format("woff2"), + url(./webfonts/fa-brands-400.ttf) format("truetype"); +} + +@font-face { + font-family: "FontAwesome"; + font-display: block; + src: + url(./webfonts/fa-regular-400.woff2) format("woff2"), + url(./webfonts/fa-regular-400.ttf) format("truetype"); + unicode-range: u+f003, u+f006, u+f014, u+f016-f017, u+f01a-f01b, u+f01d, u+f022, u+f03e, u+f044, u+f046, u+f05c-f05d, u+f06e, u+f070, u+f087-f088, u+f08a, + u+f094, u+f096-f097, u+f09d, u+f0a0, u+f0a2, u+f0a4-f0a7, u+f0c5, u+f0c7, u+f0e5-f0e6, u+f0eb, u+f0f6-f0f8, u+f10c, u+f114-f115, u+f118-f11a, u+f11c-f11d, + u+f133, u+f147, u+f14e, u+f150-f152, u+f185-f186, u+f18e, u+f190-f192, u+f196, u+f1c1-f1c9, u+f1d9, u+f1db, u+f1e3, u+f1ea, u+f1f7, u+f1f9, u+f20a, + u+f247-f248, u+f24a, u+f24d, u+f255-f25b, u+f25d, u+f271-f274, u+f278, u+f27b, u+f28c, u+f28e, u+f29c, u+f2b5, u+f2b7, u+f2ba, u+f2bc, u+f2be, u+f2c0-f2c1, + u+f2c3, u+f2d0, u+f2d2, u+f2d4, u+f2dc; +} + +@font-face { + font-family: "FontAwesome"; + font-display: block; + src: + url(./webfonts/fa-v4compatibility.woff2) format("woff2"), + url(./webfonts/fa-v4compatibility.ttf) format("truetype"); + unicode-range: u+f041, u+f047, u+f065-f066, u+f07d-f07e, u+f080, u+f08b, u+f08e, u+f090, u+f09a, u+f0ac, u+f0ae, u+f0b2, u+f0d0, u+f0d6, u+f0e4, u+f0ec, + u+f10a-f10b, u+f123, u+f13e, u+f148-f149, u+f14c, u+f156, u+f15e, u+f160-f161, u+f163, u+f175-f178, u+f195, u+f1f8, u+f219, u+f27a; +} diff --git a/static/styles/proxima.css b/static/styles/proxima.css new file mode 100644 index 0000000..123ae36 --- /dev/null +++ b/static/styles/proxima.css @@ -0,0 +1,54 @@ +@font-face { + font-family: "Ubiquity Nova"; + font-style: normal; + font-weight: 100; + src: url(./proxima/2B04A9_A_0.eot); + src: + url(./proxima/2B04A9_A_0.eot#iefix) format("embedded-opentype"), + url(./proxima/2B04A9_A_0.woff) format("woff"), + url(./proxima/2B04A9_A_0.ttf) format("truetype"); +} + +@font-face { + font-family: "Ubiquity Nova"; + font-style: normal; + font-weight: 200; + src: url(./proxima/2B04A9_B_0.eot); + src: + url(./proxima/2B04A9_B_0.eot#iefix) format("embedded-opentype"), + url(./proxima/2B04A9_B_0.woff) format("woff"), + url(./proxima/2B04A9_B_0.ttf) format("truetype"); +} + +@font-face { + font-family: "Ubiquity Nova"; + font-style: normal; + font-weight: 400; + src: url(./proxima/2B04A9_E_0.eot); + src: + url(./proxima/2B04A9_E_0.eot#iefix) format("embedded-opentype"), + url(./proxima/2B04A9_E_0.woff) format("woff"), + url(./proxima/2B04A9_E_0.ttf) format("truetype"); +} + +@font-face { + font-family: "Ubiquity Nova"; + font-style: italic; + font-weight: 400; + src: url(./proxima/2B04A9_C_0.eot); + src: + url(./proxima/2B04A9_C_0.eot#iefix) format("embedded-opentype"), + url(./proxima/2B04A9_C_0.woff) format("woff"), + url(./proxima/2B04A9_C_0.ttf) format("truetype"); +} + +@font-face { + font-family: "Ubiquity Nova"; + font-style: normal; + font-weight: 700; + src: url(./proxima/2B04A9_D_0.eot); + src: + url(./proxima/2B04A9_D_0.eot#iefix) format("embedded-opentype"), + url(./proxima/2B04A9_D_0.woff) format("woff"), + url(./proxima/2B04A9_D_0.ttf) format("truetype"); +} diff --git a/static/styles/proxima/2B04A9_A_0.eot b/static/styles/proxima/2B04A9_A_0.eot new file mode 100644 index 0000000..736c1c0 Binary files /dev/null and b/static/styles/proxima/2B04A9_A_0.eot differ diff --git a/static/styles/proxima/2B04A9_A_0.ttf b/static/styles/proxima/2B04A9_A_0.ttf new file mode 100644 index 0000000..3702fd6 Binary files /dev/null and b/static/styles/proxima/2B04A9_A_0.ttf differ diff --git a/static/styles/proxima/2B04A9_A_0.woff b/static/styles/proxima/2B04A9_A_0.woff new file mode 100644 index 0000000..b8e7802 Binary files /dev/null and b/static/styles/proxima/2B04A9_A_0.woff differ diff --git a/static/styles/proxima/2B04A9_B_0.eot b/static/styles/proxima/2B04A9_B_0.eot new file mode 100644 index 0000000..4f493c5 Binary files /dev/null and b/static/styles/proxima/2B04A9_B_0.eot differ diff --git a/static/styles/proxima/2B04A9_B_0.ttf b/static/styles/proxima/2B04A9_B_0.ttf new file mode 100644 index 0000000..48faa7a Binary files /dev/null and b/static/styles/proxima/2B04A9_B_0.ttf differ diff --git a/static/styles/proxima/2B04A9_B_0.woff b/static/styles/proxima/2B04A9_B_0.woff new file mode 100644 index 0000000..b022624 Binary files /dev/null and b/static/styles/proxima/2B04A9_B_0.woff differ diff --git a/static/styles/proxima/2B04A9_C_0.eot b/static/styles/proxima/2B04A9_C_0.eot new file mode 100644 index 0000000..940cd93 Binary files /dev/null and b/static/styles/proxima/2B04A9_C_0.eot differ diff --git a/static/styles/proxima/2B04A9_C_0.ttf b/static/styles/proxima/2B04A9_C_0.ttf new file mode 100644 index 0000000..815bc3e Binary files /dev/null and b/static/styles/proxima/2B04A9_C_0.ttf differ diff --git a/static/styles/proxima/2B04A9_C_0.woff b/static/styles/proxima/2B04A9_C_0.woff new file mode 100644 index 0000000..643e354 Binary files /dev/null and b/static/styles/proxima/2B04A9_C_0.woff differ diff --git a/static/styles/proxima/2B04A9_D_0.eot b/static/styles/proxima/2B04A9_D_0.eot new file mode 100644 index 0000000..10e8880 Binary files /dev/null and b/static/styles/proxima/2B04A9_D_0.eot differ diff --git a/static/styles/proxima/2B04A9_D_0.ttf b/static/styles/proxima/2B04A9_D_0.ttf new file mode 100644 index 0000000..2779c93 Binary files /dev/null and b/static/styles/proxima/2B04A9_D_0.ttf differ diff --git a/static/styles/proxima/2B04A9_D_0.woff b/static/styles/proxima/2B04A9_D_0.woff new file mode 100644 index 0000000..a3219db Binary files /dev/null and b/static/styles/proxima/2B04A9_D_0.woff differ diff --git a/static/styles/proxima/2B04A9_E_0.eot b/static/styles/proxima/2B04A9_E_0.eot new file mode 100644 index 0000000..1e46099 Binary files /dev/null and b/static/styles/proxima/2B04A9_E_0.eot differ diff --git a/static/styles/proxima/2B04A9_E_0.ttf b/static/styles/proxima/2B04A9_E_0.ttf new file mode 100644 index 0000000..d953486 Binary files /dev/null and b/static/styles/proxima/2B04A9_E_0.ttf differ diff --git a/static/styles/proxima/2B04A9_E_0.woff b/static/styles/proxima/2B04A9_E_0.woff new file mode 100644 index 0000000..0c2691e Binary files /dev/null and b/static/styles/proxima/2B04A9_E_0.woff differ diff --git a/static/styles/rewards/background.css b/static/styles/rewards/background.css new file mode 100644 index 0000000..7125a18 --- /dev/null +++ b/static/styles/rewards/background.css @@ -0,0 +1,21 @@ +background, +background #grid { + width: 100%; + height: 100%; + position: fixed; + top: 0; + left: 0; +} +html, +background { + background-color: #000410; +} + +background #grid { + -webkit-mask-image: radial-gradient(#00000020 0, #00000080 100%); + mask-image: radial-gradient(#00000020 0, #00000080 100%); + /* opacity: 1; */ + pointer-events: none; + /* background-image: url(../../media/grid-1.png); */ + /* background-repeat: repeat; */ +} diff --git a/static/styles/rewards/claim-table.css b/static/styles/rewards/claim-table.css new file mode 100644 index 0000000..121a462 --- /dev/null +++ b/static/styles/rewards/claim-table.css @@ -0,0 +1,331 @@ +:root { + --left-table-column-width: 120px; + + --background-color-default-brightness: 3%; + --background-color-light-brightness: 6%; + --border-brightness: 9%; + + --background-color-default: hsl(225 50% var(--background-color-default-brightness) / 1); + --background-color-light: hsl(225 50% var(--background-color-light-brightness) / 1); + --border-color: hsl(225 25% var(--border-brightness) / 1); +} +#claimButton { + display: flex; + justify-content: center; + align-items: center; +} +main > div { + /* border-collapse: collapse; */ + /* width: 100%; */ + flex-grow: 1; + display: flex; + flex-direction: column; + justify-content: center; +} +table { + border-collapse: collapse; + width: 100vw; + max-width: 640px; + background-color: var(--background-color-default); + border: 1px solid var(--border-color); +} +table tr { + /* width: 100%; */ + /* border: 1px solid; */ +} + +table a:hover, +table a:hover > div { + color: #fff; +} +table #controls { + display: none; + color: #fff; +} +table #controls > button { + flex: 1; + padding: 0 24px; +} +table aside { + text-transform: uppercase; + font-weight: 100; + letter-spacing: 2px; + font-size: 16px; + color: grey; + display: inline; + vertical-align: middle; + text-align: center; + padding: 16px; +} +table button { + user-select: none; + appearance: none; + border: none; + background: 0 0; + cursor: pointer; + outline: 0; + height: 48px; + color: currentColor; +} +table button div { + text-transform: uppercase; + /* white-space: nowrap; */ + word-break: break-all; + text-rendering: geometricPrecision; + color: #fff; +} +table hr { + background-color: #80808040; + height: 1px; + border: none; +} +table svg path { + fill: currentColor; +} +table td div { + word-break: break-all; +} +table th div { + text-align: right; + color: #80808080; +} +table td, +table th { + padding: 8px; + text-rendering: geometricPrecision; + /* max-width: 320px; */ + line-height: 1.25; + color: #808080; +} +table td div { + /* width: calc(100vw - var(--left-table-column-width)); */ + /* white-space: nowrap; */ + word-break: break-all; + overflow: hidden; + text-overflow: ellipsis; +} +table td div svg ~ div { + width: unset; +} +table tr:first-of-type > * { + padding-top: 24px; +} +table tr:last-child td div > div { + width: 50%; + display: inline-block; + vertical-align: middle; +} +table tr:last-of-type > * { + padding-bottom: 24px; +} +table tr#additional-details-border > * { + padding: 0; + margin: 0; +} +table[data-claim-rendered] { + /* border: 1px solid #80808020; */ + /* border-right: 0; */ + /* border-left: 0; */ +} +table[data-claim-rendered] #controls { + display: flex; +} +table[data-claim-rendered] button { + opacity: 0.5; +} +table[data-claim-rendered] button:disabled { + opacity: 0.5; + pointer-events: none; +} +table[data-claim-rendered] button:hover { + background-color: #80808020; + opacity: 1; +} +table[data-claim-rendered] button > div { + display: none; +} +table[data-claim-rendered] button:disabled > svg.claim-icon { + display: none; +} +table[data-claim-rendered] button:hover > div { + display: unset; + color: #fff; +} +table[data-claim-rendered] button:hover > svg { + display: none !important; +} +table[data-claim-rendered] button#additionalDetails { + width: 100%; + color: #fff; + /* opacity: 0.25; */ +} +table[data-claim-rendered] button#additionalDetails:hover { + /* opacity: 1; */ +} +table[data-claim-rendered] tr { + background-color: #80808000; + transition: 125ms ease-in-out opacity; +} +table[data-claim-rendered] tr#additional-details-border { + /* background-color: #80808010; */ + background-color: var(--background-color-light); + /* -webkit-backdrop-filter: blur(4px); */ + /* backdrop-filter: blur(4px); */ + /* border: 1px solid #80808020; */ + /* border-left: 0; */ + /* border-right: 0; */ +} +table[data-claim-rendered] tr#additional-details-border + tr > * { + padding-top: 24px; +} +table #additionalDetailsTable tr, +table[data-details-visible="false"] #additionalDetailsTable tr { + opacity: 0; + pointer-events: none; + display: none; +} +table[data-details-visible="false"] { + /* border-bottom: 1px solid #80808000; */ +} +table[data-details-visible="true"] #additionalDetailsTable tr { + opacity: 1; + pointer-events: unset; + display: table-row; + background-color: #80808000; + /* -webkit-backdrop-filter: blur(4px); */ + /* backdrop-filter: blur(4px); */ +} +table[data-details-visible="true"] { + /* border-bottom: 1px solid #80808020; */ +} +table[data-contract-loaded] #Token { + display: none; +} +#rewardAmount a { + font-size: 24px; +} +#rewardAmount a, +#rewardRecipient div, +#rewardsCount { + color: #fff; +} +#nextTx, +#previousTx { + fill: #fff; +} +table[data-details-visible="false"] #rewardToken .full, +table[data-details-visible="true"] #rewardToken .short { + display: none; +} +table[data-details-visible="false"] #rewardToken .short, +table[data-details-visible="true"] #rewardToken .full { + display: initial; +} +table[data-details-visible="false"] #rewardRecipient .full, +table[data-details-visible="true"] #rewardRecipient .short { + display: none; +} +table[data-details-visible="false"] #rewardRecipient .short, +table[data-details-visible="true"] #rewardRecipient .full { + display: initial; +} +#To > td, +#To > th { + padding-bottom: 24px; +} +table thead { + display: table-row-group; +} +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; +} +#rewardRecipient a:hover div { + opacity: 1; +} +#rewardRecipient div { + color: #fff; +} + +.show-cl { + display: block; +} + +.hide-cl > svg.claim-loader { + display: none; +} +.show-cl > svg.claim-loader { + display: unset; +} +.hide-cl > svg.claim-icon { + display: unset; +} +.show-cl > svg.claim-icon { + display: none; +} + +.show-pagination { + display: flex; + cursor: pointer; + padding: 10px; +} + +.hide-pagination { + display: none; +} + +#additionalDetails svg { + /* display: none; */ +} +table[data-details-visible="true"] #additionalDetails svg.opener { + display: none; +} +table[data-details-visible="false"] #additionalDetails svg.opener { + display: unset; +} + +table[data-details-visible="true"] #additionalDetails svg.closer { + display: unset; +} +table[data-details-visible="false"] #additionalDetails svg.closer { + display: none; +} + +table .full { + /* word-break: break-all; */ +} + +td#owner > a { + word-break: break-all; +} + +table td { + padding-right: 16px; +} +table th { + padding-left: 16px; +} diff --git a/static/styles/rewards/light-mode.css b/static/styles/rewards/light-mode.css new file mode 100644 index 0000000..c148ed7 --- /dev/null +++ b/static/styles/rewards/light-mode.css @@ -0,0 +1,84 @@ +:root { + --light-mode-background-color-default-brightness: calc(100% - var(--background-color-default-brightness)); + --light-mode-background-color-dark-brightness: calc(100% - var(--background-color-light-brightness)); + + --light-mode-background-color-default: hsl(225 0% var(--light-mode-background-color-default-brightness) / 1); + --light-mode-background-color-dark: hsl(225 0% var(--light-mode-background-color-dark-brightness) / 1); + + --light-mode-border-color: hsl(225 0% calc(100% - var(--border-brightness)) / 1); +} +@media (prefers-color-scheme: light) { + background { + /* dark mode styles */ + background-color: #fff; + color: #000; + } + + table a:hover > div { + color: #000; + } + + #rewardAmount > a { + color: #000; + } + + table svg path { + fill: #000; + } + + #logo-icon > svg { + fill: #000; + } + + #logo > div#logo-text > span { + color: #000; + } + + table button div { + color: #000; + } + table[data-claim-rendered] button:hover > div { + color: #000; + } + + table a:hover, + table a:hover > div { + color: #000; + } + + div#build > a { + color: #000; + } + #rewardAmount div, + #rewardRecipient div, + #rewardsCount { + color: #000; + } + #nextTx, + #previousTx { + fill: #000; + } + + html { + background-color: #fff; + } + #grid { + opacity: 0.25; + } + + table { + background-color: var(--light-mode-background-color-default); + border: 1px solid var(--light-mode-border-color); + } + + table[data-claim-rendered] tr#additional-details-border { + background-color: var(--light-mode-background-color-dark); + } + table[data-details-visible="true"] #additional-details-border ~ tr { + background-color: var(--light-mode-background-color-dark); + } + .notifications .toast { + border: 1px solid var(--light-mode-border-color); + background-color: var(--light-mode-background-color-default); + } +} diff --git a/static/styles/rewards/media-queries.css b/static/styles/rewards/media-queries.css new file mode 100644 index 0000000..3cdf401 --- /dev/null +++ b/static/styles/rewards/media-queries.css @@ -0,0 +1,40 @@ +header span:first-child::after { + /* content: " | "; */ +} + +@media screen and (max-width: 640px) { + table { + border-left-width: 0px; + border-right-width: 0px; + } +} +@media screen and (max-width: 768px) { + header span:first-child { + display: none; + } + + header span:first-child::after { + content: ""; + } +} + +/* +@media screen and (min-height: 512px) { + table[data-details-visible="false"] #additional-details-border ~ tr { + display: none; + } + table[data-details-visible="true"] #additional-details-border ~ tr { + display: table-row; + } +} */ + +/* Landscape */ +@media screen and (orientation: landscape) { + body { + width: 100vw; /* 100% of viewport width */ + max-width: 100vw; /* prevents any overflow issues */ + overflow-x: hidden; /* prevents horizontal scrolling */ + padding-left: env(safe-area-inset-left); + padding-right: env(safe-area-inset-right); + } +} diff --git a/static/styles/rewards/pay.css b/static/styles/rewards/pay.css new file mode 100644 index 0000000..76cf477 --- /dev/null +++ b/static/styles/rewards/pay.css @@ -0,0 +1,147 @@ +* { + -webkit-text-size-adjust: 100%; + font-family: + "Ubiquity Nova", + FT Base, + -apple-system, + system-ui, + BlinkMacSystemFont, + SF Pro Text, + Segoe UI, + Roboto, + Helvetica, + Arial, + sans-serif; + line-height: 1; + padding: 0; + margin: 0; + font-size: 12px; + font-weight: 400; + text-transform: uppercase; + letter-spacing: 2px; +} + +a { + color: #808080; +} + +body { + /* min-height: 100vh; */ + /* height: calc(100 * var(--vh)); */ +} + +body, +main { + max-width: 100vw; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +main { + width: 100vw; + position: relative; +} + +a { + text-decoration: none; +} + +#logo a { + display: block; + border: 1px solid transparent; + border-radius: 3px; + flex-direction: row; +} + +#logo { + letter-spacing: 2px; + padding: 48px 0; + -ms-flex-pack: justify; + -ms-flex-align: center; + line-height: 1; + text-align: center; +} + +#logo > #logo-icon { + display: inline-block; + vertical-align: middle; + padding: 4px; + text-rendering: geometricPrecision; + /* color: #fff; */ +} + +#logo-icon > svg { + height: 36px; + display: block; + margin: 0; + width: 36px; + padding: 0; + margin-right: 10px; + fill: #fff; +} + +#logo > div#logo-text { + display: inline-block; + vertical-align: middle; +} + +#logo > div#logo-text > span { + font-size: 20px; + letter-spacing: 5px; + text-transform: uppercase; + text-rendering: geometricPrecision; + color: #fff; + /* font-weight: 400; */ +} + +div#build { + /* bottom: 48px; */ + padding: 48px 0; + text-align: center; + text-transform: uppercase; + letter-spacing: 2px; + text-rendering: geometricPrecision; + /* font-weight: 100; */ + /* width: 48px; */ + margin: auto; +} + +div#build > a { + opacity: 0.25; + font-size: 12px; + color: #fff; +} + +div#build > a:hover { + opacity: 1; +} +header a #logo { + opacity: 0.5; +} +header a:hover #logo { + opacity: 1; +} + +main { + display: flex; + flex-direction: column; + height: 100vh; /* adjust this according to your needs */ +} + +header { + /* height: 140px; */ + /* width: 100%; */ +} + +footer { + /* height: 108px; */ + /* width: 100%; */ + /* padding-bottom: env(safe-area-inset-bottom); */ +} + +canvas { + width: 100vw; + height: 100vh; +} diff --git a/static/styles/rewards/rewards.css b/static/styles/rewards/rewards.css new file mode 100644 index 0000000..707ab0f --- /dev/null +++ b/static/styles/rewards/rewards.css @@ -0,0 +1,8 @@ +@import url("pay.css"); +@import url("background.css"); +@import url("claim-table.css"); +@import url("media-queries.css"); +@import url("../proxima.css"); +@import url("../toast.css"); +@import url("../fa.css"); +@import url("light-mode.css"); diff --git a/static/styles/toast.css b/static/styles/toast.css new file mode 100644 index 0000000..03582f7 --- /dev/null +++ b/static/styles/toast.css @@ -0,0 +1,140 @@ +:root { + --toast-success: hsl(120, 50%, 50%); + --toast-error: hsl(0, 50%, 50%); + --toast-warning: hsl(50, 100%, 50%); + --toast-info: hsl(0, 0%, 50%); +} + +.fa-circle-check { + color: var(--toast-success); +} +.fa-circle-xmark { + color: var(--toast-error); +} +.fa-triangle-exclamation { + color: var(--toast-warning); +} +.fa-circle-info { + color: var(--toast-info); +} + +.notifications { + position: fixed; + bottom: 0; + /* right: 20px; */ +} + +.notifications :where(.toast, .column) { + display: flex; + align-items: center; +} + +.notifications .toast { + position: relative; + overflow: hidden; + list-style: none; + padding: 24px; + margin: 12px; + justify-content: space-between; + animation: show_toast 0.5s ease-in-out; + /* border: 1px solid #80808020; */ + border: 1px solid var(--border-color); + /* backdrop-filter: blur(24px); */ + /* -webkit-backdrop-filter: blur(24px); */ + background-color: var(--background-color-default); +} + +@keyframes show_toast { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +.notifications .toast.hide { + animation: hide_toast 0.5s ease-in-out; +} + +@keyframes hide_toast { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +.toast::before { + position: absolute; + content: ""; + height: 3px; + width: 100%; + bottom: 0px; + left: 0px; + animation: progress 5s linear forwards; +} + +@keyframes progress { + 100% { + width: 0%; + } +} + +.toast.success::before, +.btn#success { + background: var(--toast-success); +} + +.toast.error::before, +.btn#error { + background: var(--toast-error); +} + +.toast.warning::before, +.btn#warning { + background: var(--toast-warning); +} + +.toast.info::before, +.btn#info { + background: var(--toast-info); +} + +.toast .column i { + font-size: 1.75rem; +} + +.toast.success .column i { + color: var(--toast-success); +} + +.toast.error .column i { + color: var(--toast-error); +} + +.toast.warning .column i { + color: var(--toast-warning); +} + +.toast.info .column i { + color: var(--toast-info); +} + +.toast .column span { + /* font-size: 1.07rem; */ + margin-left: 12px; + color: #808080; + line-height: 1.5; +} + +.toast i:last-child { + color: #80808080; + cursor: pointer; + margin-left: 12px; +} + +.toast i:last-child:hover { + color: #808080; +} diff --git a/static/styles/webfonts/fa-brands-400.ttf b/static/styles/webfonts/fa-brands-400.ttf new file mode 100644 index 0000000..cf6a98f Binary files /dev/null and b/static/styles/webfonts/fa-brands-400.ttf differ diff --git a/static/styles/webfonts/fa-brands-400.woff2 b/static/styles/webfonts/fa-brands-400.woff2 new file mode 100644 index 0000000..c740267 Binary files /dev/null and b/static/styles/webfonts/fa-brands-400.woff2 differ diff --git a/static/styles/webfonts/fa-regular-400.ttf b/static/styles/webfonts/fa-regular-400.ttf new file mode 100644 index 0000000..9ef8a37 Binary files /dev/null and b/static/styles/webfonts/fa-regular-400.ttf differ diff --git a/static/styles/webfonts/fa-regular-400.woff2 b/static/styles/webfonts/fa-regular-400.woff2 new file mode 100644 index 0000000..a865b2f Binary files /dev/null and b/static/styles/webfonts/fa-regular-400.woff2 differ diff --git a/static/styles/webfonts/fa-solid-900.ttf b/static/styles/webfonts/fa-solid-900.ttf new file mode 100644 index 0000000..2b96436 Binary files /dev/null and b/static/styles/webfonts/fa-solid-900.ttf differ diff --git a/static/styles/webfonts/fa-solid-900.woff2 b/static/styles/webfonts/fa-solid-900.woff2 new file mode 100644 index 0000000..021d33f Binary files /dev/null and b/static/styles/webfonts/fa-solid-900.woff2 differ diff --git a/static/styles/webfonts/fa-v4compatibility.ttf b/static/styles/webfonts/fa-v4compatibility.ttf new file mode 100644 index 0000000..f07e670 Binary files /dev/null and b/static/styles/webfonts/fa-v4compatibility.ttf differ diff --git a/static/styles/webfonts/fa-v4compatibility.woff2 b/static/styles/webfonts/fa-v4compatibility.woff2 new file mode 100644 index 0000000..6f96a11 Binary files /dev/null and b/static/styles/webfonts/fa-v4compatibility.woff2 differ diff --git a/yarn.lock b/yarn.lock index 9be1cc3..90f17d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -816,6 +816,348 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b" integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2": + version "5.7.2" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@humanwhocodes/config-array@^0.11.13": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -938,6 +1280,109 @@ dependencies: which "^4.0.0" +"@octokit/auth-token@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-4.0.0.tgz#40d203ea827b9f17f42a29c6afb93b7745ef80c7" + integrity sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA== + +"@octokit/core@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-5.1.0.tgz#81dacf0197ed7855e6413f128bd6dd9e121e7d2f" + integrity sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g== + dependencies: + "@octokit/auth-token" "^4.0.0" + "@octokit/graphql" "^7.0.0" + "@octokit/request" "^8.0.2" + "@octokit/request-error" "^5.0.0" + "@octokit/types" "^12.0.0" + before-after-hook "^2.2.0" + universal-user-agent "^6.0.0" + +"@octokit/endpoint@^9.0.0": + version "9.0.4" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-9.0.4.tgz#8afda5ad1ffc3073d08f2b450964c610b821d1ea" + integrity sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw== + dependencies: + "@octokit/types" "^12.0.0" + universal-user-agent "^6.0.0" + +"@octokit/graphql@^7.0.0": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-7.0.2.tgz#3df14b9968192f9060d94ed9e3aa9780a76e7f99" + integrity sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q== + dependencies: + "@octokit/request" "^8.0.1" + "@octokit/types" "^12.0.0" + universal-user-agent "^6.0.0" + +"@octokit/openapi-types@^20.0.0": + version "20.0.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-20.0.0.tgz#9ec2daa0090eeb865ee147636e0c00f73790c6e5" + integrity sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA== + +"@octokit/plugin-paginate-rest@^9.0.0": + version "9.2.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.0.tgz#ca08e32adfab72a1223c4f4b77c9f0222087f879" + integrity sha512-NKi0bJEZqOSbBLMv9kdAcuocpe05Q2xAXNLTGi0HN2GSMFJHNZuSoPNa0tcQFTOFCKe+ZaYBZ3lpXh1yxgUDCA== + dependencies: + "@octokit/types" "^12.6.0" + +"@octokit/plugin-request-log@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-4.0.0.tgz#260fa6970aa97bbcbd91f99f3cd812e2b285c9f1" + integrity sha512-2uJI1COtYCq8Z4yNSnM231TgH50bRkheQ9+aH8TnZanB6QilOnx8RMD2qsnamSOXtDj0ilxvevf5fGsBhBBzKA== + +"@octokit/plugin-rest-endpoint-methods@^10.0.0": + version "10.4.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.0.tgz#f3756b080b75c397e82052de0105535b5d830ead" + integrity sha512-INw5rGXWlbv/p/VvQL63dhlXr38qYTHkQ5bANi9xofrF9OraqmjHsIGyenmjmul1JVRHpUlw5heFOj1UZLEolA== + dependencies: + "@octokit/types" "^12.6.0" + +"@octokit/plugin-throttling@^8.1.3": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-throttling/-/plugin-throttling-8.2.0.tgz#9ec3ea2e37b92fac63f06911d0c8141b46dc4941" + integrity sha512-nOpWtLayKFpgqmgD0y3GqXafMFuKcA4tRPZIfu7BArd2lEZeb1988nhWhwx4aZWmjDmUfdgVf7W+Tt4AmvRmMQ== + dependencies: + "@octokit/types" "^12.2.0" + bottleneck "^2.15.3" + +"@octokit/request-error@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-5.0.1.tgz#277e3ce3b540b41525e07ba24c5ef5e868a72db9" + integrity sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ== + dependencies: + "@octokit/types" "^12.0.0" + deprecation "^2.0.0" + once "^1.4.0" + +"@octokit/request@^8.0.1", "@octokit/request@^8.0.2": + version "8.2.0" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-8.2.0.tgz#125c547bc3f4c0e2dfa38c6829a1cf00027fbd98" + integrity sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ== + dependencies: + "@octokit/endpoint" "^9.0.0" + "@octokit/request-error" "^5.0.0" + "@octokit/types" "^12.0.0" + universal-user-agent "^6.0.0" + +"@octokit/rest@^20.0.2": + version "20.0.2" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-20.0.2.tgz#5cc8871ba01b14604439049e5f06c74b45c99594" + integrity sha512-Ux8NDgEraQ/DMAU1PlAohyfBBXDwhnX2j33Z1nJNziqAfHi70PuxkFYIcIt8aIAxtRE7KVuKp8lSR8pA0J5iOQ== + dependencies: + "@octokit/core" "^5.0.0" + "@octokit/plugin-paginate-rest" "^9.0.0" + "@octokit/plugin-request-log" "^4.0.0" + "@octokit/plugin-rest-endpoint-methods" "^10.0.0" + +"@octokit/types@^12.0.0", "@octokit/types@^12.2.0", "@octokit/types@^12.6.0": + version "12.6.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-12.6.0.tgz#8100fb9eeedfe083aae66473bd97b15b62aedcb2" + integrity sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw== + dependencies: + "@octokit/openapi-types" "^20.0.0" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -1055,6 +1500,11 @@ "@pnpm/resolve-workspace-range" "5.0.1" ramda "npm:@pnpm/ramda@0.28.1" +"@sinclair/typebox@^0.32.14": + version "0.32.14" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.32.14.tgz#ef0a4ed981515fd430cadfb65cb6c2719a0b5539" + integrity sha512-EC77Mw8huT2z9YlYbWfpIQgN6shZE1tH4NP4/Trig8UBel9FZNMZRJ42ubJI8PLor2uIU+waLml1dce5ReCOPg== + "@snyk/github-codeowners@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@snyk/github-codeowners/-/github-codeowners-1.1.0.tgz#45b99732c3c38b5f5b47e43d2b0c9db67a6d2bcc" @@ -1064,6 +1514,63 @@ ignore "^5.1.8" p-map "^4.0.0" +"@supabase/functions-js@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@supabase/functions-js/-/functions-js-2.1.5.tgz#ed1b85f499dfda21d40fe39b86ab923117cb572b" + integrity sha512-BNzC5XhCzzCaggJ8s53DP+WeHHGT/NfTsx2wUSSGKR2/ikLFQTBCDzMvGz/PxYMqRko/LwncQtKXGOYp1PkPaw== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/gotrue-js@2.62.2": + version "2.62.2" + resolved "https://registry.yarnpkg.com/@supabase/gotrue-js/-/gotrue-js-2.62.2.tgz#9f15a451559d71475c953aa0027e1248b0210196" + integrity sha512-AP6e6W9rQXFTEJ7sTTNYQrNf0LCcnt1hUW+RIgUK+Uh3jbWvcIST7wAlYyNZiMlS9+PYyymWQ+Ykz/rOYSO0+A== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/node-fetch@2.6.15", "@supabase/node-fetch@^2.6.14": + version "2.6.15" + resolved "https://registry.yarnpkg.com/@supabase/node-fetch/-/node-fetch-2.6.15.tgz#731271430e276983191930816303c44159e7226c" + integrity sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ== + dependencies: + whatwg-url "^5.0.0" + +"@supabase/postgrest-js@1.9.2": + version "1.9.2" + resolved "https://registry.yarnpkg.com/@supabase/postgrest-js/-/postgrest-js-1.9.2.tgz#39c839022ce73f4eb5da6fb7724fb6a6392150c7" + integrity sha512-I6yHo8CC9cxhOo6DouDMy9uOfW7hjdsnCxZiaJuIVZm1dBGTFiQPgfMa9zXCamEWzNyWRjZvupAUuX+tqcl5Sw== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/realtime-js@2.9.3": + version "2.9.3" + resolved "https://registry.yarnpkg.com/@supabase/realtime-js/-/realtime-js-2.9.3.tgz#f822401aed70883dca5d538179b11089d6d1b6ed" + integrity sha512-lAp50s2n3FhGJFq+wTSXLNIDPw5Y0Wxrgt44eM5nLSA3jZNUUP3Oq2Ccd1CbZdVntPCWLZvJaU//pAd2NE+QnQ== + dependencies: + "@supabase/node-fetch" "^2.6.14" + "@types/phoenix" "^1.5.4" + "@types/ws" "^8.5.10" + ws "^8.14.2" + +"@supabase/storage-js@2.5.5": + version "2.5.5" + resolved "https://registry.yarnpkg.com/@supabase/storage-js/-/storage-js-2.5.5.tgz#2958e2a2cec8440e605bb53bd36649288c4dfa01" + integrity sha512-OpLoDRjFwClwc2cjTJZG8XviTiQH4Ik8sCiMK5v7et0MDu2QlXjCAW3ljxJB5+z/KazdMOTnySi+hysxWUPu3w== + dependencies: + "@supabase/node-fetch" "^2.6.14" + +"@supabase/supabase-js@2.39.7": + version "2.39.7" + resolved "https://registry.yarnpkg.com/@supabase/supabase-js/-/supabase-js-2.39.7.tgz#61c3277a94bd9fd0574b39ecdf4fecffd73a139c" + integrity sha512-1vxsX10Uhc2b+Dv9pRjBjHfqmw2N2h1PyTg9LEfICR3x2xwE24By1MGCjDZuzDKH5OeHCsf4it6K8KRluAAEXA== + dependencies: + "@supabase/functions-js" "2.1.5" + "@supabase/gotrue-js" "2.62.2" + "@supabase/node-fetch" "2.6.15" + "@supabase/postgrest-js" "1.9.2" + "@supabase/realtime-js" "2.9.3" + "@supabase/storage-js" "2.5.5" + "@types/json-schema@^7.0.12": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -1074,6 +1581,13 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.5.tgz#ec10755e871497bcd83efe927e43ec46e8c0747e" integrity sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag== +"@types/node@*": + version "20.11.22" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.22.tgz#9a192c3d7e7e71fa3a4b15032654f64643815cd6" + integrity sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA== + dependencies: + undici-types "~5.26.4" + "@types/node@^20.11.19": version "20.11.19" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.19.tgz#b466de054e9cb5b3831bee38938de64ac7f81195" @@ -1086,6 +1600,11 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== +"@types/phoenix@^1.5.4": + version "1.6.4" + resolved "https://registry.yarnpkg.com/@types/phoenix/-/phoenix-1.6.4.tgz#cceac93a827555473ad38057d1df7d06eef1ed71" + integrity sha512-B34A7uot1Cv0XtaHRYDATltAdKx0BvVKNgYNqE4WjtPUa4VQJM7kxeXcVKaH+KS+kCmZ+6w+QaUdcljiheiBJA== + "@types/picomatch@2.3.3": version "2.3.3" resolved "https://registry.yarnpkg.com/@types/picomatch/-/picomatch-2.3.3.tgz#be60498568c19e989e43fb39aa84be1ed3655e92" @@ -1096,6 +1615,13 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.7.tgz#326f5fdda70d13580777bcaa1bc6fa772a5aef0e" integrity sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg== +"@types/ws@^8.5.10": + version "8.5.10" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" + integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== + dependencies: + "@types/node" "*" + "@typescript-eslint/eslint-plugin@^7.0.1": version "7.0.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.1.tgz#407daffe09d964d57aceaf3ac51846359fbe61b0" @@ -1217,6 +1743,11 @@ acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -1340,11 +1871,25 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz#ac812d8ce5a6b976d738e1c45f08d0b00bc7d725" integrity sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg== +axios@^1.6.7: + version "1.6.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7" + integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA== + dependencies: + follow-redirects "^1.15.4" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babylon@^6.9.1: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -1355,6 +1900,26 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +before-after-hook@^2.2.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" + integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + bole@^5.0.0: version "5.0.11" resolved "https://registry.yarnpkg.com/bole/-/bole-5.0.11.tgz#c4a165975422daee6f576360e882a425c8e40617" @@ -1363,6 +1928,11 @@ bole@^5.0.0: fast-safe-stringify "^2.0.7" individual "^3.0.0" +bottleneck@^2.15.3: + version "2.19.5" + resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" + integrity sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1385,6 +1955,11 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + builtins@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" @@ -1522,6 +2097,13 @@ colorette@^2.0.20: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" @@ -1832,6 +2414,16 @@ define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +deprecation@^2.0.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -1879,6 +2471,19 @@ easy-table@1.2.0: optionalDependencies: wcwidth "^1.0.1" +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emoji-regex@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.3.0.tgz#76998b9268409eb3dae3de989254d456e70cfe23" @@ -2176,6 +2781,42 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +ethers@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + eventemitter3@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" @@ -2339,6 +2980,11 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== +follow-redirects@^1.15.4: + version "1.15.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -2354,6 +3000,15 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fs-extra@10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -2538,6 +3193,11 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +godb@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/godb/-/godb-0.6.2.tgz#0c380310558a7c9114f49aa70c1a1da67313120e" + integrity sha512-641W5/CzvwWCCW8Z5ETT6Js6posF5XXbc93F8fwJNseTpuQsTuJPxRntZPe6iYtb9ExfNlGteK09cN3Sl2avXw== + gopd@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" @@ -2609,6 +3269,14 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.1: dependencies: has-symbols "^1.0.3" +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + hasown@^2.0.0, hasown@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa" @@ -2616,6 +3284,15 @@ hasown@^2.0.0, hasown@^2.0.1: dependencies: function-bind "^1.1.2" +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -2696,7 +3373,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3: +inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2937,6 +3614,11 @@ jiti@1.21.0, jiti@^1.19.1: resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -3297,6 +3979,18 @@ micromatch@4.0.5, micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -3317,6 +4011,16 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: version "9.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" @@ -3510,7 +4214,7 @@ object.assign@^4.1.5: has-symbols "^1.0.3" object-keys "^1.1.1" -once@^1.3.0: +once@^1.3.0, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== @@ -3769,6 +4473,11 @@ promise-retry@^2.0.1: err-code "^2.0.2" retry "^0.12.0" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + punycode@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -3979,6 +4688,11 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + "semver@2 || 3 || 4 || 5", semver@^5.5.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" @@ -4353,6 +5067,11 @@ to-space-case@^1.0.0: dependencies: to-no-case "^1.0.0" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" @@ -4502,6 +5221,11 @@ unique-string@^3.0.0: dependencies: crypto-random-string "^4.0.0" +universal-user-agent@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" + integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== + universalify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" @@ -4570,6 +5294,19 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -4655,6 +5392,16 @@ write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +ws@7.4.6: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +ws@^8.14.2: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== + xdg-basedir@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-5.1.0.tgz#1efba19425e73be1bc6f2a6ceb52a3d2c884c0c9"