diff --git a/.cspell.json b/.cspell.json index d220b84..6ede700 100644 --- a/.cspell.json +++ b/.cspell.json @@ -35,7 +35,8 @@ "WXDAI", "XDAI", "xmark", - "SUPABASE" + "SUPABASE", + "Knip" ], "dictionaries": ["typescript", "node", "software-terms", "html"], "import": ["@cspell/dict-typescript/cspell-ext.json", "@cspell/dict-node/cspell-ext.json", "@cspell/dict-software-terms"], diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index 63c4474..a5f909e 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -2,7 +2,7 @@ name: Knip on: pull_request_target: - types: [ opened, synchronize ] + types: [opened, synchronize] permissions: write-all diff --git a/.gitignore b/.gitignore index 725ce5f..7bad22f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ node_modules .env static/dist metamask +static/out \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 9b3aa47..0000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "lib/chainlist"] - path = lib/chainlist - url = https://github.com/DefiLlama/chainlist.git - branch = main diff --git a/README.md b/README.md index 3354efb..108ad82 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # `@ubiquity/onboard.ubq.fi` -Generates the configuration for organizations, by creating a default configuration and creating a repository under the +Generates the configuration for organizations, by creating a default configuration and creating a repository under the given Organization. ## Requirements @@ -12,24 +12,29 @@ Copy the `env.example` to `.env` and fill the required variables. ```shell yarn start ``` + Should make the front-end page available at [http://localhost:8080](http://localhost:8080). ### Required fields + - `CHAIN_ID`: the id of the network you want to use for the transactions - `WALLET_PRIVATE_KEY`: the [64 digits](https://www.browserling.com/tools/random-hex) crypto wallet key that will be used for transactions - `GITHUB_PAT`: a [GitHub Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) - `ORG_NAME`: the name of the [organization](https://github.com/settings/organizations) where you want to add the bot ## Testing + To test with Cypress Studio UI, run + ```shell yarn cy:open ``` Otherwise to simply run the tests through the console, run + ```shell yarn cy:run ``` -To test in a real-world scenario, you will need to create an Organization under your GitHub account, and use it as a +To test in a real-world scenario, you will need to create an Organization under your GitHub account, and use it as a dummy. If the operation is successful, you will see a new repository appear with the Ubiquibot configuration. diff --git a/build/esbuild-build.ts b/build/esbuild-build.ts index e8d8f1f..c88a5ff 100644 --- a/build/esbuild-build.ts +++ b/build/esbuild-build.ts @@ -1,21 +1,11 @@ import { execSync } from "child_process"; import { config } from "dotenv"; import esbuild from "esbuild"; -import extraRpcs from "../lib/chainlist/constants/extraRpcs"; const typescriptEntries = ["static/scripts/onboarding/onboarding.ts"]; -const cssEntries = ["static/styles/rewards/rewards.css", "static/styles/audit-report/audit.css", "static/styles/onboarding/onboarding.css"]; +const cssEntries = ["static/styles/onboarding/onboarding.css"]; export const entries = [...typescriptEntries, ...cssEntries]; -const allNetworkUrls: Record = {}; -// this flattens all the rpcs into a single object, with key names that match the networkIds. The arrays are just of URLs per network ID. - -Object.keys(extraRpcs).forEach((networkId) => { - const officialUrls = extraRpcs[networkId].rpcs.filter((rpc) => typeof rpc === "string"); - const extraUrls: string[] = extraRpcs[networkId].rpcs.filter((rpc) => rpc.url !== undefined).map((rpc) => rpc.url); - allNetworkUrls[networkId] = [...officialUrls, ...extraUrls]; -}); - export const esBuildContext: esbuild.BuildOptions = { sourcemap: true, entryPoints: entries, @@ -31,7 +21,6 @@ export const esBuildContext: esbuild.BuildOptions = { }, outdir: "static/out", define: createEnvDefines(["SUPABASE_URL", "SUPABASE_ANON_KEY", "FRONTEND_URL"], { - extraRpcs: allNetworkUrls, commitHash: execSync(`git rev-parse --short HEAD`).toString().trim(), }), }; diff --git a/cypress/e2e/main.cy.ts b/cypress/e2e/main.cy.ts index 3fc9ca2..b423ce3 100644 --- a/cypress/e2e/main.cy.ts +++ b/cypress/e2e/main.cy.ts @@ -82,7 +82,7 @@ describe("Homepage tests", () => { statusCode: 200, }); // Simulate login token - // cspell:ignore wfzpewmlyiozupulbuur + // cSpell: ignore wfzpewmlyiozupulbuur window.localStorage.setItem("sb-wfzpewmlyiozupulbuur-auth-token", JSON.stringify(loginToken)); }).as("githubLogin"); cy.get("#github-login-button").click(); diff --git a/cypress/fixtures/get-installation-repositories.json b/cypress/fixtures/get-installation-repositories.json index fea6b4e..c5922ce 100644 --- a/cypress/fixtures/get-installation-repositories.json +++ b/cypress/fixtures/get-installation-repositories.json @@ -94,9 +94,7 @@ "allow_forking": false, "is_template": false, "web_commit_signoff_required": false, - "topics": [ - - ], + "topics": [], "visibility": "private", "forks": 0, "open_issues": 0, diff --git a/cypress/fixtures/get-installations.json b/cypress/fixtures/get-installations.json index e0170d1..9c9c2f3 100644 --- a/cypress/fixtures/get-installations.json +++ b/cypress/fixtures/get-installations.json @@ -74,9 +74,7 @@ "updated_at": "2024-02-13T19:37:31.000+09:00", "single_file_name": null, "has_multiple_single_files": false, - "single_file_paths": [ - - ], + "single_file_paths": [], "suspended_by": null, "suspended_at": null }, @@ -110,19 +108,13 @@ "app_slug": "ubi", "target_id": 159901852, "target_type": "Organization", - "permissions": { - - }, - "events": [ - - ], + "permissions": {}, + "events": [], "created_at": "2024-02-13T21:12:10.000+09:00", "updated_at": "2024-02-13T21:12:10.000+09:00", "single_file_name": null, "has_multiple_single_files": false, - "single_file_paths": [ - - ], + "single_file_paths": [], "suspended_by": null, "suspended_at": null } diff --git a/cypress/fixtures/get-org-installations.json b/cypress/fixtures/get-org-installations.json index 69afcbe..dba3ee1 100644 --- a/cypress/fixtures/get-org-installations.json +++ b/cypress/fixtures/get-org-installations.json @@ -74,9 +74,7 @@ "updated_at": "2024-03-11T20:40:33.000+09:00", "single_file_name": null, "has_multiple_single_files": false, - "single_file_paths": [ - - ], + "single_file_paths": [], "suspended_by": null, "suspended_at": null } diff --git a/cypress/fixtures/get-repos.json b/cypress/fixtures/get-repos.json index 4ea6823..c885ca8 100644 --- a/cypress/fixtures/get-repos.json +++ b/cypress/fixtures/get-repos.json @@ -91,9 +91,7 @@ "allow_forking": false, "is_template": false, "web_commit_signoff_required": false, - "topics": [ - - ], + "topics": [], "visibility": "private", "forks": 0, "open_issues": 0, @@ -117,9 +115,7 @@ "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", "merge_commit_message": "PR_TITLE", "merge_commit_title": "MERGE_MESSAGE", - "custom_properties": { - - }, + "custom_properties": {}, "organization": { "login": "Ubiquity", "id": 159901852, diff --git a/cypress/fixtures/get-search.json b/cypress/fixtures/get-search.json index f99cfad..71262b7 100644 --- a/cypress/fixtures/get-search.json +++ b/cypress/fixtures/get-search.json @@ -95,9 +95,7 @@ "allow_forking": false, "is_template": false, "web_commit_signoff_required": false, - "topics": [ - - ], + "topics": [], "visibility": "private", "forks": 0, "open_issues": 0, diff --git a/cypress/fixtures/get-ubiquibot-config.json b/cypress/fixtures/get-ubiquibot-config.json index b285e34..5c3ce87 100644 --- a/cypress/fixtures/get-ubiquibot-config.json +++ b/cypress/fixtures/get-ubiquibot-config.json @@ -91,9 +91,7 @@ "allow_forking": true, "is_template": false, "web_commit_signoff_required": false, - "topics": [ - - ], + "topics": [], "visibility": "private", "forks": 0, "open_issues": 0, @@ -118,9 +116,7 @@ "squash_merge_commit_title": "COMMIT_OR_PR_TITLE", "merge_commit_message": "PR_TITLE", "merge_commit_title": "MERGE_MESSAGE", - "custom_properties": { - - }, + "custom_properties": {}, "organization": { "login": "ubiquity", "id": 76412717, diff --git a/cypress/fixtures/put-config.json b/cypress/fixtures/put-config.json index 69afcbe..dba3ee1 100644 --- a/cypress/fixtures/put-config.json +++ b/cypress/fixtures/put-config.json @@ -74,9 +74,7 @@ "updated_at": "2024-03-11T20:40:33.000+09:00", "single_file_name": null, "has_multiple_single_files": false, - "single_file_paths": [ - - ], + "single_file_paths": [], "suspended_by": null, "suspended_at": null } diff --git a/knip.ts b/knip.ts index 39b7c3e..596073b 100644 --- a/knip.ts +++ b/knip.ts @@ -1,7 +1,7 @@ import type { KnipConfig } from "knip"; const config: KnipConfig = { - entry: ["static/scripts/onboarding/onboarding.ts", "static/scripts/rewards/index.ts"], + entry: ["static/scripts/onboarding/onboarding.ts"], project: ["static/**/*.ts"], ignoreExportsUsedInFile: true, ignoreDependencies: ["eslint-config-prettier", "eslint-plugin-prettier", "@octokit/core"], diff --git a/lib/chainlist b/lib/chainlist deleted file mode 160000 index 8059283..0000000 --- a/lib/chainlist +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 805928372c7a97eec513e8c74c344dd759f07e1c diff --git a/package.json b/package.json index 28c4e52..3269ed7 100644 --- a/package.json +++ b/package.json @@ -34,12 +34,10 @@ "@octokit/core": "^5.1.0", "@octokit/plugin-create-or-update-text-file": "^4.0.1", "@octokit/rest": "^20.0.2", - "@sinclair/typebox": "^0.32.15", "@supabase/supabase-js": "2.39.7", "@types/libsodium-wrappers": "^0.7.13", "@ubiquibot/configuration": "1.1.0", "@uniswap/permit2-sdk": "^1.2.0", - "axios": "^1.6.8", "dotenv": "^16.4.4", "ethers": "^5.7.2", "libsodium-wrappers": "^0.7.13", diff --git a/static/index.html b/static/index.html index 6413e25..3f1caa2 100644 --- a/static/index.html +++ b/static/index.html @@ -21,8 +21,7 @@

Onboarding

-
-
+
@@ -39,8 +38,7 @@

Onboarding

- +
diff --git a/static/scripts/rewards/abis/cirip.json b/static/scripts/onboarding/abis/cirip.json similarity index 100% rename from static/scripts/rewards/abis/cirip.json rename to static/scripts/onboarding/abis/cirip.json diff --git a/static/scripts/rewards/abis/erc20Abi.ts b/static/scripts/onboarding/abis/erc20Abi.ts similarity index 100% rename from static/scripts/rewards/abis/erc20Abi.ts rename to static/scripts/onboarding/abis/erc20Abi.ts diff --git a/static/scripts/onboarding/abis/index.ts b/static/scripts/onboarding/abis/index.ts new file mode 100644 index 0000000..3813550 --- /dev/null +++ b/static/scripts/onboarding/abis/index.ts @@ -0,0 +1 @@ +export * from "./erc20Abi"; diff --git a/static/scripts/onboarding/constants.ts b/static/scripts/onboarding/constants.ts new file mode 100644 index 0000000..dc2bf37 --- /dev/null +++ b/static/scripts/onboarding/constants.ts @@ -0,0 +1,29 @@ +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 function getNetworkName(networkId?: number) { + const networkName = networkNames[networkId as keyof typeof networkNames]; + if (!networkName) { + console.error(`Unknown network ID: ${networkId}`); + } + return networkName ?? "Unknown Network"; +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const nftAddress = "0xAa1bfC0e51969415d64d6dE74f27CDa0587e645b"; diff --git a/static/scripts/onboarding/github-login-button.ts b/static/scripts/onboarding/github-login-button.ts index 319bf5f..ecaf714 100644 --- a/static/scripts/onboarding/github-login-button.ts +++ b/static/scripts/onboarding/github-login-button.ts @@ -53,7 +53,7 @@ function getNewSessionToken() { } function getSessionToken() { - // cspell:ignore wfzpewmlyiozupulbuur + // cSpell: ignore wfzpewmlyiozupulbuur const cachedSessionToken = getLocalStore("sb-wfzpewmlyiozupulbuur-auth-token"); if (cachedSessionToken) { return cachedSessionToken.provider_token; diff --git a/static/scripts/onboarding/onboarding.ts b/static/scripts/onboarding/onboarding.ts index 24dd95b..09203ba 100644 --- a/static/scripts/onboarding/onboarding.ts +++ b/static/scripts/onboarding/onboarding.ts @@ -7,8 +7,8 @@ import { ethers } from "ethers"; import { parseUnits } from "ethers/lib/utils"; import _sodium from "libsodium-wrappers"; import YAML from "yaml"; -import { erc20Abi } from "../rewards/abis"; -import { getNetworkName, NetworkIds, Tokens } from "../rewards/constants"; +import { erc20Abi } from "./abis"; +import { getNetworkName, NetworkIds, Tokens } from "./constants"; import { getSessionToken, renderGitHubLoginButton } from "./github-login-button"; const classes = ["error", "warn", "success"]; diff --git a/static/scripts/rewards/abis/index.ts b/static/scripts/rewards/abis/index.ts deleted file mode 100644 index de30ac1..0000000 --- a/static/scripts/rewards/abis/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./erc20Abi"; -export * from "./permit2Abi"; diff --git a/static/scripts/rewards/abis/nftRewardAbi.ts b/static/scripts/rewards/abis/nftRewardAbi.ts deleted file mode 100644 index eb89aac..0000000 --- a/static/scripts/rewards/abis/nftRewardAbi.ts +++ /dev/null @@ -1,992 +0,0 @@ -/* 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 deleted file mode 100644 index 5d17050..0000000 --- a/static/scripts/rewards/abis/permit2Abi.ts +++ /dev/null @@ -1,353 +0,0 @@ -// 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 deleted file mode 100644 index 67a772f..0000000 --- a/static/scripts/rewards/cirip/ens-lookup.ts +++ /dev/null @@ -1,67 +0,0 @@ -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 deleted file mode 100644 index ba3ba46..0000000 --- a/static/scripts/rewards/cirip/fetch-ens.ts +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 8df99d5..0000000 --- a/static/scripts/rewards/cirip/query-graph.ts +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index 5b14fd7..0000000 --- a/static/scripts/rewards/cirip/query-reverse-ens.ts +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 979c5d1..0000000 --- a/static/scripts/rewards/constants.ts +++ /dev/null @@ -1,57 +0,0 @@ -// 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"; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const nftAddress = "0xAa1bfC0e51969415d64d6dE74f27CDa0587e645b"; diff --git a/static/scripts/rewards/helpers.ts b/static/scripts/rewards/helpers.ts deleted file mode 100644 index b9c3896..0000000 --- a/static/scripts/rewards/helpers.ts +++ /dev/null @@ -1,80 +0,0 @@ -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 deleted file mode 100644 index 9aa754c..0000000 --- a/static/scripts/rewards/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 8687d32..0000000 --- a/static/scripts/rewards/invalidate-component.ts +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index ee56eba..0000000 --- a/static/scripts/rewards/render-transaction/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index 0da3719..0000000 --- a/static/scripts/rewards/render-transaction/insert-table-data.ts +++ /dev/null @@ -1,129 +0,0 @@ -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 deleted file mode 100644 index 8be3262..0000000 --- a/static/scripts/rewards/render-transaction/render-ens-name.ts +++ /dev/null @@ -1,42 +0,0 @@ -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 deleted file mode 100644 index 429bda7..0000000 --- a/static/scripts/rewards/render-transaction/render-token-symbol.ts +++ /dev/null @@ -1,56 +0,0 @@ -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 deleted file mode 100644 index 4f3d015..0000000 --- a/static/scripts/rewards/render-transaction/render-transaction.ts +++ /dev/null @@ -1,155 +0,0 @@ -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 deleted file mode 100644 index 51d38d1..0000000 --- a/static/scripts/rewards/render-transaction/set-claim-message.ts +++ /dev/null @@ -1,6 +0,0 @@ -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 deleted file mode 100644 index 23df134..0000000 --- a/static/scripts/rewards/render-transaction/tx-type.ts +++ /dev/null @@ -1,68 +0,0 @@ -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 deleted file mode 100644 index 80281a6..0000000 --- a/static/scripts/rewards/render-transaction/utils.ts +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index bd9832e..0000000 --- a/static/scripts/rewards/the-grid.ts +++ /dev/null @@ -1,160 +0,0 @@ -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 deleted file mode 100644 index 9294e72..0000000 --- a/static/scripts/rewards/toaster.ts +++ /dev/null @@ -1,89 +0,0 @@ -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 deleted file mode 100644 index fd26d9f..0000000 --- a/static/scripts/rewards/web3/erc20-permit.ts +++ /dev/null @@ -1,183 +0,0 @@ -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 deleted file mode 100644 index 0dafff6..0000000 --- a/static/scripts/rewards/web3/erc721-permit.ts +++ /dev/null @@ -1,64 +0,0 @@ -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 deleted file mode 100644 index 34766b8..0000000 --- a/static/scripts/rewards/web3/wallet.ts +++ /dev/null @@ -1,103 +0,0 @@ -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/tsconfig.json b/tsconfig.json index 90f2a77..9df9da6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -44,8 +44,8 @@ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ /* JavaScript Support */ - "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, + "checkJs": true /* Enable error reporting in type-checked JavaScript files. */, // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ /* Emit */ diff --git a/yarn.lock b/yarn.lock index af700aa..46bb7c1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1542,11 +1542,6 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.32.14.tgz#ef0a4ed981515fd430cadfb65cb6c2719a0b5539" integrity sha512-EC77Mw8huT2z9YlYbWfpIQgN6shZE1tH4NP4/Trig8UBel9FZNMZRJ42ubJI8PLor2uIU+waLml1dce5ReCOPg== -"@sinclair/typebox@^0.32.15": - version "0.32.15" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.32.15.tgz#92dcdc12907f7c0f6d954ba3700b5bb888d2eb34" - integrity sha512-5Lrwo7VOiWEBJBhHmqNmf3TPB9ll8gcEshvYJyAIJyCZ2PF48MFOtiDHJNj8+FsNcqImaQYmxVkKBCBlyAa/wg== - "@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" @@ -2038,15 +2033,6 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== -axios@^1.6.8: - version "1.6.8" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" - integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== - dependencies: - follow-redirects "^1.15.6" - 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" @@ -2328,7 +2314,7 @@ colorette@^2.0.16, 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.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -3383,11 +3369,6 @@ 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.6: - version "1.15.6" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" - integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== - for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -3408,15 +3389,6 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== -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" - form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -5086,11 +5058,6 @@ proxy-from-env@1.0.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== -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== - psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"