├── cli ├── .gitignore ├── README.md ├── runner.sh ├── Cargo.toml └── src │ ├── rescue.json │ ├── erc20.json │ ├── main.rs │ ├── rescue.rs │ ├── watchtower.rs │ └── erc20.rs ├── contracts ├── .gitignore ├── .prettierrc ├── foundry.toml ├── remappings.txt ├── .prettierignore ├── src │ ├── test │ │ ├── Rescue.t.sol │ │ ├── base │ │ │ └── BaseTest.sol │ │ └── mocks │ │ │ ├── MockERC20.sol │ │ │ └── MockERC721.sol │ └── Rescue.sol ├── .solhint.json └── package.json ├── backend ├── .env.template ├── src │ ├── db │ │ ├── dbAccess.ts │ │ └── dbQueries.ts │ ├── types │ │ └── customTypes.ts │ ├── watchTower.ts │ ├── server.ts │ └── abi │ │ └── erc20.abi.json ├── .prettierrc.js ├── .gitignore ├── prisma │ └── schema.prisma ├── package.json ├── tsconfig.json └── yarn.lock ├── frontend ├── .eslintrc.json ├── public │ ├── favicon.ico │ ├── test_im.jpg │ └── vercel.svg ├── styles │ ├── Matter-Bold.otf │ ├── Matter-Heavy.otf │ ├── Matter-Light.otf │ ├── Matter-Medium.otf │ ├── Matter-Regular.otf │ ├── Matter-BoldItalic.otf │ ├── Matter-SemiBold.otf │ ├── Matter-HeavyItalic.otf │ ├── Matter-LightItalic.otf │ ├── Matter-MediumItalic.otf │ ├── Matter-RegularItalic.otf │ ├── Matter-SemiBoldItalic.otf │ ├── globals.css │ └── Home.module.css ├── postcss.config.js ├── next.config.js ├── tailwind.config.js ├── pages │ ├── api │ │ ├── hello.ts │ │ └── form.js │ ├── _app.tsx │ └── index.tsx ├── .gitignore ├── tsconfig.json ├── package.json └── README.md ├── .gitmodules ├── LICENSE └── README.md /cli/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /contracts/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | node_modules/ 3 | out/ 4 | cache/ -------------------------------------------------------------------------------- /contracts/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": true 3 | } -------------------------------------------------------------------------------- /backend/.env.template: -------------------------------------------------------------------------------- 1 | WSS_PROVIDER= 2 | MY_ADDRESS= 3 | DATABASE_URL= -------------------------------------------------------------------------------- /frontend/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /cli/README.md: -------------------------------------------------------------------------------- 1 | # ethereum-watchtower cli 2 | `cargo install --path .` 3 | `watchtower` 4 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/test_im.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/public/test_im.jpg -------------------------------------------------------------------------------- /contracts/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | fuzz_runs = 256 3 | 4 | [profile.hugeRun] 5 | fuzz_runs = 2048 -------------------------------------------------------------------------------- /contracts/remappings.txt: -------------------------------------------------------------------------------- 1 | @ds-test/=lib/ds-test/src/ 2 | @solmate/=lib/solmate/src/ 3 | @oz/=lib/oz/contracts/ -------------------------------------------------------------------------------- /frontend/styles/Matter-Bold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-Bold.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-Heavy.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-Heavy.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-Light.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-Light.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-Medium.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-Regular.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-BoldItalic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-BoldItalic.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-SemiBold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-SemiBold.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-HeavyItalic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-HeavyItalic.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-LightItalic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-LightItalic.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-MediumItalic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-MediumItalic.otf -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/styles/Matter-RegularItalic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-RegularItalic.otf -------------------------------------------------------------------------------- /frontend/styles/Matter-SemiBoldItalic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lyronctk/veil/HEAD/frontend/styles/Matter-SemiBoldItalic.otf -------------------------------------------------------------------------------- /backend/src/db/dbAccess.ts: -------------------------------------------------------------------------------- 1 | import { PrismaClient } from '@prisma/client' 2 | const prisma = new PrismaClient() 3 | 4 | export default prisma; -------------------------------------------------------------------------------- /contracts/.prettierignore: -------------------------------------------------------------------------------- 1 | *.json 2 | *.js 3 | *.md 4 | *.yaml 5 | lib/ 6 | cache/ 7 | node_modules/ 8 | out/ 9 | typechain/ 10 | coverage/ -------------------------------------------------------------------------------- /backend/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | trailingComma: "all", 4 | singleQuote: true, 5 | printWidth: 120, 6 | tabWidth: 2, 7 | }; 8 | -------------------------------------------------------------------------------- /frontend/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | } 6 | 7 | module.exports = nextConfig 8 | -------------------------------------------------------------------------------- /frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./pages/**/*.{js,ts,jsx,tsx}", 5 | "./components/**/*.{js,ts,jsx,tsx}", 6 | ], 7 | theme: { 8 | extend: {}, 9 | }, 10 | plugins: [], 11 | } 12 | -------------------------------------------------------------------------------- /backend/src/types/customTypes.ts: -------------------------------------------------------------------------------- 1 | export type RescueTxData = { 2 | userAddress: string, 3 | nonce: string, 4 | signedTx: string, 5 | gasPrice: number 6 | } 7 | 8 | export type ApproveTxData = { 9 | signedTx: string, 10 | userAddress: string 11 | token: string 12 | } -------------------------------------------------------------------------------- /contracts/src/test/Rescue.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Unlicense 2 | pragma solidity 0.8.11; 3 | 4 | import "./base/BaseTest.sol"; 5 | 6 | contract ContractTest is BaseTest { 7 | function setUp() public {} 8 | 9 | function testExample() public { 10 | assertTrue(true); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /contracts/src/test/base/BaseTest.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.11; 3 | 4 | import "@ds-test/test.sol"; 5 | 6 | contract BaseTest is DSTest { 7 | // using stdStorage for StdStorage; 8 | 9 | // StdStorage stdstore; 10 | // Hevm internal constant hevm = Hevm(HEVM_ADDRESS); 11 | } 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "contracts/lib/ds-test"] 2 | path = contracts/lib/ds-test 3 | url = https://github.com/dapphub/ds-test 4 | [submodule "contracts/lib/solmate"] 5 | path = contracts/lib/solmate 6 | url = https://github.com/Rari-Capital/solmate 7 | [submodule "contracts/lib/oz"] 8 | path = contracts/lib/oz 9 | url = https://github.com/OpenZeppelin/openzeppelin-contracts 10 | -------------------------------------------------------------------------------- /frontend/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /frontend/pages/api/form.js: -------------------------------------------------------------------------------- 1 | export default function handler(req, res) { 2 | const body = req.body 3 | console.log('body: ', body) 4 | 5 | // Both of these are required. 6 | if (!body.first || !body.last) { 7 | return res.json({ data: 'First or last name not found' }) 8 | } 9 | 10 | // Found the name. 11 | res.json({ data: `${body.first} ${body.last}` }) 12 | } -------------------------------------------------------------------------------- /contracts/.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["solhint:recommended"], 3 | "rules": { 4 | "prettier/prettier": "error", 5 | "avoid-throw": "off", 6 | "avoid-suicide": "error", 7 | "avoid-sha3": "warn", 8 | "reason-string": "off", 9 | "private-vars-leading-underscore": "error", 10 | "compiler-version": ["off"], 11 | "func-visibility": ["warn",{"ignoreConstructors":true}], 12 | "not-rely-on-time": "off" 13 | }, 14 | "plugins": ["prettier"] 15 | } -------------------------------------------------------------------------------- /cli/runner.sh: -------------------------------------------------------------------------------- 1 | cargo run --release -- \ 2 | --private-key $HACKLODGE_PRIVATE_KEY \ 3 | --backup-address $HACKLODGE_BACKUP_ADDRESS \ 4 | --contract-address $HACKLODGE_CONTRACT_ADDRESS \ 5 | --min-gas 10 \ 6 | --max-gas 100 \ 7 | --gas-step 10 \ 8 | --nonce 1 \ 9 | --output-path "not-your-private-keys.csv" \ 10 | --erc20-addresses "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" \ 11 | "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9" \ 12 | "0xA808B22ffd2c472aD1278088F16D4010E6a54D5F" 13 | 14 | -------------------------------------------------------------------------------- /contracts/src/test/mocks/MockERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.11; 3 | import "@solmate/tokens/ERC20.sol"; 4 | 5 | // Adapted from: 6 | // https://github.com/ZeframLou/vested-erc20/blob/c937b59b14c602cf885b7e144f418a942ee5336b/src/test/mocks/TestERC20.sol 7 | 8 | contract MockERC20 is ERC20("MockToken", "MOCK", 18) { 9 | // Expose external mint function 10 | function mint(address to, uint256 amount) external { 11 | _mint(to, amount); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/src/test/mocks/MockERC721.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.8.11; 3 | import "@solmate/tokens/ERC721.sol"; 4 | 5 | contract MockERC721 is ERC721("MockNft", "") { 6 | string baseURI = "yeet"; 7 | 8 | // Expose external mint function 9 | function mint(address to, uint256 id) external { 10 | _mint(to, id); 11 | } 12 | 13 | function tokenURI(uint256) public view override returns (string memory) { 14 | return baseURI; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "veil" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | ethers = {version = "0.17.0", features = ["abigen"]} 10 | serde_json = "1.0.84" 11 | anyhow = "1.0.56" 12 | eyre = "0.6" 13 | tokio = { version = "1", features = ["full"] } 14 | clap = { version = "3.1.6", features = ["derive"] } 15 | 16 | [profile.release] 17 | lto = "fat" 18 | codegen-units = 1 19 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | .env 3 | */dist 4 | .idea 5 | .vscode 6 | process.env 7 | 8 | # dependencies 9 | /node_modules 10 | /.pnp 11 | .pnp.js 12 | 13 | # testing 14 | /coverage 15 | 16 | # next.js 17 | /.next/ 18 | /out/ 19 | 20 | # production 21 | /build 22 | 23 | # misc 24 | .DS_Store 25 | *.pem 26 | 27 | # debug 28 | npm-debug.log* 29 | yarn-debug.log* 30 | yarn-error.log* 31 | .pnpm-debug.log* 32 | 33 | # local env files 34 | .env*.local 35 | 36 | # vercel 37 | .vercel 38 | 39 | # typescript 40 | *.tsbuildinfo 41 | dist/ 42 | -------------------------------------------------------------------------------- /backend/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | output = "../node_modules/.prisma/client" 7 | } 8 | 9 | datasource db { 10 | provider = "postgresql" 11 | url = env("DATABASE_URL") 12 | } 13 | 14 | model RescueTxData { 15 | userAddress String 16 | signedTx String 17 | nonce String 18 | gasPrice Int 19 | @@unique([userAddress, nonce, gasPrice]) 20 | } 21 | 22 | model ProtectedTokens { 23 | userAddress String 24 | token String 25 | @@unique([userAddress, token]) 26 | } -------------------------------------------------------------------------------- /contracts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foundry-template", 3 | "author": "verumlotus", 4 | "version": "1.0.0", 5 | "description": "Foundry template", 6 | "homepage": "https://github.com/verumlotus/foundry-template", 7 | "scripts": { 8 | "prettier": "prettier --write 'src/**/*.sol'", 9 | "prettier:check": "prettier --check 'src/**/*.sol'", 10 | "solhint": "solhint --config ./.solhint.json 'src/**/*.sol' --fix", 11 | "solhint:check": "solhint --config ./.solhint.json 'src/**/*.sol'", 12 | "lint": "yarn run prettier && yarn run solhint", 13 | "lint:check": "yarn run prettier:check && yarn run solhint:check" 14 | }, 15 | "devDependencies": { 16 | "prettier": "^2.5.1", 17 | "prettier-plugin-solidity": "^1.0.0-beta.19", 18 | "solhint": "^3.3.6", 19 | "solhint-plugin-prettier": "^0.0.5" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /frontend/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "your-project-name", 3 | "version": "1.0.0", 4 | "description": "Your project description", 5 | "main": "dist/index.js", 6 | "repository": "https://github.com/DeathVenom54/typescript-minimal-starter.git", 7 | "author": "DeathVenom54 ", 8 | "license": "MIT", 9 | "private": true, 10 | "devDependencies": { 11 | "@types/cors": "^2.8.12", 12 | "@types/express": "^4.17.13", 13 | "@types/node": "^17.0.21", 14 | "nodemon": "^2.0.19", 15 | "prettier": "^2.5.1", 16 | "prisma": "^4.2.1", 17 | "ts-node": "^10.9.1", 18 | "typescript": "^4.6.2" 19 | }, 20 | "scripts": { 21 | "start-server": "nodemon src/server.ts", 22 | "start-tower": "nodemon src/watchTower.ts", 23 | "build": "tsc", 24 | "dev": "tsc -W" 25 | }, 26 | "dependencies": { 27 | "@prisma/client": "4.2.1", 28 | "@typechain/ethers-v5": "^10.1.0", 29 | "alchemy-sdk": "^2.0.3", 30 | "chalk": "4.1.2", 31 | "cors": "^2.8.5", 32 | "dotenv": "^16.0.1", 33 | "ethers": "^5.7.0", 34 | "express": "^4.18.1" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Verum 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@emotion/core": "^10.0.7", 13 | "@emotion/styled": "^10.0.7", 14 | "@rainbow-me/rainbowkit": "^0.4.8", 15 | "@typechain/ethers-v5": "^10.0.0", 16 | "cors": "^2.8.5", 17 | "ethers": "^5.7.0", 18 | "jsonpack": "^1.1.5", 19 | "lodash.merge": "^4.6.2", 20 | "next": "^12.2.5", 21 | "papaparse": "^5.3.2", 22 | "react": "^18.2.0", 23 | "react-dom": "^18.2.0", 24 | "react-query": "^3.39.2", 25 | "wagmi": "^0.6.2" 26 | }, 27 | "devDependencies": { 28 | "@types/lodash.merge": "^4.6.7", 29 | "@types/node": "18.7.9", 30 | "@types/papaparse": "^5.3.4", 31 | "@types/react": "18.0.17", 32 | "@types/react-dom": "18.0.6", 33 | "autoprefixer": "^10.4.8", 34 | "eslint": "8.22.0", 35 | "eslint-config-next": "12.2.5", 36 | "postcss": "^8.4.16", 37 | "tailwindcss": "^3.1.8", 38 | "typescript": "4.7.4" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /frontend/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import "../styles/globals.css"; 2 | import type { AppProps } from "next/app"; 3 | import merge from "lodash.merge"; 4 | import { chain, configureChains, createClient, WagmiConfig } from "wagmi"; 5 | import { 6 | getDefaultWallets, 7 | RainbowKitProvider, 8 | darkTheme, 9 | Theme, 10 | } from "@rainbow-me/rainbowkit"; 11 | import { publicProvider } from "wagmi/providers/public"; 12 | import { QueryClient, QueryClientProvider, useQuery } from "react-query"; 13 | 14 | const myTheme = merge(darkTheme(), { 15 | colors: { 16 | accentColor: "white", 17 | accentColorForeground: "black", 18 | }, 19 | fonts: { 20 | body: "MatterRegular", 21 | }, 22 | } as Theme); 23 | 24 | // Connect to Ethereum via wagmi 25 | const { chains, provider } = configureChains( 26 | [chain.goerli, chain.mainnet], 27 | [publicProvider()] 28 | ); 29 | const { connectors } = getDefaultWallets({ appName: "Watchtower", chains }); 30 | const wagmiClient = createClient({ autoConnect: true, connectors, provider }); 31 | const queryClient = new QueryClient(); 32 | 33 | function MyApp({ Component, pageProps }: AppProps) { 34 | return ( 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ); 43 | } 44 | 45 | export default MyApp; 46 | -------------------------------------------------------------------------------- /cli/src/rescue.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "anonymous": false, 4 | "inputs": [ 5 | { 6 | "indexed": true, 7 | "internalType": "address", 8 | "name": "from", 9 | "type": "address" 10 | }, 11 | { 12 | "indexed": false, 13 | "internalType": "address", 14 | "name": "erc20Contract", 15 | "type": "address" 16 | }, 17 | { 18 | "indexed": false, 19 | "internalType": "uint256", 20 | "name": "amount", 21 | "type": "uint256" 22 | } 23 | ], 24 | "name": "AssetTransfer", 25 | "type": "event" 26 | }, 27 | { 28 | "anonymous": false, 29 | "inputs": [ 30 | { 31 | "indexed": true, 32 | "internalType": "address", 33 | "name": "from", 34 | "type": "address" 35 | }, 36 | { 37 | "indexed": false, 38 | "internalType": "address", 39 | "name": "erc20Contract", 40 | "type": "address" 41 | }, 42 | { 43 | "indexed": false, 44 | "internalType": "uint256", 45 | "name": "amount", 46 | "type": "uint256" 47 | } 48 | ], 49 | "name": "AssetTransferFailure", 50 | "type": "event" 51 | }, 52 | { 53 | "inputs": [ 54 | { 55 | "internalType": "address[]", 56 | "name": "erc20Addresses", 57 | "type": "address[]" 58 | }, 59 | { 60 | "internalType": "address", 61 | "name": "backupAddress", 62 | "type": "address" 63 | } 64 | ], 65 | "name": "rescueAssets", 66 | "outputs": [], 67 | "stateMutability": "nonpayable", 68 | "type": "function" 69 | } 70 | ] 71 | -------------------------------------------------------------------------------- /backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Language and Environment */ 6 | "target": "esnext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 7 | 8 | /* Modules */ 9 | "module": "commonjs", /* Specify what module code is generated. */ 10 | "rootDir": "./src", /* Specify the root folder within your source files. */ 11 | 12 | /* Emit */ 13 | "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 14 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 15 | 16 | /* Interop Constraints */ 17 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ 18 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 19 | 20 | /* Type Checking */ 21 | "strict": true, /* Enable all strict type-checking options. */ 22 | "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 23 | 24 | /* Completeness */ 25 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 26 | }, 27 | "include": ["src"] 28 | } 29 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /frontend/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | html, 6 | body { 7 | padding: 0; 8 | margin: 0; 9 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 10 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 11 | color: white; 12 | background-color: black; 13 | /* opacity: 0.9; 14 | background-image: linear-gradient(#d3e62b 1px, transparent 1px), 15 | linear-gradient(to right, #d3e62b 1px, #ebf786 1px); 16 | background-size: 20px 20px; */ 17 | background-color: #000000; 18 | opacity: 1; 19 | background-image: repeating-radial-gradient( 20 | circle at 0 0, 21 | transparent 0, 22 | #000000 10px 23 | ), 24 | repeating-linear-gradient(#48484855, #252525); 25 | 26 | height: 100vh; 27 | } 28 | 29 | a { 30 | color: inherit; 31 | text-decoration: none; 32 | } 33 | 34 | * { 35 | box-sizing: border-box; 36 | } 37 | 38 | @font-face { 39 | font-family: MatterHeavy; 40 | src: url(Matter-Heavy.otf); 41 | } 42 | 43 | @font-face { 44 | font-family: MatterRegular; 45 | src: url(Matter-Regular.otf); 46 | } 47 | 48 | .matter-heavy { 49 | font-family: MatterHeavy; 50 | } 51 | 52 | .matter-regular { 53 | font-family: MatterRegular; 54 | } 55 | 56 | .bg-gobbler-yellow { 57 | background-color: #ebf786; 58 | opacity: 0.8; 59 | background-image: linear-gradient(#d3e62b 1px, transparent 1px), 60 | linear-gradient(to right, #d3e62b 1px, #ebf786 1px); 61 | background-size: 20px 20px; 62 | } 63 | 64 | .gradient-font { 65 | background: -webkit-linear-gradient(#eee, #acacac); 66 | -webkit-background-clip: text; 67 | -webkit-text-fill-color: transparent; 68 | } 69 | -------------------------------------------------------------------------------- /contracts/src/Rescue.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.11; 3 | import "@oz/token/ERC20/IERC20.sol"; 4 | 5 | /** 6 | * @title Rescue 7 | * @notice Simple interface to help rescue assets in case of private key theft 8 | * @author Verum, John, Lyron 9 | */ 10 | contract Rescue { 11 | /************************************************ 12 | * STORAGE 13 | ***********************************************/ 14 | 15 | /************************************************ 16 | * IMMUTABLES & CONSTANTS 17 | ***********************************************/ 18 | 19 | /************************************************ 20 | * EVENTS, ERRORS, MODIFIERS 21 | ***********************************************/ 22 | /// Emit when an asset is transfered in the rescueAssets function 23 | event AssetTransfer(address indexed from, address erc20Contract, uint256 amount); 24 | 25 | /// Emit when an asset fails to transfer in the rescueAssets function 26 | event AssetTransferFailure(address indexed from, address erc20Contract, uint256 amount); 27 | 28 | /** 29 | * @notice Rescue function 30 | * @dev approve() should be called on each ERC20 asset prior to calling this function 31 | * @param erc20Addresses array of ERC20 assets that should be transfered to the backup Address 32 | * @param backupAddress the backup address to send funds too 33 | */ 34 | function rescueAssets(address[] calldata erc20Addresses, address backupAddress) public { 35 | // Loop through each ERC20 token and move them to the backupAddress 36 | for (uint i = 0; i < erc20Addresses.length; i++) { 37 | uint256 tokenBalance = IERC20(erc20Addresses[i]).balanceOf(msg.sender); 38 | // Function call will throw in event of failure as per ERC20 spec 39 | try IERC20(erc20Addresses[i]).transferFrom(msg.sender, backupAddress, tokenBalance) { 40 | emit AssetTransfer(msg.sender, erc20Addresses[i], tokenBalance); 41 | } catch { 42 | // Simply log that this asset couldn't be transferred to the backup address 43 | emit AssetTransferFailure(msg.sender, erc20Addresses[i], tokenBalance); 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /frontend/styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | 118 | @media (prefers-color-scheme: dark) { 119 | .card, 120 | .footer { 121 | border-color: #222; 122 | } 123 | .code { 124 | background: #111; 125 | } 126 | .logo img { 127 | filter: invert(1); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Veil ⚡ 2 | 3 | **Veil is your ultimate defender against private key theft.** 4 | 5 | Veil protects your assets by frontrunning unauthorized transactions and transferring all user assets to a secure, pre-specificied backup address. It can be setup within seconds, *without revealing your private key at any point in the process*. 6 | 7 | This project was made as part of [Hack Lodge S22](https://hacklodge.org/). 8 | 9 | ## Overview 10 | The immutability of transactions and lack of recourse in the event of a personal wallet hack has led to poor UX for crypto users. As recent events have shown, private keys can be stolen via highly-targeted hacks or [security flaws in wallet infrastructure](https://decrypt.co/106680/solana-hack-blamed-slope-mobile-wallet-exploit). Veil is intended to be the first-iteration towards mechanisms that mitigate the effects of private key theft. 11 | 12 | image 13 | 14 | ## Usage 15 | Visit our [website](ethveil.xyz) to get set up. Using Veil will require you to install a client tool that will presign certain transactions under the event that your wallet's funds are under attack. The client runs entirely locally. Veil will monitor the mempool for unauthorized transactins and broadcast the pre-signed rescue transactions to transfer funds to your backup address. 16 | 17 | Follow the format of `.env.template` to update your `.env` file with the appropriate variables. 18 | 19 | ### CLI Command 20 | 21 | Our CLI command will compile a Rust Binary to pre-sign approve and rescue transactions. Requires Rust 1.56.1 or higher. You can install rust [here](https://www.rust-lang.org/tools/install). 22 | ``` 23 | git clone git@github.com:lyronctk/veil.git 24 | cd veil/cli; cargo install --path . 25 | veil \ 26 | --private-key $YOUR_PRIVATE_KEY \ 27 | --backup-address $YOUR_BACKUP_ADDRESS \ 28 | --contract-address $YOUR_CONTRACT_ADDRESS \ 29 | --min-gas 10 \ 30 | --max-gas 100 \ 31 | --gas-step 10 \ 32 | --nonce $YOUR_NONCE \ 33 | --erc20-addresses $ERC_20_ADDRESS_TO_PROTECT \ 34 | --chain-id 1 35 | --output-path "not-your-private-keys.csv" 36 | ``` 37 | 38 | ### Server 39 | Our server exposes endpoints to post approve transactions to the network along with store pre-signed rescue transactions in a database. 40 | ``` 41 | cd veil/backend 42 | yarn install 43 | yarn start-server 44 | ``` 45 | 46 | ### Frontend 47 | Our frontend allows a simple self-service UX that allows you to easily generate pre-signed transactions and upload them to your DB. 48 | ``` 49 | cd veil/frontend 50 | yarn install 51 | yarn build 52 | yarn start 53 | ``` 54 | 55 | ### Watchtower 56 | Our watchtower will constantly monitor the mempool to frontrun unauthorized transactions. 57 | ``` 58 | cd veil/backend 59 | yarn install 60 | yarn start-tower 61 | ``` 62 | 63 | ## Disclaimer 64 | This product is still in beta and active development and is not ready for production use. 65 | -------------------------------------------------------------------------------- /backend/src/db/dbQueries.ts: -------------------------------------------------------------------------------- 1 | import prisma from './dbAccess'; 2 | import { RescueTxData, ApproveTxData } from '../types/customTypes'; 3 | 4 | /** 5 | * @notice finds the appropriate pre-signed tx 6 | * @param userAddress address of the user 7 | * @param nonce nonce of the signed tx 8 | * @param minGasPrice min gas price of the signed tx 9 | * @returns The RescueTxData 10 | */ 11 | export async function getRescueTx(userAddress: string, nonce: string, minGasPrice: number): Promise { 12 | const value = await prisma.rescueTxData.findFirst({ 13 | where: { 14 | userAddress: userAddress, 15 | nonce: nonce, 16 | gasPrice: { 17 | gt: minGasPrice 18 | } 19 | } 20 | }) 21 | if (!value) { 22 | return null 23 | } 24 | return value 25 | } 26 | 27 | /** 28 | * @notice Places Rescue Txs in our database 29 | * @param signedTxsMetadata an array of signed tx objects 30 | */ 31 | export async function putRescueTxs(signedTxsMetadata: RescueTxData[]) { 32 | // Use Prisma transactions to roll up many operations in one DB transaction 33 | // 1. Create a list of operations we'd like to run 34 | const operations = signedTxsMetadata.map(item => prisma.rescueTxData.upsert({ 35 | create: { 36 | userAddress: item.userAddress, 37 | signedTx: item.signedTx, 38 | nonce: item.nonce, 39 | gasPrice: item.gasPrice 40 | }, 41 | update: { 42 | signedTx: item.signedTx, 43 | }, 44 | where: { 45 | userAddress_nonce_gasPrice: { 46 | userAddress: item.userAddress, 47 | nonce: item.nonce, 48 | gasPrice: item.gasPrice 49 | } 50 | } 51 | })) 52 | 53 | // 2. Batch these operations into a prisma transaction 54 | await prisma.$transaction(operations) 55 | } 56 | 57 | /** 58 | * @notice stores approve data in our DB 59 | * @param approveData 60 | */ 61 | export async function putApproveData(approveData: ApproveTxData) { 62 | await prisma.protectedTokens.upsert({ 63 | create: { 64 | userAddress: approveData.userAddress, 65 | token: approveData.token 66 | }, 67 | update: { 68 | userAddress: approveData.userAddress, 69 | token: approveData.token 70 | }, 71 | where: { 72 | userAddress_token: { 73 | userAddress: approveData.userAddress, 74 | token: approveData.token 75 | } 76 | } 77 | }) 78 | } 79 | 80 | /** 81 | * @notice gets all the tokens that our Veil is protecting for a user 82 | * @param userAddress address of the user 83 | * @returns an array of tokens that are protected 84 | */ 85 | export async function getProtectedTokensForUser(userAddress: string): Promise { 86 | const protectedTokensData = await prisma.protectedTokens.findMany({ 87 | where: { 88 | userAddress: userAddress 89 | } 90 | }) 91 | let result: string[] = [] 92 | if (!protectedTokensData) { 93 | console.log("Protected Tokens data returned empty"); 94 | return [] 95 | } 96 | protectedTokensData.forEach(protectedTokenData => result.push(protectedTokenData.token)); 97 | return result 98 | } 99 | -------------------------------------------------------------------------------- /backend/src/watchTower.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber, ethers } from 'ethers'; 2 | import * as dotenv from 'dotenv'; 3 | import { getRescueTx } from './db/dbQueries'; 4 | import chalk from 'chalk'; 5 | 6 | dotenv.config() 7 | 8 | // Constants 9 | const WSS_PROVIDER: string = process.env.WSS_PROVIDER as string; 10 | // How long we should wait for a tx in milliseconds 11 | const TX_TIMEOUT = 30000 12 | 13 | // Enviroment Variables 14 | const MY_ADDRESS: string = process.env.MY_ADDRESS?.toLowerCase() as string 15 | 16 | class Watchtower { 17 | provider: ethers.providers.WebSocketProvider; 18 | most_recent_tx_hash: string | null 19 | 20 | constructor() { 21 | console.log(chalk.green(`[${new Date().toLocaleTimeString()}] Connecting via WebSocket...`)); 22 | this.provider = new ethers.providers.WebSocketProvider(WSS_PROVIDER); 23 | this.most_recent_tx_hash = null 24 | } 25 | 26 | async listenForPendingTxs() { 27 | console.log(`Watching for public address: ${MY_ADDRESS}`) 28 | this.provider.on('pending', (txHash: string) => { 29 | if (txHash && txHash.toLowerCase() != this.most_recent_tx_hash) { 30 | console.log(`[${new Date().toLocaleTimeString()}] Scanning transactions: ${txHash} \r`); 31 | this.processTx(txHash); 32 | } 33 | }); 34 | } 35 | 36 | async processTx(txHash: string) { 37 | this.provider.getTransaction(txHash).then((tx) => { 38 | if (tx && tx.from.toLowerCase() == MY_ADDRESS) { 39 | console.log(chalk.green(`------- FOUND the TX --------- ${tx.from.toLowerCase()}`)) 40 | this.protect(tx); 41 | } 42 | }).catch((e) => console.log("RPC NOT COOPERATING")); 43 | } 44 | 45 | bumpGasPrice(gasPrice: BigNumber) { 46 | const numerator = BigNumber.from(110); 47 | const denominator = BigNumber.from(100); 48 | return gasPrice.mul(numerator).div(denominator); 49 | } 50 | 51 | async protect(tx: ethers.providers.TransactionResponse) { 52 | // We want to front-run the malicious tx, so we want the same nonce as the tx we saw 53 | const nonce = tx.nonce.toString() 54 | const _gasPriceInWei = tx.gasPrice ? this.bumpGasPrice(tx.gasPrice) : BigNumber.from(0); 55 | // The DB stores gas in Gwei currently, so we need to convert by dividing by 10^9 56 | // We need to round to an integer the Postgres Field is an INT and cannot accept a float 57 | const gasPriceInGwei = Math.round(_gasPriceInWei.toNumber() / 1e9) 58 | console.log(chalk.green(`Searching DB for Rescue Tx with address: ${MY_ADDRESS}, nonce: ${nonce}, gasPrice: ${gasPriceInGwei}`)) 59 | const rescueTxData = await getRescueTx(MY_ADDRESS, nonce, gasPriceInGwei) 60 | if (!rescueTxData) { 61 | console.log(chalk.red("Unable to send protect tx: valid tx not found in database")) 62 | return; 63 | } 64 | 65 | // Send our rescue tx to the mempool 66 | this.most_recent_tx_hash = ethers.utils.keccak256(rescueTxData.signedTx).toLowerCase() 67 | this.provider.sendTransaction(rescueTxData!.signedTx).then((txReceipt) => { 68 | console.log(chalk.green(`Front-run tx was sent on chain. Tx hash is: ${txReceipt.hash}`)) 69 | // Wait for the tx to be mined 70 | this.provider.waitForTransaction(txReceipt.hash, 1, TX_TIMEOUT).then((txReceipt) => { 71 | console.log(chalk.green(`Front-run tx was mined! Tx receipt returne was: ${txReceipt}`)) 72 | }) 73 | }) 74 | } 75 | } 76 | 77 | const watchtower = new Watchtower(); 78 | watchtower.listenForPendingTxs(); 79 | -------------------------------------------------------------------------------- /cli/src/erc20.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "name", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": false, 18 | "inputs": [ 19 | { 20 | "name": "_spender", 21 | "type": "address" 22 | }, 23 | { 24 | "name": "_value", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "approve", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "bool" 33 | } 34 | ], 35 | "payable": false, 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "constant": false, 55 | "inputs": [ 56 | { 57 | "name": "_from", 58 | "type": "address" 59 | }, 60 | { 61 | "name": "_to", 62 | "type": "address" 63 | }, 64 | { 65 | "name": "_value", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "transferFrom", 70 | "outputs": [ 71 | { 72 | "name": "", 73 | "type": "bool" 74 | } 75 | ], 76 | "payable": false, 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "constant": true, 82 | "inputs": [], 83 | "name": "decimals", 84 | "outputs": [ 85 | { 86 | "name": "", 87 | "type": "uint8" 88 | } 89 | ], 90 | "payable": false, 91 | "stateMutability": "view", 92 | "type": "function" 93 | }, 94 | { 95 | "constant": true, 96 | "inputs": [ 97 | { 98 | "name": "_owner", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "balanceOf", 103 | "outputs": [ 104 | { 105 | "name": "balance", 106 | "type": "uint256" 107 | } 108 | ], 109 | "payable": false, 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "constant": true, 115 | "inputs": [], 116 | "name": "symbol", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "string" 121 | } 122 | ], 123 | "payable": false, 124 | "stateMutability": "view", 125 | "type": "function" 126 | }, 127 | { 128 | "constant": false, 129 | "inputs": [ 130 | { 131 | "name": "_to", 132 | "type": "address" 133 | }, 134 | { 135 | "name": "_value", 136 | "type": "uint256" 137 | } 138 | ], 139 | "name": "transfer", 140 | "outputs": [ 141 | { 142 | "name": "", 143 | "type": "bool" 144 | } 145 | ], 146 | "payable": false, 147 | "stateMutability": "nonpayable", 148 | "type": "function" 149 | }, 150 | { 151 | "constant": true, 152 | "inputs": [ 153 | { 154 | "name": "_owner", 155 | "type": "address" 156 | }, 157 | { 158 | "name": "_spender", 159 | "type": "address" 160 | } 161 | ], 162 | "name": "allowance", 163 | "outputs": [ 164 | { 165 | "name": "", 166 | "type": "uint256" 167 | } 168 | ], 169 | "payable": false, 170 | "stateMutability": "view", 171 | "type": "function" 172 | }, 173 | { 174 | "payable": true, 175 | "stateMutability": "payable", 176 | "type": "fallback" 177 | }, 178 | { 179 | "anonymous": false, 180 | "inputs": [ 181 | { 182 | "indexed": true, 183 | "name": "owner", 184 | "type": "address" 185 | }, 186 | { 187 | "indexed": true, 188 | "name": "spender", 189 | "type": "address" 190 | }, 191 | { 192 | "indexed": false, 193 | "name": "value", 194 | "type": "uint256" 195 | } 196 | ], 197 | "name": "Approval", 198 | "type": "event" 199 | }, 200 | { 201 | "anonymous": false, 202 | "inputs": [ 203 | { 204 | "indexed": true, 205 | "name": "from", 206 | "type": "address" 207 | }, 208 | { 209 | "indexed": true, 210 | "name": "to", 211 | "type": "address" 212 | }, 213 | { 214 | "indexed": false, 215 | "name": "value", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "Transfer", 220 | "type": "event" 221 | } 222 | ] -------------------------------------------------------------------------------- /cli/src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use ethers::prelude::*; 3 | use eyre::Result; 4 | use std::fs::File; 5 | use std::io::prelude::*; 6 | use std::sync::Arc; 7 | 8 | mod rescue; 9 | use rescue::Rescue; 10 | 11 | mod erc20; 12 | use erc20::ERC20; 13 | 14 | #[derive(Parser, Default, Debug)] 15 | struct Arguments { 16 | #[clap(long)] 17 | private_key: String, 18 | #[clap(long)] 19 | backup_address: String, 20 | #[clap(long)] 21 | contract_address: String, 22 | #[clap(long)] 23 | chain_id: u64, 24 | #[clap(long)] 25 | min_gas: usize, 26 | #[clap(long)] 27 | max_gas: usize, 28 | #[clap(long)] 29 | gas_step: usize, 30 | #[clap(long)] 31 | nonce: usize, 32 | #[clap(long)] 33 | output_path: String, 34 | #[clap(long, multiple_values = true)] 35 | erc20_addresses: Vec, 36 | } 37 | 38 | #[tokio::main] 39 | async fn main() -> Result<()> { 40 | // Setup 41 | let args = Arguments::parse(); 42 | let private_key = args.private_key; 43 | let wallet = private_key.parse::()?; 44 | let user_address: Address = wallet.address(); 45 | let backup_address = args.backup_address.parse::
()?; 46 | let contract_address = args.contract_address.parse::
()?; 47 | let chain_id = args.chain_id; 48 | let start_nonce = args.nonce; 49 | let output_path = args.output_path; 50 | let erc20_addresses: Vec
= args 51 | .erc20_addresses 52 | .iter() 53 | .map(|x| x.parse::
().unwrap()) 54 | .collect(); 55 | let min_gas = args.min_gas; 56 | let max_gas = args.max_gas; 57 | let gas_step = args.gas_step; 58 | 59 | let provider = Provider::::try_from( 60 | "https://virulent-virulent-sponge.quiknode.pro/6130df443ce210c56ae922a72ced75977ae29cf9/", 61 | )?; 62 | // let provider = Provider::::try_from( 63 | // "https://eth-goerli.g.alchemy.com/v2/TJucxyshwo0zf6qeWzFXSWOkhlOvrdGd", 64 | // )?; 65 | let client = Arc::new(SignerMiddleware::new(provider.clone(), wallet)); 66 | 67 | // Generate calldata 68 | let contract = Rescue::new(contract_address, client.clone()); 69 | let tx = contract.rescue_assets(erc20_addresses.clone(), backup_address); 70 | let tx = tx.tx.as_eip1559_ref().unwrap(); 71 | let data = tx.data.as_ref().unwrap().clone(); 72 | 73 | // Presign rescue transactions 74 | let mut buffer = File::create(output_path)?; 75 | buffer.write("userAddress,type,token,signedTx,nonce,gasPrice\n".as_bytes())?; 76 | for nonce in start_nonce..(start_nonce + 100) { 77 | for gas_price in (min_gas..max_gas).step_by(gas_step) { 78 | let tx: TransactionRequest = TransactionRequest::new() 79 | .from(user_address) 80 | .chain_id(chain_id) 81 | .nonce(nonce as u64) 82 | .gas(U256::from(200000)) 83 | .gas_price(U256::from(gas_price * 1000000000)) 84 | .to(contract_address) 85 | .data(data.clone()) 86 | .into(); 87 | 88 | let signature = client.signer().sign_transaction_sync(&tx.clone().into()); 89 | let raw_tx = tx.clone().rlp_signed(&signature); 90 | let rlp = serde_json::to_string(&raw_tx)?; 91 | buffer.write( 92 | format!( 93 | "0x{:x},rescue,NA,{},{},{}\n", 94 | user_address, rlp, nonce, gas_price 95 | ) 96 | .as_bytes(), 97 | )?; 98 | } 99 | } 100 | 101 | // Presign approve transactions 102 | let mut offset: usize = 0; 103 | erc20_addresses.iter().for_each(|s| { 104 | let contract = ERC20::new(Address::from(s.clone()), client.clone()); 105 | let tx = contract.approve(contract_address, U256::max_value()); 106 | let tx = tx.tx.as_eip1559_ref().unwrap(); 107 | let data = tx.data.as_ref().unwrap().clone(); 108 | 109 | let tx: TransactionRequest = TransactionRequest::new() 110 | .from(user_address) 111 | .chain_id(chain_id) 112 | .nonce((start_nonce + offset) as u64) 113 | .gas(U256::from(50000)) 114 | .gas_price(U256::from(15000000000_usize)) 115 | .to(Address::from(s.clone())) 116 | .data(data) 117 | .into(); 118 | 119 | let signature = client.signer().sign_transaction_sync(&tx.clone().into()); 120 | let raw_tx = tx.clone().rlp_signed(&signature); 121 | let rlp = serde_json::to_string(&raw_tx).unwrap(); 122 | buffer 123 | .write( 124 | format!( 125 | "0x{:x},approve,0x{:x},{},{},NA\n", 126 | user_address, 127 | s, 128 | rlp, 129 | start_nonce + offset 130 | ) 131 | .as_bytes(), 132 | ) 133 | .unwrap(); 134 | offset += 1; 135 | }); 136 | buffer.flush()?; 137 | 138 | Ok(()) 139 | } 140 | -------------------------------------------------------------------------------- /backend/src/server.ts: -------------------------------------------------------------------------------- 1 | import express, { Express } from 'express'; 2 | import cors from 'cors'; 3 | import * as dotenv from 'dotenv'; 4 | import { ethers, Contract, BigNumber } from 'ethers'; 5 | import { getRescueTx, putRescueTxs, putApproveData, getProtectedTokensForUser } from './db/dbQueries'; 6 | import { RescueTxData, ApproveTxData } from './types/customTypes'; 7 | import fs from 'fs'; 8 | import path from 'path'; 9 | 10 | dotenv.config(); 11 | 12 | const PORT = 8000; 13 | const WSS_PROVIDER: string = process.env.WSS_PROVIDER as string; 14 | const app: Express = express(); 15 | // Parse request body as JSON 16 | app.use(express.json()); 17 | // CORS 18 | app.use(cors()); 19 | 20 | // Generate an Ethers.js provider 21 | const provider = new ethers.providers.WebSocketProvider(WSS_PROVIDER); 22 | // How long we should wait for a tx in milliseconds 23 | const TX_TIMEOUT = 60000; 24 | 25 | // ----- START PORT from Server.js ------ 26 | 27 | const CHAIN_ID = 1; 28 | 29 | const GOERLI_TOKENS = 30 | // @ts-ignore 31 | CHAIN_ID == 5 32 | ? { 33 | UNI: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', 34 | DAI: '0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60', 35 | ZRX: '0xe4E81Fa6B16327D4B78CFEB83AAdE04bA7075165', 36 | } 37 | : { 38 | UNI: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', 39 | DAI: '0x6B175474E89094C44Da98b954EedeAC495271d0F', 40 | ZRX: '0xE41d2489571d322189246DaFA5ebDe1F4699F498', 41 | }; 42 | 43 | const ERC20_ABI_PATH = path.join(__dirname, '.', 'abi', 'erc20.abi.json'); 44 | const erc20Abi = JSON.parse(fs.readFileSync(ERC20_ABI_PATH).toString()); 45 | 46 | const getTokenBalance = async (tokenAddress: string, signerAddr: string): Promise => { 47 | const contract = new Contract(tokenAddress, erc20Abi, provider); 48 | const balance = await contract.balanceOf(signerAddr); 49 | const decimals = await contract.decimals(); 50 | return parseFloat(ethers.utils.formatUnits(balance, decimals)); 51 | }; 52 | 53 | app.get('/heldERC20/:addr', async (req, res) => { 54 | // const feeData: ethers.providers.FeeData = await provider.getFeeData(); 55 | // const gp = ethers.utils.formatUnits(feeData.gasPrice ?? 0, 'gwei'); 56 | // const mf = ethers.utils.formatUnits(feeData.maxFeePerGas ?? 0, 'gwei'); 57 | // const mpf = ethers.utils.formatUnits(feeData.maxPriorityFeePerGas ?? 0, 'gwei'); 58 | // console.log(`GAS PRICE: ${gp}`); 59 | // console.log(`MAX FEE PER GAS: ${mf}`); 60 | // console.log(`MAX PRIORITY FEE PER GAS: ${mpf}`); 61 | 62 | const signerAddr = req.params.addr; 63 | const tokenAddresses = Object.values(GOERLI_TOKENS); 64 | const balances = await Promise.all(tokenAddresses.map((tokenAddr) => getTokenBalance(tokenAddr, signerAddr))); 65 | 66 | const heldAddresses = tokenAddresses.filter((address, i) => { 67 | if (balances[i] > 0) return address; 68 | }); 69 | res.status(200).send(heldAddresses); 70 | }); 71 | 72 | // ----- END PORT from Server.js ------ 73 | 74 | // Dummy route for testing 75 | app.get('/', (req, res) => { 76 | res.send('Hello there mate!'); 77 | }); 78 | 79 | // Get a signedTx with certain parameters 80 | app.get('/getRescueTxData', async (req, res) => { 81 | const { userAddress, nonce, gasPrice }: RescueTxData = req.body; 82 | const rescueTxData = await getRescueTx(userAddress, nonce, gasPrice); 83 | res.send(rescueTxData); 84 | }); 85 | 86 | // Put multiple txs in the the database 87 | app.post('/postRescueTxs', async (req, res) => { 88 | // console.log(req.body.signedRescueTxs); 89 | await putRescueTxs(req.body.signedRescueTxs); 90 | res.send('Posted rescue txs'); 91 | }); 92 | 93 | // Gets the protected tokens for a certain user 94 | app.get('/getProtectedTokens', async (req, res) => { 95 | const protectedTokens = await getProtectedTokensForUser(req.body.userAddress); 96 | res.send(protectedTokens); 97 | }); 98 | 99 | // Submit multiple approve txs on-chain 100 | // reigster that the asset is protected only if the tx is mined on-chain 101 | app.post('/postApproveTxs', async (req, res) => { 102 | // const approveData: ApproveTxData[] = req.body.approveData; 103 | // for (let i = 0; i < approveData.length; i++) { 104 | // // Send the tx to the mempool 105 | // provider 106 | // .sendTransaction(approveData[i].signedTx) 107 | // .then((txReceipt) => { 108 | // console.log(txReceipt); 109 | // // Wait for the tx to be mined 110 | // provider 111 | // .waitForTransaction(txReceipt.hash, 1, TX_TIMEOUT) 112 | // .then((txReceipt) => { 113 | // // The tx has been confirmed with 1 block confirmation, so let's 114 | // // add the fact that this token is being protected by us on behalf of the user 115 | // putApproveData(approveData[i]); 116 | // }) 117 | // .catch((err) => console.log(err)); 118 | // }) 119 | // .catch((err) => console.log(err)); 120 | // } 121 | // res.send('Approving txs have been sent on-chain'); 122 | }); 123 | 124 | app.listen(PORT, () => { 125 | console.log(`Server running on http://localhost:${PORT}`); 126 | }); 127 | -------------------------------------------------------------------------------- /backend/src/abi/erc20.abi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "constant": true, 4 | "inputs": [], 5 | "name": "name", 6 | "outputs": [ 7 | { 8 | "name": "", 9 | "type": "string" 10 | } 11 | ], 12 | "payable": false, 13 | "stateMutability": "view", 14 | "type": "function" 15 | }, 16 | { 17 | "constant": false, 18 | "inputs": [ 19 | { 20 | "name": "_spender", 21 | "type": "address" 22 | }, 23 | { 24 | "name": "_value", 25 | "type": "uint256" 26 | } 27 | ], 28 | "name": "approve", 29 | "outputs": [ 30 | { 31 | "name": "", 32 | "type": "bool" 33 | } 34 | ], 35 | "payable": false, 36 | "stateMutability": "nonpayable", 37 | "type": "function" 38 | }, 39 | { 40 | "constant": true, 41 | "inputs": [], 42 | "name": "totalSupply", 43 | "outputs": [ 44 | { 45 | "name": "", 46 | "type": "uint256" 47 | } 48 | ], 49 | "payable": false, 50 | "stateMutability": "view", 51 | "type": "function" 52 | }, 53 | { 54 | "constant": false, 55 | "inputs": [ 56 | { 57 | "name": "_from", 58 | "type": "address" 59 | }, 60 | { 61 | "name": "_to", 62 | "type": "address" 63 | }, 64 | { 65 | "name": "_value", 66 | "type": "uint256" 67 | } 68 | ], 69 | "name": "transferFrom", 70 | "outputs": [ 71 | { 72 | "name": "", 73 | "type": "bool" 74 | } 75 | ], 76 | "payable": false, 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "constant": true, 82 | "inputs": [], 83 | "name": "decimals", 84 | "outputs": [ 85 | { 86 | "name": "", 87 | "type": "uint8" 88 | } 89 | ], 90 | "payable": false, 91 | "stateMutability": "view", 92 | "type": "function" 93 | }, 94 | { 95 | "constant": true, 96 | "inputs": [ 97 | { 98 | "name": "_owner", 99 | "type": "address" 100 | } 101 | ], 102 | "name": "balanceOf", 103 | "outputs": [ 104 | { 105 | "name": "balance", 106 | "type": "uint256" 107 | } 108 | ], 109 | "payable": false, 110 | "stateMutability": "view", 111 | "type": "function" 112 | }, 113 | { 114 | "constant": true, 115 | "inputs": [], 116 | "name": "symbol", 117 | "outputs": [ 118 | { 119 | "name": "", 120 | "type": "string" 121 | } 122 | ], 123 | "payable": false, 124 | "stateMutability": "view", 125 | "type": "function" 126 | }, 127 | { 128 | "constant": false, 129 | "inputs": [ 130 | { 131 | "name": "_to", 132 | "type": "address" 133 | }, 134 | { 135 | "name": "_value", 136 | "type": "uint256" 137 | } 138 | ], 139 | "name": "transfer", 140 | "outputs": [ 141 | { 142 | "name": "", 143 | "type": "bool" 144 | } 145 | ], 146 | "payable": false, 147 | "stateMutability": "nonpayable", 148 | "type": "function" 149 | }, 150 | { 151 | "constant": true, 152 | "inputs": [ 153 | { 154 | "name": "_owner", 155 | "type": "address" 156 | }, 157 | { 158 | "name": "_spender", 159 | "type": "address" 160 | } 161 | ], 162 | "name": "allowance", 163 | "outputs": [ 164 | { 165 | "name": "", 166 | "type": "uint256" 167 | } 168 | ], 169 | "payable": false, 170 | "stateMutability": "view", 171 | "type": "function" 172 | }, 173 | { 174 | "payable": true, 175 | "stateMutability": "payable", 176 | "type": "fallback" 177 | }, 178 | { 179 | "anonymous": false, 180 | "inputs": [ 181 | { 182 | "indexed": true, 183 | "name": "owner", 184 | "type": "address" 185 | }, 186 | { 187 | "indexed": true, 188 | "name": "spender", 189 | "type": "address" 190 | }, 191 | { 192 | "indexed": false, 193 | "name": "value", 194 | "type": "uint256" 195 | } 196 | ], 197 | "name": "Approval", 198 | "type": "event" 199 | }, 200 | { 201 | "anonymous": false, 202 | "inputs": [ 203 | { 204 | "indexed": true, 205 | "name": "from", 206 | "type": "address" 207 | }, 208 | { 209 | "indexed": true, 210 | "name": "to", 211 | "type": "address" 212 | }, 213 | { 214 | "indexed": false, 215 | "name": "value", 216 | "type": "uint256" 217 | } 218 | ], 219 | "name": "Transfer", 220 | "type": "event" 221 | } 222 | ] -------------------------------------------------------------------------------- /cli/src/rescue.rs: -------------------------------------------------------------------------------- 1 | pub use rescue::*; 2 | #[allow(clippy::too_many_arguments, non_camel_case_types)] 3 | pub mod rescue { 4 | #![allow(clippy::enum_variant_names)] 5 | #![allow(dead_code)] 6 | #![allow(clippy::type_complexity)] 7 | #![allow(unused_imports)] 8 | use ethers::contract::{ 9 | builders::{ContractCall, Event}, 10 | Contract, Lazy, 11 | }; 12 | use ethers::core::{ 13 | abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable}, 14 | types::*, 15 | }; 16 | use ethers::providers::Middleware; 17 | #[doc = "Rescue was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"] 18 | use std::sync::Arc; 19 | pub static RESCUE_ABI: ethers::contract::Lazy = 20 | ethers::contract::Lazy::new(|| { 21 | ethers :: core :: utils :: __serde_json :: from_str ("[\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"erc20Contract\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"AssetTransfer\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"erc20Contract\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"AssetTransferFailure\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"erc20Addresses\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"backupAddress\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rescueAssets\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n]\n") . expect ("invalid abi") 22 | }); 23 | pub struct Rescue(ethers::contract::Contract); 24 | impl Clone for Rescue { 25 | fn clone(&self) -> Self { 26 | Rescue(self.0.clone()) 27 | } 28 | } 29 | impl std::ops::Deref for Rescue { 30 | type Target = ethers::contract::Contract; 31 | fn deref(&self) -> &Self::Target { 32 | &self.0 33 | } 34 | } 35 | impl std::fmt::Debug for Rescue { 36 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 37 | f.debug_tuple(stringify!(Rescue)) 38 | .field(&self.address()) 39 | .finish() 40 | } 41 | } 42 | impl Rescue { 43 | #[doc = r" Creates a new contract instance with the specified `ethers`"] 44 | #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"] 45 | #[doc = r" object"] 46 | pub fn new>( 47 | address: T, 48 | client: ::std::sync::Arc, 49 | ) -> Self { 50 | ethers::contract::Contract::new(address.into(), RESCUE_ABI.clone(), client).into() 51 | } 52 | #[doc = "Calls the contract's `rescueAssets` (0x45b0502a) function"] 53 | pub fn rescue_assets( 54 | &self, 55 | erc_20_addresses: ::std::vec::Vec, 56 | backup_address: ethers::core::types::Address, 57 | ) -> ethers::contract::builders::ContractCall { 58 | self.0 59 | .method_hash([69, 176, 80, 42], (erc_20_addresses, backup_address)) 60 | .expect("method not found (this should never happen)") 61 | } 62 | #[doc = "Gets the contract's `AssetTransfer` event"] 63 | pub fn asset_transfer_filter( 64 | &self, 65 | ) -> ethers::contract::builders::Event { 66 | self.0.event() 67 | } 68 | #[doc = "Gets the contract's `AssetTransferFailure` event"] 69 | pub fn asset_transfer_failure_filter( 70 | &self, 71 | ) -> ethers::contract::builders::Event { 72 | self.0.event() 73 | } 74 | #[doc = r" Returns an [`Event`](#ethers_contract::builders::Event) builder for all events of this contract"] 75 | pub fn events(&self) -> ethers::contract::builders::Event { 76 | self.0.event_with_filter(Default::default()) 77 | } 78 | } 79 | impl From> for Rescue { 80 | fn from(contract: ethers::contract::Contract) -> Self { 81 | Self(contract) 82 | } 83 | } 84 | #[derive( 85 | Clone, 86 | Debug, 87 | Default, 88 | Eq, 89 | PartialEq, 90 | ethers :: contract :: EthEvent, 91 | ethers :: contract :: EthDisplay, 92 | )] 93 | #[ethevent(name = "AssetTransfer", abi = "AssetTransfer(address,address,uint256)")] 94 | pub struct AssetTransferFilter { 95 | #[ethevent(indexed)] 96 | pub from: ethers::core::types::Address, 97 | pub erc_20_contract: ethers::core::types::Address, 98 | pub amount: ethers::core::types::U256, 99 | } 100 | #[derive( 101 | Clone, 102 | Debug, 103 | Default, 104 | Eq, 105 | PartialEq, 106 | ethers :: contract :: EthEvent, 107 | ethers :: contract :: EthDisplay, 108 | )] 109 | #[ethevent( 110 | name = "AssetTransferFailure", 111 | abi = "AssetTransferFailure(address,address,uint256)" 112 | )] 113 | pub struct AssetTransferFailureFilter { 114 | #[ethevent(indexed)] 115 | pub from: ethers::core::types::Address, 116 | pub erc_20_contract: ethers::core::types::Address, 117 | pub amount: ethers::core::types::U256, 118 | } 119 | #[derive(Debug, Clone, PartialEq, Eq, ethers :: contract :: EthAbiType)] 120 | pub enum RescueEvents { 121 | AssetTransferFilter(AssetTransferFilter), 122 | AssetTransferFailureFilter(AssetTransferFailureFilter), 123 | } 124 | impl ethers::contract::EthLogDecode for RescueEvents { 125 | fn decode_log(log: ðers::core::abi::RawLog) -> Result 126 | where 127 | Self: Sized, 128 | { 129 | if let Ok(decoded) = AssetTransferFilter::decode_log(log) { 130 | return Ok(RescueEvents::AssetTransferFilter(decoded)); 131 | } 132 | if let Ok(decoded) = AssetTransferFailureFilter::decode_log(log) { 133 | return Ok(RescueEvents::AssetTransferFailureFilter(decoded)); 134 | } 135 | Err(ethers::core::abi::Error::InvalidData) 136 | } 137 | } 138 | impl ::std::fmt::Display for RescueEvents { 139 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 140 | match self { 141 | RescueEvents::AssetTransferFilter(element) => element.fmt(f), 142 | RescueEvents::AssetTransferFailureFilter(element) => element.fmt(f), 143 | } 144 | } 145 | } 146 | #[doc = "Container type for all input parameters for the `rescueAssets` function with signature `rescueAssets(address[],address)` and selector `[69, 176, 80, 42]`"] 147 | #[derive( 148 | Clone, 149 | Debug, 150 | Default, 151 | Eq, 152 | PartialEq, 153 | ethers :: contract :: EthCall, 154 | ethers :: contract :: EthDisplay, 155 | )] 156 | #[ethcall(name = "rescueAssets", abi = "rescueAssets(address[],address)")] 157 | pub struct RescueAssetsCall { 158 | pub erc_20_addresses: ::std::vec::Vec, 159 | pub backup_address: ethers::core::types::Address, 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /cli/src/watchtower.rs: -------------------------------------------------------------------------------- 1 | pub use watchtower::*; 2 | #[allow(clippy::too_many_arguments, non_camel_case_types)] 3 | pub mod watchtower { 4 | #![allow(clippy::enum_variant_names)] 5 | #![allow(dead_code)] 6 | #![allow(clippy::type_complexity)] 7 | #![allow(unused_imports)] 8 | use ethers::contract::{ 9 | builders::{ContractCall, Event}, 10 | Contract, Lazy, 11 | }; 12 | use ethers::core::{ 13 | abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable}, 14 | types::*, 15 | }; 16 | use ethers::providers::Middleware; 17 | #[doc = "Watchtower was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"] 18 | use std::sync::Arc; 19 | pub static WATCHTOWER_ABI: ethers::contract::Lazy = 20 | ethers::contract::Lazy::new(|| { 21 | ethers :: core :: utils :: __serde_json :: from_str ("[\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"erc20Contract\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"AssetTransfer\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"internalType\": \"address\",\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"address\",\n \"name\": \"erc20Contract\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"internalType\": \"uint256\",\n \"name\": \"amount\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"AssetTransferFailure\",\n \"type\": \"event\"\n },\n {\n \"inputs\": [\n {\n \"internalType\": \"address[]\",\n \"name\": \"erc20Addresses\",\n \"type\": \"address[]\"\n },\n {\n \"internalType\": \"address\",\n \"name\": \"backupAddress\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"rescueAssets\",\n \"outputs\": [],\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n }\n]\n") . expect ("invalid abi") 22 | }); 23 | pub struct Watchtower(ethers::contract::Contract); 24 | impl Clone for Watchtower { 25 | fn clone(&self) -> Self { 26 | Watchtower(self.0.clone()) 27 | } 28 | } 29 | impl std::ops::Deref for Watchtower { 30 | type Target = ethers::contract::Contract; 31 | fn deref(&self) -> &Self::Target { 32 | &self.0 33 | } 34 | } 35 | impl std::fmt::Debug for Watchtower { 36 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 37 | f.debug_tuple(stringify!(Watchtower)) 38 | .field(&self.address()) 39 | .finish() 40 | } 41 | } 42 | impl Watchtower { 43 | #[doc = r" Creates a new contract instance with the specified `ethers`"] 44 | #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"] 45 | #[doc = r" object"] 46 | pub fn new>( 47 | address: T, 48 | client: ::std::sync::Arc, 49 | ) -> Self { 50 | ethers::contract::Contract::new(address.into(), WATCHTOWER_ABI.clone(), client).into() 51 | } 52 | #[doc = "Calls the contract's `rescueAssets` (0x45b0502a) function"] 53 | pub fn rescue_assets( 54 | &self, 55 | erc_20_addresses: ::std::vec::Vec, 56 | backup_address: ethers::core::types::Address, 57 | ) -> ethers::contract::builders::ContractCall { 58 | self.0 59 | .method_hash([69, 176, 80, 42], (erc_20_addresses, backup_address)) 60 | .expect("method not found (this should never happen)") 61 | } 62 | #[doc = "Gets the contract's `AssetTransfer` event"] 63 | pub fn asset_transfer_filter( 64 | &self, 65 | ) -> ethers::contract::builders::Event { 66 | self.0.event() 67 | } 68 | #[doc = "Gets the contract's `AssetTransferFailure` event"] 69 | pub fn asset_transfer_failure_filter( 70 | &self, 71 | ) -> ethers::contract::builders::Event { 72 | self.0.event() 73 | } 74 | #[doc = r" Returns an [`Event`](#ethers_contract::builders::Event) builder for all events of this contract"] 75 | pub fn events(&self) -> ethers::contract::builders::Event { 76 | self.0.event_with_filter(Default::default()) 77 | } 78 | } 79 | impl From> for Watchtower { 80 | fn from(contract: ethers::contract::Contract) -> Self { 81 | Self(contract) 82 | } 83 | } 84 | #[derive( 85 | Clone, 86 | Debug, 87 | Default, 88 | Eq, 89 | PartialEq, 90 | ethers :: contract :: EthEvent, 91 | ethers :: contract :: EthDisplay, 92 | )] 93 | #[ethevent(name = "AssetTransfer", abi = "AssetTransfer(address,address,uint256)")] 94 | pub struct AssetTransferFilter { 95 | #[ethevent(indexed)] 96 | pub from: ethers::core::types::Address, 97 | pub erc_20_contract: ethers::core::types::Address, 98 | pub amount: ethers::core::types::U256, 99 | } 100 | #[derive( 101 | Clone, 102 | Debug, 103 | Default, 104 | Eq, 105 | PartialEq, 106 | ethers :: contract :: EthEvent, 107 | ethers :: contract :: EthDisplay, 108 | )] 109 | #[ethevent( 110 | name = "AssetTransferFailure", 111 | abi = "AssetTransferFailure(address,address,uint256)" 112 | )] 113 | pub struct AssetTransferFailureFilter { 114 | #[ethevent(indexed)] 115 | pub from: ethers::core::types::Address, 116 | pub erc_20_contract: ethers::core::types::Address, 117 | pub amount: ethers::core::types::U256, 118 | } 119 | #[derive(Debug, Clone, PartialEq, Eq, ethers :: contract :: EthAbiType)] 120 | pub enum WatchtowerEvents { 121 | AssetTransferFilter(AssetTransferFilter), 122 | AssetTransferFailureFilter(AssetTransferFailureFilter), 123 | } 124 | impl ethers::contract::EthLogDecode for WatchtowerEvents { 125 | fn decode_log(log: ðers::core::abi::RawLog) -> Result 126 | where 127 | Self: Sized, 128 | { 129 | if let Ok(decoded) = AssetTransferFilter::decode_log(log) { 130 | return Ok(WatchtowerEvents::AssetTransferFilter(decoded)); 131 | } 132 | if let Ok(decoded) = AssetTransferFailureFilter::decode_log(log) { 133 | return Ok(WatchtowerEvents::AssetTransferFailureFilter(decoded)); 134 | } 135 | Err(ethers::core::abi::Error::InvalidData) 136 | } 137 | } 138 | impl ::std::fmt::Display for WatchtowerEvents { 139 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 140 | match self { 141 | WatchtowerEvents::AssetTransferFilter(element) => element.fmt(f), 142 | WatchtowerEvents::AssetTransferFailureFilter(element) => element.fmt(f), 143 | } 144 | } 145 | } 146 | #[doc = "Container type for all input parameters for the `rescueAssets` function with signature `rescueAssets(address[],address)` and selector `[69, 176, 80, 42]`"] 147 | #[derive( 148 | Clone, 149 | Debug, 150 | Default, 151 | Eq, 152 | PartialEq, 153 | ethers :: contract :: EthCall, 154 | ethers :: contract :: EthDisplay, 155 | )] 156 | #[ethcall(name = "rescueAssets", abi = "rescueAssets(address[],address)")] 157 | pub struct RescueAssetsCall { 158 | pub erc_20_addresses: ::std::vec::Vec, 159 | pub backup_address: ethers::core::types::Address, 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /frontend/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | import styles from "../styles/Home.module.css"; 3 | import { useEffect } from "react"; 4 | import { ethers } from "ethers"; 5 | 6 | import * as React from "react"; 7 | import "@rainbow-me/rainbowkit/styles.css"; 8 | 9 | import { useSigner } from "wagmi"; 10 | import { ConnectButton, useConnectModal } from "@rainbow-me/rainbowkit"; 11 | 12 | import Papa, { ParseResult } from "papaparse"; 13 | 14 | const SERVER_ENDPOINT = "https://ethwatchtower.ngrok.io"; 15 | 16 | const CHAIN_ID = 1; 17 | 18 | const CONTRACT_ADDR = 19 | // @ts-ignore 20 | CHAIN_ID == 5 21 | ? "0x8F8F457a0F6BF163af60bC9254E47a44E01AD776" 22 | : "0xa576edc195c48440fa98840fb3721bf17c1656f6"; 23 | const CLI_USER = "--private-key $PRIV_KEY --backup-address $BACKUP_ADDR"; 24 | const CLI_RESCUE = `--contract-address ${CONTRACT_ADDR}`; 25 | const CLI_CHAIN = `--chain-id ${CHAIN_ID}`; 26 | const CLI_OUT = "--output-path not-your-private-keys.csv"; 27 | 28 | const DUMMY_TX_HASHES: string[] = [ 29 | "0x8fcf61d7037ce1fa42e5986eac2f18c0cc65a9e3c1ec899f55467465c8daf0e1", 30 | "0xcfbfddf83cdffa8566603be2617fc8a351809fc0eeb163946aa612f7e22ef769", 31 | "0xa54c436c28ac7523dc495dd738c3ec756429b32713b1a72b3ef6ffde6205e891", 32 | "0x3b6e0ebd4f460b8ebcf7f4040b299dd65e1662db2b4a2d4f5e130e1de198e63d", 33 | "0xf36979f3f3e3c4858872440e66fdce0439d7cafa7f9a711e4b2da2193170f1c3", 34 | "0x3a49d1bdc11711fadc33d8474c61d5f4c7e739ac0605094f27438be8b58decc7", 35 | "0x82dddff278146498c08ad3b8172c481e516fdc006b049a02713be7b85b5f56c7", 36 | "0x27495a975ad5a9a6296694871cb4f08ea689e6f2a097407eec31b0d479216335", 37 | "0xf4e88725a872759e392de58f6c2af0673c75014fec3d8ab48534c8b655e3eb5c", 38 | "0xdf0f8682b99f90d0dcfc558ab67902c7d484b1c9dc254ac8d06161c3de940dee", 39 | ]; 40 | 41 | export default function Home() { 42 | const { data: signer } = useSigner(); 43 | const [cliCmd, setCliCmd] = React.useState(""); 44 | 45 | const [upApproveStat, setUpApproveStat] = React.useState(0); 46 | const [upRescueStat, setUpRescueStat] = React.useState(0); 47 | const { openConnectModal } = useConnectModal(); 48 | 49 | // Update the displayed CLI command when wallet is connected 50 | useEffect(() => { 51 | signer && constructCliCmd(signer); 52 | }, [signer]); 53 | const constructCliCmd = async (signer: ethers.Signer) => { 54 | const txCt = await signer.getTransactionCount(); 55 | const signerAddr = await signer.getAddress(); 56 | fetch(`${SERVER_ENDPOINT}/heldERC20/${signerAddr}`) 57 | .then(async (res) => { 58 | const quantParam = `--min-gas 10 --max-gas 100 --gas-step 10 --nonce ${txCt}`; 59 | const heldAddresses = await res.json(); 60 | const strAddresses = heldAddresses.join(" "); 61 | const tokenParam = `--erc20-addresses ${strAddresses}`; 62 | setCliCmd( 63 | `veil ${CLI_USER} ${CLI_RESCUE} ${quantParam} ${tokenParam} ${CLI_CHAIN} ${CLI_OUT}` 64 | ); 65 | }) 66 | .catch((e) => console.error(e)); 67 | }; 68 | 69 | // Send signed approval / rescue transactions to backend to be stored 70 | const uploadSignatures = async (event: any) => { 71 | const chunk = (a: any[], size: number) => 72 | Array.from(new Array(Math.ceil(a.length / size)), (_, i) => 73 | a.slice(i * size, i * size + size) 74 | ); 75 | 76 | Papa.parse(event.target.files[0], { 77 | header: true, 78 | skipEmptyLines: true, 79 | complete: async ( 80 | results: ParseResult<{ [property: string]: string | number }> 81 | ) => { 82 | // Send approval transactions 83 | const approvals = results.data.filter( 84 | (row) => row["type"] === "approve" 85 | ); 86 | const approveRequestOptions = { 87 | method: "POST", 88 | headers: { "Content-Type": "application/json" }, 89 | body: JSON.stringify({ approveData: approvals }), 90 | }; 91 | fetch(`${SERVER_ENDPOINT}/postApproveTxs`, approveRequestOptions) 92 | .then((response) => setUpApproveStat(response.status)) 93 | .catch((e) => console.error(e)); 94 | 95 | // Send rescue transactions 96 | const rescueTxs = results.data 97 | .filter((row) => row["type"] === "rescue") 98 | .map((row) => { 99 | row["gasPrice"] = parseInt(String(row["gasPrice"])); 100 | return row; 101 | }); 102 | chunk(rescueTxs, 100).map((rescueChunk) => { 103 | const rescueRequestOptions = { 104 | method: "POST", 105 | headers: { "Content-Type": "application/json" }, 106 | body: JSON.stringify({ signedRescueTxs: rescueChunk }), 107 | }; 108 | fetch(`${SERVER_ENDPOINT}/postRescueTxs`, rescueRequestOptions) 109 | .then((response) => { 110 | if (upRescueStat == 0 || upRescueStat == 200) { 111 | setUpRescueStat(response.status); 112 | } 113 | }) 114 | .catch((e) => console.error(e)); 115 | }); 116 | }, 117 | }); 118 | }; 119 | 120 | const [latestTxHash, setLatestTxHash] = React.useState(""); 121 | const [mempool, setMempool] = React.useState([]); 122 | 123 | useEffect(() => { 124 | const id = setInterval(() => { 125 | setLatestTxHash( 126 | DUMMY_TX_HASHES[Math.floor(Math.random() * DUMMY_TX_HASHES.length)] 127 | ); 128 | }, 100); 129 | return () => clearInterval(id); 130 | }, [latestTxHash]); 131 | 132 | return ( 133 |
134 | 135 | Veil ⚡ 136 | 137 | 138 | 139 |
140 |
141 |
142 | Veil 143 | 149 | 154 | 155 |
156 |
157 |
158 |
159 |
160 |
161 | 162 |
163 |
164 | 165 |
166 |
167 |
168 |
169 | Your ultimate defense against private key theft. 170 |
171 |

172 |
173 | Veil protects assets by frontrunning unauthorized transactions and 174 | transferring all your assets to a secure, pre-specificied backup 175 | address. It can be set up in seconds, without revealing your 176 | private key at any point in the process. 177 |
178 |

179 |
Scanning the mempool...
180 | {latestTxHash} 181 |

182 |

183 |
Get Started
184 | 185 |
186 | 1) Save your generated watchtower command. 187 |

188 |
189 | {cliCmd || 190 | `veil --private-key $PRIV_KEY \ 191 | --backup-address $BACKUP_ADDR \ 192 | --contract-address 0x8F8F457a0F6BF163af60bC9254E47a44E01AD776 \ 193 | --min-gas 10 \ 194 | --max-gas 100 \ 195 | --gas-step 10 \ 196 | --nonce 8 \ 197 | --erc20-addresses 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984 0xdc31Ee1784292379Fbb2964b3B9C4124D8F89C60 \ 198 | --output-path not-your-private-keys.csv`} 199 |
200 |
201 |
202 | 2) Run watchtower from a secure sandbox and upload your signed 203 | transactions. 204 | 211 |

212 | Approve Upload Status:{" "} 213 | {upApproveStat == 0 ? ( 214 | 220 | 225 | 226 | ) : ( 227 | 233 | 238 | 239 | )} 240 |

241 |

242 | Rescue Upload Status:{" "} 243 | {upRescueStat == 0 ? ( 244 | 250 | 255 | 256 | ) : ( 257 | 263 | 268 | 269 | )} 270 |

271 |
272 |
273 |
274 |
275 |
276 | ); 277 | } 278 | -------------------------------------------------------------------------------- /cli/src/erc20.rs: -------------------------------------------------------------------------------- 1 | pub use erc20::*; 2 | #[allow(clippy::too_many_arguments, non_camel_case_types)] 3 | pub mod erc20 { 4 | #![allow(clippy::enum_variant_names)] 5 | #![allow(dead_code)] 6 | #![allow(clippy::type_complexity)] 7 | #![allow(unused_imports)] 8 | use ethers::contract::{ 9 | builders::{ContractCall, Event}, 10 | Contract, Lazy, 11 | }; 12 | use ethers::core::{ 13 | abi::{Abi, Detokenize, InvalidOutputType, Token, Tokenizable}, 14 | types::*, 15 | }; 16 | use ethers::providers::Middleware; 17 | #[doc = "ERC20 was auto-generated with ethers-rs Abigen. More information at: https://github.com/gakonst/ethers-rs"] 18 | use std::sync::Arc; 19 | pub static ERC20_ABI: ethers::contract::Lazy = 20 | ethers::contract::Lazy::new(|| { 21 | ethers :: core :: utils :: __serde_json :: from_str ("[\n {\n \"constant\": true,\n \"inputs\": [],\n \"name\": \"name\",\n \"outputs\": [\n {\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"constant\": false,\n \"inputs\": [\n {\n \"name\": \"_spender\",\n \"type\": \"address\"\n },\n {\n \"name\": \"_value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"approve\",\n \"outputs\": [\n {\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"constant\": true,\n \"inputs\": [],\n \"name\": \"totalSupply\",\n \"outputs\": [\n {\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"constant\": false,\n \"inputs\": [\n {\n \"name\": \"_from\",\n \"type\": \"address\"\n },\n {\n \"name\": \"_to\",\n \"type\": \"address\"\n },\n {\n \"name\": \"_value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transferFrom\",\n \"outputs\": [\n {\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"constant\": true,\n \"inputs\": [],\n \"name\": \"decimals\",\n \"outputs\": [\n {\n \"name\": \"\",\n \"type\": \"uint8\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"constant\": true,\n \"inputs\": [\n {\n \"name\": \"_owner\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"balanceOf\",\n \"outputs\": [\n {\n \"name\": \"balance\",\n \"type\": \"uint256\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"constant\": true,\n \"inputs\": [],\n \"name\": \"symbol\",\n \"outputs\": [\n {\n \"name\": \"\",\n \"type\": \"string\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"constant\": false,\n \"inputs\": [\n {\n \"name\": \"_to\",\n \"type\": \"address\"\n },\n {\n \"name\": \"_value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"transfer\",\n \"outputs\": [\n {\n \"name\": \"\",\n \"type\": \"bool\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"nonpayable\",\n \"type\": \"function\"\n },\n {\n \"constant\": true,\n \"inputs\": [\n {\n \"name\": \"_owner\",\n \"type\": \"address\"\n },\n {\n \"name\": \"_spender\",\n \"type\": \"address\"\n }\n ],\n \"name\": \"allowance\",\n \"outputs\": [\n {\n \"name\": \"\",\n \"type\": \"uint256\"\n }\n ],\n \"payable\": false,\n \"stateMutability\": \"view\",\n \"type\": \"function\"\n },\n {\n \"payable\": true,\n \"stateMutability\": \"payable\",\n \"type\": \"fallback\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"name\": \"owner\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"name\": \"spender\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Approval\",\n \"type\": \"event\"\n },\n {\n \"anonymous\": false,\n \"inputs\": [\n {\n \"indexed\": true,\n \"name\": \"from\",\n \"type\": \"address\"\n },\n {\n \"indexed\": true,\n \"name\": \"to\",\n \"type\": \"address\"\n },\n {\n \"indexed\": false,\n \"name\": \"value\",\n \"type\": \"uint256\"\n }\n ],\n \"name\": \"Transfer\",\n \"type\": \"event\"\n }\n]") . expect ("invalid abi") 22 | }); 23 | pub struct ERC20(ethers::contract::Contract); 24 | impl Clone for ERC20 { 25 | fn clone(&self) -> Self { 26 | ERC20(self.0.clone()) 27 | } 28 | } 29 | impl std::ops::Deref for ERC20 { 30 | type Target = ethers::contract::Contract; 31 | fn deref(&self) -> &Self::Target { 32 | &self.0 33 | } 34 | } 35 | impl std::fmt::Debug for ERC20 { 36 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 37 | f.debug_tuple(stringify!(ERC20)) 38 | .field(&self.address()) 39 | .finish() 40 | } 41 | } 42 | impl ERC20 { 43 | #[doc = r" Creates a new contract instance with the specified `ethers`"] 44 | #[doc = r" client at the given `Address`. The contract derefs to a `ethers::Contract`"] 45 | #[doc = r" object"] 46 | pub fn new>( 47 | address: T, 48 | client: ::std::sync::Arc, 49 | ) -> Self { 50 | ethers::contract::Contract::new(address.into(), ERC20_ABI.clone(), client).into() 51 | } 52 | #[doc = "Calls the contract's `allowance` (0xdd62ed3e) function"] 53 | pub fn allowance( 54 | &self, 55 | owner: ethers::core::types::Address, 56 | spender: ethers::core::types::Address, 57 | ) -> ethers::contract::builders::ContractCall { 58 | self.0 59 | .method_hash([221, 98, 237, 62], (owner, spender)) 60 | .expect("method not found (this should never happen)") 61 | } 62 | #[doc = "Calls the contract's `approve` (0x095ea7b3) function"] 63 | pub fn approve( 64 | &self, 65 | spender: ethers::core::types::Address, 66 | value: ethers::core::types::U256, 67 | ) -> ethers::contract::builders::ContractCall { 68 | self.0 69 | .method_hash([9, 94, 167, 179], (spender, value)) 70 | .expect("method not found (this should never happen)") 71 | } 72 | #[doc = "Calls the contract's `balanceOf` (0x70a08231) function"] 73 | pub fn balance_of( 74 | &self, 75 | owner: ethers::core::types::Address, 76 | ) -> ethers::contract::builders::ContractCall { 77 | self.0 78 | .method_hash([112, 160, 130, 49], owner) 79 | .expect("method not found (this should never happen)") 80 | } 81 | #[doc = "Calls the contract's `decimals` (0x313ce567) function"] 82 | pub fn decimals(&self) -> ethers::contract::builders::ContractCall { 83 | self.0 84 | .method_hash([49, 60, 229, 103], ()) 85 | .expect("method not found (this should never happen)") 86 | } 87 | #[doc = "Calls the contract's `name` (0x06fdde03) function"] 88 | pub fn name(&self) -> ethers::contract::builders::ContractCall { 89 | self.0 90 | .method_hash([6, 253, 222, 3], ()) 91 | .expect("method not found (this should never happen)") 92 | } 93 | #[doc = "Calls the contract's `symbol` (0x95d89b41) function"] 94 | pub fn symbol(&self) -> ethers::contract::builders::ContractCall { 95 | self.0 96 | .method_hash([149, 216, 155, 65], ()) 97 | .expect("method not found (this should never happen)") 98 | } 99 | #[doc = "Calls the contract's `totalSupply` (0x18160ddd) function"] 100 | pub fn total_supply( 101 | &self, 102 | ) -> ethers::contract::builders::ContractCall { 103 | self.0 104 | .method_hash([24, 22, 13, 221], ()) 105 | .expect("method not found (this should never happen)") 106 | } 107 | #[doc = "Calls the contract's `transfer` (0xa9059cbb) function"] 108 | pub fn transfer( 109 | &self, 110 | to: ethers::core::types::Address, 111 | value: ethers::core::types::U256, 112 | ) -> ethers::contract::builders::ContractCall { 113 | self.0 114 | .method_hash([169, 5, 156, 187], (to, value)) 115 | .expect("method not found (this should never happen)") 116 | } 117 | #[doc = "Calls the contract's `transferFrom` (0x23b872dd) function"] 118 | pub fn transfer_from( 119 | &self, 120 | from: ethers::core::types::Address, 121 | to: ethers::core::types::Address, 122 | value: ethers::core::types::U256, 123 | ) -> ethers::contract::builders::ContractCall { 124 | self.0 125 | .method_hash([35, 184, 114, 221], (from, to, value)) 126 | .expect("method not found (this should never happen)") 127 | } 128 | #[doc = "Gets the contract's `Approval` event"] 129 | pub fn approval_filter(&self) -> ethers::contract::builders::Event { 130 | self.0.event() 131 | } 132 | #[doc = "Gets the contract's `Transfer` event"] 133 | pub fn transfer_filter(&self) -> ethers::contract::builders::Event { 134 | self.0.event() 135 | } 136 | #[doc = r" Returns an [`Event`](#ethers_contract::builders::Event) builder for all events of this contract"] 137 | pub fn events(&self) -> ethers::contract::builders::Event { 138 | self.0.event_with_filter(Default::default()) 139 | } 140 | } 141 | impl From> for ERC20 { 142 | fn from(contract: ethers::contract::Contract) -> Self { 143 | Self(contract) 144 | } 145 | } 146 | #[derive( 147 | Clone, 148 | Debug, 149 | Default, 150 | Eq, 151 | PartialEq, 152 | ethers :: contract :: EthEvent, 153 | ethers :: contract :: EthDisplay, 154 | )] 155 | #[ethevent(name = "Approval", abi = "Approval(address,address,uint256)")] 156 | pub struct ApprovalFilter { 157 | #[ethevent(indexed)] 158 | pub owner: ethers::core::types::Address, 159 | #[ethevent(indexed)] 160 | pub spender: ethers::core::types::Address, 161 | pub value: ethers::core::types::U256, 162 | } 163 | #[derive( 164 | Clone, 165 | Debug, 166 | Default, 167 | Eq, 168 | PartialEq, 169 | ethers :: contract :: EthEvent, 170 | ethers :: contract :: EthDisplay, 171 | )] 172 | #[ethevent(name = "Transfer", abi = "Transfer(address,address,uint256)")] 173 | pub struct TransferFilter { 174 | #[ethevent(indexed)] 175 | pub from: ethers::core::types::Address, 176 | #[ethevent(indexed)] 177 | pub to: ethers::core::types::Address, 178 | pub value: ethers::core::types::U256, 179 | } 180 | #[derive(Debug, Clone, PartialEq, Eq, ethers :: contract :: EthAbiType)] 181 | pub enum ERC20Events { 182 | ApprovalFilter(ApprovalFilter), 183 | TransferFilter(TransferFilter), 184 | } 185 | impl ethers::contract::EthLogDecode for ERC20Events { 186 | fn decode_log(log: ðers::core::abi::RawLog) -> Result 187 | where 188 | Self: Sized, 189 | { 190 | if let Ok(decoded) = ApprovalFilter::decode_log(log) { 191 | return Ok(ERC20Events::ApprovalFilter(decoded)); 192 | } 193 | if let Ok(decoded) = TransferFilter::decode_log(log) { 194 | return Ok(ERC20Events::TransferFilter(decoded)); 195 | } 196 | Err(ethers::core::abi::Error::InvalidData) 197 | } 198 | } 199 | impl ::std::fmt::Display for ERC20Events { 200 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 201 | match self { 202 | ERC20Events::ApprovalFilter(element) => element.fmt(f), 203 | ERC20Events::TransferFilter(element) => element.fmt(f), 204 | } 205 | } 206 | } 207 | #[doc = "Container type for all input parameters for the `allowance` function with signature `allowance(address,address)` and selector `[221, 98, 237, 62]`"] 208 | #[derive( 209 | Clone, 210 | Debug, 211 | Default, 212 | Eq, 213 | PartialEq, 214 | ethers :: contract :: EthCall, 215 | ethers :: contract :: EthDisplay, 216 | )] 217 | #[ethcall(name = "allowance", abi = "allowance(address,address)")] 218 | pub struct AllowanceCall { 219 | pub owner: ethers::core::types::Address, 220 | pub spender: ethers::core::types::Address, 221 | } 222 | #[doc = "Container type for all input parameters for the `approve` function with signature `approve(address,uint256)` and selector `[9, 94, 167, 179]`"] 223 | #[derive( 224 | Clone, 225 | Debug, 226 | Default, 227 | Eq, 228 | PartialEq, 229 | ethers :: contract :: EthCall, 230 | ethers :: contract :: EthDisplay, 231 | )] 232 | #[ethcall(name = "approve", abi = "approve(address,uint256)")] 233 | pub struct ApproveCall { 234 | pub spender: ethers::core::types::Address, 235 | pub value: ethers::core::types::U256, 236 | } 237 | #[doc = "Container type for all input parameters for the `balanceOf` function with signature `balanceOf(address)` and selector `[112, 160, 130, 49]`"] 238 | #[derive( 239 | Clone, 240 | Debug, 241 | Default, 242 | Eq, 243 | PartialEq, 244 | ethers :: contract :: EthCall, 245 | ethers :: contract :: EthDisplay, 246 | )] 247 | #[ethcall(name = "balanceOf", abi = "balanceOf(address)")] 248 | pub struct BalanceOfCall { 249 | pub owner: ethers::core::types::Address, 250 | } 251 | #[doc = "Container type for all input parameters for the `decimals` function with signature `decimals()` and selector `[49, 60, 229, 103]`"] 252 | #[derive( 253 | Clone, 254 | Debug, 255 | Default, 256 | Eq, 257 | PartialEq, 258 | ethers :: contract :: EthCall, 259 | ethers :: contract :: EthDisplay, 260 | )] 261 | #[ethcall(name = "decimals", abi = "decimals()")] 262 | pub struct DecimalsCall; 263 | #[doc = "Container type for all input parameters for the `name` function with signature `name()` and selector `[6, 253, 222, 3]`"] 264 | #[derive( 265 | Clone, 266 | Debug, 267 | Default, 268 | Eq, 269 | PartialEq, 270 | ethers :: contract :: EthCall, 271 | ethers :: contract :: EthDisplay, 272 | )] 273 | #[ethcall(name = "name", abi = "name()")] 274 | pub struct NameCall; 275 | #[doc = "Container type for all input parameters for the `symbol` function with signature `symbol()` and selector `[149, 216, 155, 65]`"] 276 | #[derive( 277 | Clone, 278 | Debug, 279 | Default, 280 | Eq, 281 | PartialEq, 282 | ethers :: contract :: EthCall, 283 | ethers :: contract :: EthDisplay, 284 | )] 285 | #[ethcall(name = "symbol", abi = "symbol()")] 286 | pub struct SymbolCall; 287 | #[doc = "Container type for all input parameters for the `totalSupply` function with signature `totalSupply()` and selector `[24, 22, 13, 221]`"] 288 | #[derive( 289 | Clone, 290 | Debug, 291 | Default, 292 | Eq, 293 | PartialEq, 294 | ethers :: contract :: EthCall, 295 | ethers :: contract :: EthDisplay, 296 | )] 297 | #[ethcall(name = "totalSupply", abi = "totalSupply()")] 298 | pub struct TotalSupplyCall; 299 | #[doc = "Container type for all input parameters for the `transfer` function with signature `transfer(address,uint256)` and selector `[169, 5, 156, 187]`"] 300 | #[derive( 301 | Clone, 302 | Debug, 303 | Default, 304 | Eq, 305 | PartialEq, 306 | ethers :: contract :: EthCall, 307 | ethers :: contract :: EthDisplay, 308 | )] 309 | #[ethcall(name = "transfer", abi = "transfer(address,uint256)")] 310 | pub struct TransferCall { 311 | pub to: ethers::core::types::Address, 312 | pub value: ethers::core::types::U256, 313 | } 314 | #[doc = "Container type for all input parameters for the `transferFrom` function with signature `transferFrom(address,address,uint256)` and selector `[35, 184, 114, 221]`"] 315 | #[derive( 316 | Clone, 317 | Debug, 318 | Default, 319 | Eq, 320 | PartialEq, 321 | ethers :: contract :: EthCall, 322 | ethers :: contract :: EthDisplay, 323 | )] 324 | #[ethcall(name = "transferFrom", abi = "transferFrom(address,address,uint256)")] 325 | pub struct TransferFromCall { 326 | pub from: ethers::core::types::Address, 327 | pub to: ethers::core::types::Address, 328 | pub value: ethers::core::types::U256, 329 | } 330 | #[derive(Debug, Clone, PartialEq, Eq, ethers :: contract :: EthAbiType)] 331 | pub enum ERC20Calls { 332 | Allowance(AllowanceCall), 333 | Approve(ApproveCall), 334 | BalanceOf(BalanceOfCall), 335 | Decimals(DecimalsCall), 336 | Name(NameCall), 337 | Symbol(SymbolCall), 338 | TotalSupply(TotalSupplyCall), 339 | Transfer(TransferCall), 340 | TransferFrom(TransferFromCall), 341 | } 342 | impl ethers::core::abi::AbiDecode for ERC20Calls { 343 | fn decode(data: impl AsRef<[u8]>) -> Result { 344 | if let Ok(decoded) = 345 | ::decode(data.as_ref()) 346 | { 347 | return Ok(ERC20Calls::Allowance(decoded)); 348 | } 349 | if let Ok(decoded) = 350 | ::decode(data.as_ref()) 351 | { 352 | return Ok(ERC20Calls::Approve(decoded)); 353 | } 354 | if let Ok(decoded) = 355 | ::decode(data.as_ref()) 356 | { 357 | return Ok(ERC20Calls::BalanceOf(decoded)); 358 | } 359 | if let Ok(decoded) = 360 | ::decode(data.as_ref()) 361 | { 362 | return Ok(ERC20Calls::Decimals(decoded)); 363 | } 364 | if let Ok(decoded) = ::decode(data.as_ref()) { 365 | return Ok(ERC20Calls::Name(decoded)); 366 | } 367 | if let Ok(decoded) = ::decode(data.as_ref()) 368 | { 369 | return Ok(ERC20Calls::Symbol(decoded)); 370 | } 371 | if let Ok(decoded) = 372 | ::decode(data.as_ref()) 373 | { 374 | return Ok(ERC20Calls::TotalSupply(decoded)); 375 | } 376 | if let Ok(decoded) = 377 | ::decode(data.as_ref()) 378 | { 379 | return Ok(ERC20Calls::Transfer(decoded)); 380 | } 381 | if let Ok(decoded) = 382 | ::decode(data.as_ref()) 383 | { 384 | return Ok(ERC20Calls::TransferFrom(decoded)); 385 | } 386 | Err(ethers::core::abi::Error::InvalidData.into()) 387 | } 388 | } 389 | impl ethers::core::abi::AbiEncode for ERC20Calls { 390 | fn encode(self) -> Vec { 391 | match self { 392 | ERC20Calls::Allowance(element) => element.encode(), 393 | ERC20Calls::Approve(element) => element.encode(), 394 | ERC20Calls::BalanceOf(element) => element.encode(), 395 | ERC20Calls::Decimals(element) => element.encode(), 396 | ERC20Calls::Name(element) => element.encode(), 397 | ERC20Calls::Symbol(element) => element.encode(), 398 | ERC20Calls::TotalSupply(element) => element.encode(), 399 | ERC20Calls::Transfer(element) => element.encode(), 400 | ERC20Calls::TransferFrom(element) => element.encode(), 401 | } 402 | } 403 | } 404 | impl ::std::fmt::Display for ERC20Calls { 405 | fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { 406 | match self { 407 | ERC20Calls::Allowance(element) => element.fmt(f), 408 | ERC20Calls::Approve(element) => element.fmt(f), 409 | ERC20Calls::BalanceOf(element) => element.fmt(f), 410 | ERC20Calls::Decimals(element) => element.fmt(f), 411 | ERC20Calls::Name(element) => element.fmt(f), 412 | ERC20Calls::Symbol(element) => element.fmt(f), 413 | ERC20Calls::TotalSupply(element) => element.fmt(f), 414 | ERC20Calls::Transfer(element) => element.fmt(f), 415 | ERC20Calls::TransferFrom(element) => element.fmt(f), 416 | } 417 | } 418 | } 419 | impl ::std::convert::From for ERC20Calls { 420 | fn from(var: AllowanceCall) -> Self { 421 | ERC20Calls::Allowance(var) 422 | } 423 | } 424 | impl ::std::convert::From for ERC20Calls { 425 | fn from(var: ApproveCall) -> Self { 426 | ERC20Calls::Approve(var) 427 | } 428 | } 429 | impl ::std::convert::From for ERC20Calls { 430 | fn from(var: BalanceOfCall) -> Self { 431 | ERC20Calls::BalanceOf(var) 432 | } 433 | } 434 | impl ::std::convert::From for ERC20Calls { 435 | fn from(var: DecimalsCall) -> Self { 436 | ERC20Calls::Decimals(var) 437 | } 438 | } 439 | impl ::std::convert::From for ERC20Calls { 440 | fn from(var: NameCall) -> Self { 441 | ERC20Calls::Name(var) 442 | } 443 | } 444 | impl ::std::convert::From for ERC20Calls { 445 | fn from(var: SymbolCall) -> Self { 446 | ERC20Calls::Symbol(var) 447 | } 448 | } 449 | impl ::std::convert::From for ERC20Calls { 450 | fn from(var: TotalSupplyCall) -> Self { 451 | ERC20Calls::TotalSupply(var) 452 | } 453 | } 454 | impl ::std::convert::From for ERC20Calls { 455 | fn from(var: TransferCall) -> Self { 456 | ERC20Calls::Transfer(var) 457 | } 458 | } 459 | impl ::std::convert::From for ERC20Calls { 460 | fn from(var: TransferFromCall) -> Self { 461 | ERC20Calls::TransferFrom(var) 462 | } 463 | } 464 | #[doc = "Container type for all return fields from the `allowance` function with signature `allowance(address,address)` and selector `[221, 98, 237, 62]`"] 465 | #[derive( 466 | Clone, 467 | Debug, 468 | Default, 469 | Eq, 470 | PartialEq, 471 | ethers :: contract :: EthAbiType, 472 | ethers :: contract :: EthAbiCodec, 473 | )] 474 | pub struct AllowanceReturn(pub ethers::core::types::U256); 475 | #[doc = "Container type for all return fields from the `approve` function with signature `approve(address,uint256)` and selector `[9, 94, 167, 179]`"] 476 | #[derive( 477 | Clone, 478 | Debug, 479 | Default, 480 | Eq, 481 | PartialEq, 482 | ethers :: contract :: EthAbiType, 483 | ethers :: contract :: EthAbiCodec, 484 | )] 485 | pub struct ApproveReturn(pub bool); 486 | #[doc = "Container type for all return fields from the `balanceOf` function with signature `balanceOf(address)` and selector `[112, 160, 130, 49]`"] 487 | #[derive( 488 | Clone, 489 | Debug, 490 | Default, 491 | Eq, 492 | PartialEq, 493 | ethers :: contract :: EthAbiType, 494 | ethers :: contract :: EthAbiCodec, 495 | )] 496 | pub struct BalanceOfReturn { 497 | pub balance: ethers::core::types::U256, 498 | } 499 | #[doc = "Container type for all return fields from the `decimals` function with signature `decimals()` and selector `[49, 60, 229, 103]`"] 500 | #[derive( 501 | Clone, 502 | Debug, 503 | Default, 504 | Eq, 505 | PartialEq, 506 | ethers :: contract :: EthAbiType, 507 | ethers :: contract :: EthAbiCodec, 508 | )] 509 | pub struct DecimalsReturn(pub u8); 510 | #[doc = "Container type for all return fields from the `name` function with signature `name()` and selector `[6, 253, 222, 3]`"] 511 | #[derive( 512 | Clone, 513 | Debug, 514 | Default, 515 | Eq, 516 | PartialEq, 517 | ethers :: contract :: EthAbiType, 518 | ethers :: contract :: EthAbiCodec, 519 | )] 520 | pub struct NameReturn(pub String); 521 | #[doc = "Container type for all return fields from the `symbol` function with signature `symbol()` and selector `[149, 216, 155, 65]`"] 522 | #[derive( 523 | Clone, 524 | Debug, 525 | Default, 526 | Eq, 527 | PartialEq, 528 | ethers :: contract :: EthAbiType, 529 | ethers :: contract :: EthAbiCodec, 530 | )] 531 | pub struct SymbolReturn(pub String); 532 | #[doc = "Container type for all return fields from the `totalSupply` function with signature `totalSupply()` and selector `[24, 22, 13, 221]`"] 533 | #[derive( 534 | Clone, 535 | Debug, 536 | Default, 537 | Eq, 538 | PartialEq, 539 | ethers :: contract :: EthAbiType, 540 | ethers :: contract :: EthAbiCodec, 541 | )] 542 | pub struct TotalSupplyReturn(pub ethers::core::types::U256); 543 | #[doc = "Container type for all return fields from the `transfer` function with signature `transfer(address,uint256)` and selector `[169, 5, 156, 187]`"] 544 | #[derive( 545 | Clone, 546 | Debug, 547 | Default, 548 | Eq, 549 | PartialEq, 550 | ethers :: contract :: EthAbiType, 551 | ethers :: contract :: EthAbiCodec, 552 | )] 553 | pub struct TransferReturn(pub bool); 554 | #[doc = "Container type for all return fields from the `transferFrom` function with signature `transferFrom(address,address,uint256)` and selector `[35, 184, 114, 221]`"] 555 | #[derive( 556 | Clone, 557 | Debug, 558 | Default, 559 | Eq, 560 | PartialEq, 561 | ethers :: contract :: EthAbiType, 562 | ethers :: contract :: EthAbiCodec, 563 | )] 564 | pub struct TransferFromReturn(pub bool); 565 | } 566 | -------------------------------------------------------------------------------- /backend/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@cspotcode/source-map-support@^0.8.0": 6 | version "0.8.1" 7 | resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" 8 | integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== 9 | dependencies: 10 | "@jridgewell/trace-mapping" "0.3.9" 11 | 12 | "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": 13 | version "5.7.0" 14 | resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz" 15 | integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== 16 | dependencies: 17 | "@ethersproject/address" "^5.7.0" 18 | "@ethersproject/bignumber" "^5.7.0" 19 | "@ethersproject/bytes" "^5.7.0" 20 | "@ethersproject/constants" "^5.7.0" 21 | "@ethersproject/hash" "^5.7.0" 22 | "@ethersproject/keccak256" "^5.7.0" 23 | "@ethersproject/logger" "^5.7.0" 24 | "@ethersproject/properties" "^5.7.0" 25 | "@ethersproject/strings" "^5.7.0" 26 | 27 | "@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.6.1", "@ethersproject/abstract-provider@^5.7.0": 28 | version "5.7.0" 29 | resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz" 30 | integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== 31 | dependencies: 32 | "@ethersproject/bignumber" "^5.7.0" 33 | "@ethersproject/bytes" "^5.7.0" 34 | "@ethersproject/logger" "^5.7.0" 35 | "@ethersproject/networks" "^5.7.0" 36 | "@ethersproject/properties" "^5.7.0" 37 | "@ethersproject/transactions" "^5.7.0" 38 | "@ethersproject/web" "^5.7.0" 39 | 40 | "@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": 41 | version "5.7.0" 42 | resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz" 43 | integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== 44 | dependencies: 45 | "@ethersproject/abstract-provider" "^5.7.0" 46 | "@ethersproject/bignumber" "^5.7.0" 47 | "@ethersproject/bytes" "^5.7.0" 48 | "@ethersproject/logger" "^5.7.0" 49 | "@ethersproject/properties" "^5.7.0" 50 | 51 | "@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": 52 | version "5.7.0" 53 | resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz" 54 | integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== 55 | dependencies: 56 | "@ethersproject/bignumber" "^5.7.0" 57 | "@ethersproject/bytes" "^5.7.0" 58 | "@ethersproject/keccak256" "^5.7.0" 59 | "@ethersproject/logger" "^5.7.0" 60 | "@ethersproject/rlp" "^5.7.0" 61 | 62 | "@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": 63 | version "5.7.0" 64 | resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz" 65 | integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== 66 | dependencies: 67 | "@ethersproject/bytes" "^5.7.0" 68 | 69 | "@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": 70 | version "5.7.0" 71 | resolved "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz" 72 | integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== 73 | dependencies: 74 | "@ethersproject/bytes" "^5.7.0" 75 | "@ethersproject/properties" "^5.7.0" 76 | 77 | "@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.6.2", "@ethersproject/bignumber@^5.7.0": 78 | version "5.7.0" 79 | resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz" 80 | integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== 81 | dependencies: 82 | "@ethersproject/bytes" "^5.7.0" 83 | "@ethersproject/logger" "^5.7.0" 84 | bn.js "^5.2.1" 85 | 86 | "@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": 87 | version "5.7.0" 88 | resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz" 89 | integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== 90 | dependencies: 91 | "@ethersproject/logger" "^5.7.0" 92 | 93 | "@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": 94 | version "5.7.0" 95 | resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz" 96 | integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== 97 | dependencies: 98 | "@ethersproject/bignumber" "^5.7.0" 99 | 100 | "@ethersproject/contracts@5.7.0": 101 | version "5.7.0" 102 | resolved "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz" 103 | integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== 104 | dependencies: 105 | "@ethersproject/abi" "^5.7.0" 106 | "@ethersproject/abstract-provider" "^5.7.0" 107 | "@ethersproject/abstract-signer" "^5.7.0" 108 | "@ethersproject/address" "^5.7.0" 109 | "@ethersproject/bignumber" "^5.7.0" 110 | "@ethersproject/bytes" "^5.7.0" 111 | "@ethersproject/constants" "^5.7.0" 112 | "@ethersproject/logger" "^5.7.0" 113 | "@ethersproject/properties" "^5.7.0" 114 | "@ethersproject/transactions" "^5.7.0" 115 | 116 | "@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": 117 | version "5.7.0" 118 | resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz" 119 | integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== 120 | dependencies: 121 | "@ethersproject/abstract-signer" "^5.7.0" 122 | "@ethersproject/address" "^5.7.0" 123 | "@ethersproject/base64" "^5.7.0" 124 | "@ethersproject/bignumber" "^5.7.0" 125 | "@ethersproject/bytes" "^5.7.0" 126 | "@ethersproject/keccak256" "^5.7.0" 127 | "@ethersproject/logger" "^5.7.0" 128 | "@ethersproject/properties" "^5.7.0" 129 | "@ethersproject/strings" "^5.7.0" 130 | 131 | "@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": 132 | version "5.7.0" 133 | resolved "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz" 134 | integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== 135 | dependencies: 136 | "@ethersproject/abstract-signer" "^5.7.0" 137 | "@ethersproject/basex" "^5.7.0" 138 | "@ethersproject/bignumber" "^5.7.0" 139 | "@ethersproject/bytes" "^5.7.0" 140 | "@ethersproject/logger" "^5.7.0" 141 | "@ethersproject/pbkdf2" "^5.7.0" 142 | "@ethersproject/properties" "^5.7.0" 143 | "@ethersproject/sha2" "^5.7.0" 144 | "@ethersproject/signing-key" "^5.7.0" 145 | "@ethersproject/strings" "^5.7.0" 146 | "@ethersproject/transactions" "^5.7.0" 147 | "@ethersproject/wordlists" "^5.7.0" 148 | 149 | "@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": 150 | version "5.7.0" 151 | resolved "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz" 152 | integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== 153 | dependencies: 154 | "@ethersproject/abstract-signer" "^5.7.0" 155 | "@ethersproject/address" "^5.7.0" 156 | "@ethersproject/bytes" "^5.7.0" 157 | "@ethersproject/hdnode" "^5.7.0" 158 | "@ethersproject/keccak256" "^5.7.0" 159 | "@ethersproject/logger" "^5.7.0" 160 | "@ethersproject/pbkdf2" "^5.7.0" 161 | "@ethersproject/properties" "^5.7.0" 162 | "@ethersproject/random" "^5.7.0" 163 | "@ethersproject/strings" "^5.7.0" 164 | "@ethersproject/transactions" "^5.7.0" 165 | aes-js "3.0.0" 166 | scrypt-js "3.0.1" 167 | 168 | "@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": 169 | version "5.7.0" 170 | resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz" 171 | integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== 172 | dependencies: 173 | "@ethersproject/bytes" "^5.7.0" 174 | js-sha3 "0.8.0" 175 | 176 | "@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": 177 | version "5.7.0" 178 | resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz" 179 | integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== 180 | 181 | "@ethersproject/networks@5.7.0", "@ethersproject/networks@^5.6.4", "@ethersproject/networks@^5.7.0": 182 | version "5.7.0" 183 | resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.0.tgz" 184 | integrity sha512-MG6oHSQHd4ebvJrleEQQ4HhVu8Ichr0RDYEfHzsVAVjHNM+w36x9wp9r+hf1JstMXtseXDtkiVoARAG6M959AA== 185 | dependencies: 186 | "@ethersproject/logger" "^5.7.0" 187 | 188 | "@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": 189 | version "5.7.0" 190 | resolved "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz" 191 | integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== 192 | dependencies: 193 | "@ethersproject/bytes" "^5.7.0" 194 | "@ethersproject/sha2" "^5.7.0" 195 | 196 | "@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": 197 | version "5.7.0" 198 | resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz" 199 | integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== 200 | dependencies: 201 | "@ethersproject/logger" "^5.7.0" 202 | 203 | "@ethersproject/providers@5.7.0", "@ethersproject/providers@^5.6.8": 204 | version "5.7.0" 205 | resolved "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.0.tgz" 206 | integrity sha512-+TTrrINMzZ0aXtlwO/95uhAggKm4USLm1PbeCBR/3XZ7+Oey+3pMyddzZEyRhizHpy1HXV0FRWRMI1O3EGYibA== 207 | dependencies: 208 | "@ethersproject/abstract-provider" "^5.7.0" 209 | "@ethersproject/abstract-signer" "^5.7.0" 210 | "@ethersproject/address" "^5.7.0" 211 | "@ethersproject/base64" "^5.7.0" 212 | "@ethersproject/basex" "^5.7.0" 213 | "@ethersproject/bignumber" "^5.7.0" 214 | "@ethersproject/bytes" "^5.7.0" 215 | "@ethersproject/constants" "^5.7.0" 216 | "@ethersproject/hash" "^5.7.0" 217 | "@ethersproject/logger" "^5.7.0" 218 | "@ethersproject/networks" "^5.7.0" 219 | "@ethersproject/properties" "^5.7.0" 220 | "@ethersproject/random" "^5.7.0" 221 | "@ethersproject/rlp" "^5.7.0" 222 | "@ethersproject/sha2" "^5.7.0" 223 | "@ethersproject/strings" "^5.7.0" 224 | "@ethersproject/transactions" "^5.7.0" 225 | "@ethersproject/web" "^5.7.0" 226 | bech32 "1.1.4" 227 | ws "7.4.6" 228 | 229 | "@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": 230 | version "5.7.0" 231 | resolved "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz" 232 | integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== 233 | dependencies: 234 | "@ethersproject/bytes" "^5.7.0" 235 | "@ethersproject/logger" "^5.7.0" 236 | 237 | "@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": 238 | version "5.7.0" 239 | resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz" 240 | integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== 241 | dependencies: 242 | "@ethersproject/bytes" "^5.7.0" 243 | "@ethersproject/logger" "^5.7.0" 244 | 245 | "@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": 246 | version "5.7.0" 247 | resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz" 248 | integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== 249 | dependencies: 250 | "@ethersproject/bytes" "^5.7.0" 251 | "@ethersproject/logger" "^5.7.0" 252 | hash.js "1.1.7" 253 | 254 | "@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": 255 | version "5.7.0" 256 | resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz" 257 | integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== 258 | dependencies: 259 | "@ethersproject/bytes" "^5.7.0" 260 | "@ethersproject/logger" "^5.7.0" 261 | "@ethersproject/properties" "^5.7.0" 262 | bn.js "^5.2.1" 263 | elliptic "6.5.4" 264 | hash.js "1.1.7" 265 | 266 | "@ethersproject/solidity@5.7.0": 267 | version "5.7.0" 268 | resolved "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz" 269 | integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== 270 | dependencies: 271 | "@ethersproject/bignumber" "^5.7.0" 272 | "@ethersproject/bytes" "^5.7.0" 273 | "@ethersproject/keccak256" "^5.7.0" 274 | "@ethersproject/logger" "^5.7.0" 275 | "@ethersproject/sha2" "^5.7.0" 276 | "@ethersproject/strings" "^5.7.0" 277 | 278 | "@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": 279 | version "5.7.0" 280 | resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz" 281 | integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== 282 | dependencies: 283 | "@ethersproject/bytes" "^5.7.0" 284 | "@ethersproject/constants" "^5.7.0" 285 | "@ethersproject/logger" "^5.7.0" 286 | 287 | "@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": 288 | version "5.7.0" 289 | resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz" 290 | integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== 291 | dependencies: 292 | "@ethersproject/address" "^5.7.0" 293 | "@ethersproject/bignumber" "^5.7.0" 294 | "@ethersproject/bytes" "^5.7.0" 295 | "@ethersproject/constants" "^5.7.0" 296 | "@ethersproject/keccak256" "^5.7.0" 297 | "@ethersproject/logger" "^5.7.0" 298 | "@ethersproject/properties" "^5.7.0" 299 | "@ethersproject/rlp" "^5.7.0" 300 | "@ethersproject/signing-key" "^5.7.0" 301 | 302 | "@ethersproject/units@5.7.0": 303 | version "5.7.0" 304 | resolved "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz" 305 | integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== 306 | dependencies: 307 | "@ethersproject/bignumber" "^5.7.0" 308 | "@ethersproject/constants" "^5.7.0" 309 | "@ethersproject/logger" "^5.7.0" 310 | 311 | "@ethersproject/wallet@5.7.0", "@ethersproject/wallet@^5.6.2": 312 | version "5.7.0" 313 | resolved "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz" 314 | integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== 315 | dependencies: 316 | "@ethersproject/abstract-provider" "^5.7.0" 317 | "@ethersproject/abstract-signer" "^5.7.0" 318 | "@ethersproject/address" "^5.7.0" 319 | "@ethersproject/bignumber" "^5.7.0" 320 | "@ethersproject/bytes" "^5.7.0" 321 | "@ethersproject/hash" "^5.7.0" 322 | "@ethersproject/hdnode" "^5.7.0" 323 | "@ethersproject/json-wallets" "^5.7.0" 324 | "@ethersproject/keccak256" "^5.7.0" 325 | "@ethersproject/logger" "^5.7.0" 326 | "@ethersproject/properties" "^5.7.0" 327 | "@ethersproject/random" "^5.7.0" 328 | "@ethersproject/signing-key" "^5.7.0" 329 | "@ethersproject/transactions" "^5.7.0" 330 | "@ethersproject/wordlists" "^5.7.0" 331 | 332 | "@ethersproject/web@5.7.0", "@ethersproject/web@^5.6.1", "@ethersproject/web@^5.7.0": 333 | version "5.7.0" 334 | resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.0.tgz" 335 | integrity sha512-ApHcbbj+muRASVDSCl/tgxaH2LBkRMEYfLOLVa0COipx0+nlu0QKet7U2lEg0vdkh8XRSLf2nd1f1Uk9SrVSGA== 336 | dependencies: 337 | "@ethersproject/base64" "^5.7.0" 338 | "@ethersproject/bytes" "^5.7.0" 339 | "@ethersproject/logger" "^5.7.0" 340 | "@ethersproject/properties" "^5.7.0" 341 | "@ethersproject/strings" "^5.7.0" 342 | 343 | "@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": 344 | version "5.7.0" 345 | resolved "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz" 346 | integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== 347 | dependencies: 348 | "@ethersproject/bytes" "^5.7.0" 349 | "@ethersproject/hash" "^5.7.0" 350 | "@ethersproject/logger" "^5.7.0" 351 | "@ethersproject/properties" "^5.7.0" 352 | "@ethersproject/strings" "^5.7.0" 353 | 354 | "@jridgewell/resolve-uri@^3.0.3": 355 | version "3.1.0" 356 | resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" 357 | integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== 358 | 359 | "@jridgewell/sourcemap-codec@^1.4.10": 360 | version "1.4.14" 361 | resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" 362 | integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== 363 | 364 | "@jridgewell/trace-mapping@0.3.9": 365 | version "0.3.9" 366 | resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" 367 | integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== 368 | dependencies: 369 | "@jridgewell/resolve-uri" "^3.0.3" 370 | "@jridgewell/sourcemap-codec" "^1.4.10" 371 | 372 | "@prisma/client@4.2.1": 373 | version "4.2.1" 374 | resolved "https://registry.npmjs.org/@prisma/client/-/client-4.2.1.tgz" 375 | integrity sha512-PZBkY60+k5oix+e6IUfl3ub8TbRLNsPLdfWrdy2eh80WcHTaT+/UfvXf/B7gXedH7FRtbPFHZXk1hZenJiJZFQ== 376 | dependencies: 377 | "@prisma/engines-version" "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826" 378 | 379 | "@prisma/engines-version@4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826": 380 | version "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826" 381 | resolved "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826.tgz" 382 | integrity sha512-tktkqdiwqE4QhmE088boPt+FwPj1Jub/zk+5F6sEfcRHzO5yz9jyMD5HFVtiwxZPLx/8Xg9ElnuTi8E5lWVQFQ== 383 | 384 | "@prisma/engines@4.2.1": 385 | version "4.2.1" 386 | resolved "https://registry.npmjs.org/@prisma/engines/-/engines-4.2.1.tgz" 387 | integrity sha512-0KqBwREUOjBiHwITsQzw2DWfLHjntvbqzGRawj4sBMnIiL5CXwyDUKeHOwXzKMtNr1rEjxEsypM14g0CzLRK3g== 388 | 389 | "@tsconfig/node10@^1.0.7": 390 | version "1.0.9" 391 | resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz" 392 | integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== 393 | 394 | "@tsconfig/node12@^1.0.7": 395 | version "1.0.11" 396 | resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" 397 | integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== 398 | 399 | "@tsconfig/node14@^1.0.0": 400 | version "1.0.3" 401 | resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" 402 | integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== 403 | 404 | "@tsconfig/node16@^1.0.2": 405 | version "1.0.3" 406 | resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz" 407 | integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== 408 | 409 | "@typechain/ethers-v5@^10.1.0": 410 | version "10.1.0" 411 | resolved "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.1.0.tgz" 412 | integrity sha512-3LIb+eUpV3mNCrjUKT5oqp8PBsZYSnVrkfk6pY/ZM0boRs2mKxjFZ7bktx42vfDye8PPz3NxtW4DL5NsNsFqlg== 413 | dependencies: 414 | lodash "^4.17.15" 415 | ts-essentials "^7.0.1" 416 | 417 | "@types/body-parser@*": 418 | version "1.19.2" 419 | resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz" 420 | integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== 421 | dependencies: 422 | "@types/connect" "*" 423 | "@types/node" "*" 424 | 425 | "@types/connect@*": 426 | version "3.4.35" 427 | resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz" 428 | integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== 429 | dependencies: 430 | "@types/node" "*" 431 | 432 | "@types/cors@^2.8.12": 433 | version "2.8.12" 434 | resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz" 435 | integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== 436 | 437 | "@types/express-serve-static-core@^4.17.18": 438 | version "4.17.30" 439 | resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz" 440 | integrity sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ== 441 | dependencies: 442 | "@types/node" "*" 443 | "@types/qs" "*" 444 | "@types/range-parser" "*" 445 | 446 | "@types/express@^4.17.13": 447 | version "4.17.13" 448 | resolved "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz" 449 | integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== 450 | dependencies: 451 | "@types/body-parser" "*" 452 | "@types/express-serve-static-core" "^4.17.18" 453 | "@types/qs" "*" 454 | "@types/serve-static" "*" 455 | 456 | "@types/mime@*": 457 | version "3.0.1" 458 | resolved "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz" 459 | integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== 460 | 461 | "@types/node@*", "@types/node@^17.0.21": 462 | version "17.0.21" 463 | resolved "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz" 464 | integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== 465 | 466 | "@types/qs@*": 467 | version "6.9.7" 468 | resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz" 469 | integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== 470 | 471 | "@types/range-parser@*": 472 | version "1.2.4" 473 | resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz" 474 | integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== 475 | 476 | "@types/serve-static@*": 477 | version "1.15.0" 478 | resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz" 479 | integrity sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg== 480 | dependencies: 481 | "@types/mime" "*" 482 | "@types/node" "*" 483 | 484 | abbrev@1: 485 | version "1.1.1" 486 | resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" 487 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 488 | 489 | accepts@~1.3.8: 490 | version "1.3.8" 491 | resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" 492 | integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== 493 | dependencies: 494 | mime-types "~2.1.34" 495 | negotiator "0.6.3" 496 | 497 | acorn-walk@^8.1.1: 498 | version "8.2.0" 499 | resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" 500 | integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== 501 | 502 | acorn@^8.4.1: 503 | version "8.8.0" 504 | resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz" 505 | integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== 506 | 507 | aes-js@3.0.0: 508 | version "3.0.0" 509 | resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz" 510 | integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== 511 | 512 | alchemy-sdk@^2.0.3: 513 | version "2.0.3" 514 | resolved "https://registry.npmjs.org/alchemy-sdk/-/alchemy-sdk-2.0.3.tgz" 515 | integrity sha512-5sebgRUrL486KTkZ6w9ViDyfqZQ4Qxv9B+q9C4c3+VTi1iyTvSjGQub2JFTtxQl/70zdLY7ujWutgAGGVxOswQ== 516 | dependencies: 517 | "@ethersproject/abstract-provider" "^5.6.1" 518 | "@ethersproject/bignumber" "^5.6.2" 519 | "@ethersproject/networks" "^5.6.4" 520 | "@ethersproject/providers" "^5.6.8" 521 | "@ethersproject/wallet" "^5.6.2" 522 | "@ethersproject/web" "^5.6.1" 523 | axios "^0.26.1" 524 | sturdy-websocket "^0.2.1" 525 | websocket "^1.0.34" 526 | 527 | ansi-styles@^4.1.0: 528 | version "4.3.0" 529 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 530 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 531 | dependencies: 532 | color-convert "^2.0.1" 533 | 534 | anymatch@~3.1.2: 535 | version "3.1.2" 536 | resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" 537 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 538 | dependencies: 539 | normalize-path "^3.0.0" 540 | picomatch "^2.0.4" 541 | 542 | arg@^4.1.0: 543 | version "4.1.3" 544 | resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" 545 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 546 | 547 | array-flatten@1.1.1: 548 | version "1.1.1" 549 | resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" 550 | integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== 551 | 552 | axios@^0.26.1: 553 | version "0.26.1" 554 | resolved "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz" 555 | integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== 556 | dependencies: 557 | follow-redirects "^1.14.8" 558 | 559 | balanced-match@^1.0.0: 560 | version "1.0.2" 561 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" 562 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 563 | 564 | bech32@1.1.4: 565 | version "1.1.4" 566 | resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" 567 | integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== 568 | 569 | binary-extensions@^2.0.0: 570 | version "2.2.0" 571 | resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" 572 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 573 | 574 | bn.js@^4.11.9: 575 | version "4.12.0" 576 | resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" 577 | integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== 578 | 579 | bn.js@^5.2.1: 580 | version "5.2.1" 581 | resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" 582 | integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== 583 | 584 | body-parser@1.20.0: 585 | version "1.20.0" 586 | resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz" 587 | integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== 588 | dependencies: 589 | bytes "3.1.2" 590 | content-type "~1.0.4" 591 | debug "2.6.9" 592 | depd "2.0.0" 593 | destroy "1.2.0" 594 | http-errors "2.0.0" 595 | iconv-lite "0.4.24" 596 | on-finished "2.4.1" 597 | qs "6.10.3" 598 | raw-body "2.5.1" 599 | type-is "~1.6.18" 600 | unpipe "1.0.0" 601 | 602 | brace-expansion@^1.1.7: 603 | version "1.1.11" 604 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" 605 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 606 | dependencies: 607 | balanced-match "^1.0.0" 608 | concat-map "0.0.1" 609 | 610 | braces@~3.0.2: 611 | version "3.0.2" 612 | resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" 613 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 614 | dependencies: 615 | fill-range "^7.0.1" 616 | 617 | brorand@^1.1.0: 618 | version "1.1.0" 619 | resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" 620 | integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== 621 | 622 | bufferutil@^4.0.1: 623 | version "4.0.6" 624 | resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz" 625 | integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw== 626 | dependencies: 627 | node-gyp-build "^4.3.0" 628 | 629 | bytes@3.1.2: 630 | version "3.1.2" 631 | resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" 632 | integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== 633 | 634 | call-bind@^1.0.0: 635 | version "1.0.2" 636 | resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" 637 | integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== 638 | dependencies: 639 | function-bind "^1.1.1" 640 | get-intrinsic "^1.0.2" 641 | 642 | chalk@4.1.2: 643 | version "4.1.2" 644 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 645 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 646 | dependencies: 647 | ansi-styles "^4.1.0" 648 | supports-color "^7.1.0" 649 | 650 | chokidar@^3.5.2: 651 | version "3.5.3" 652 | resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" 653 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== 654 | dependencies: 655 | anymatch "~3.1.2" 656 | braces "~3.0.2" 657 | glob-parent "~5.1.2" 658 | is-binary-path "~2.1.0" 659 | is-glob "~4.0.1" 660 | normalize-path "~3.0.0" 661 | readdirp "~3.6.0" 662 | optionalDependencies: 663 | fsevents "~2.3.2" 664 | 665 | color-convert@^2.0.1: 666 | version "2.0.1" 667 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 668 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 669 | dependencies: 670 | color-name "~1.1.4" 671 | 672 | color-name@~1.1.4: 673 | version "1.1.4" 674 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 675 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 676 | 677 | concat-map@0.0.1: 678 | version "0.0.1" 679 | resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 680 | integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== 681 | 682 | content-disposition@0.5.4: 683 | version "0.5.4" 684 | resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" 685 | integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== 686 | dependencies: 687 | safe-buffer "5.2.1" 688 | 689 | content-type@~1.0.4: 690 | version "1.0.4" 691 | resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz" 692 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 693 | 694 | cookie-signature@1.0.6: 695 | version "1.0.6" 696 | resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" 697 | integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== 698 | 699 | cookie@0.5.0: 700 | version "0.5.0" 701 | resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" 702 | integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== 703 | 704 | cors@^2.8.5: 705 | version "2.8.5" 706 | resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" 707 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== 708 | dependencies: 709 | object-assign "^4" 710 | vary "^1" 711 | 712 | create-require@^1.1.0: 713 | version "1.1.1" 714 | resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" 715 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 716 | 717 | d@1, d@^1.0.1: 718 | version "1.0.1" 719 | resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz" 720 | integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== 721 | dependencies: 722 | es5-ext "^0.10.50" 723 | type "^1.0.1" 724 | 725 | debug@2.6.9, debug@^2.2.0: 726 | version "2.6.9" 727 | resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" 728 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 729 | dependencies: 730 | ms "2.0.0" 731 | 732 | debug@^3.2.7: 733 | version "3.2.7" 734 | resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" 735 | integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== 736 | dependencies: 737 | ms "^2.1.1" 738 | 739 | depd@2.0.0: 740 | version "2.0.0" 741 | resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" 742 | integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== 743 | 744 | destroy@1.2.0: 745 | version "1.2.0" 746 | resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" 747 | integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== 748 | 749 | diff@^4.0.1: 750 | version "4.0.2" 751 | resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" 752 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 753 | 754 | dotenv@^16.0.1: 755 | version "16.0.1" 756 | resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz" 757 | integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== 758 | 759 | ee-first@1.1.1: 760 | version "1.1.1" 761 | resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" 762 | integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== 763 | 764 | elliptic@6.5.4: 765 | version "6.5.4" 766 | resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" 767 | integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== 768 | dependencies: 769 | bn.js "^4.11.9" 770 | brorand "^1.1.0" 771 | hash.js "^1.0.0" 772 | hmac-drbg "^1.0.1" 773 | inherits "^2.0.4" 774 | minimalistic-assert "^1.0.1" 775 | minimalistic-crypto-utils "^1.0.1" 776 | 777 | encodeurl@~1.0.2: 778 | version "1.0.2" 779 | resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" 780 | integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== 781 | 782 | es5-ext@^0.10.35, es5-ext@^0.10.50: 783 | version "0.10.62" 784 | resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz" 785 | integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== 786 | dependencies: 787 | es6-iterator "^2.0.3" 788 | es6-symbol "^3.1.3" 789 | next-tick "^1.1.0" 790 | 791 | es6-iterator@^2.0.3: 792 | version "2.0.3" 793 | resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz" 794 | integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== 795 | dependencies: 796 | d "1" 797 | es5-ext "^0.10.35" 798 | es6-symbol "^3.1.1" 799 | 800 | es6-symbol@^3.1.1, es6-symbol@^3.1.3: 801 | version "3.1.3" 802 | resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz" 803 | integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== 804 | dependencies: 805 | d "^1.0.1" 806 | ext "^1.1.2" 807 | 808 | escape-html@~1.0.3: 809 | version "1.0.3" 810 | resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" 811 | integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== 812 | 813 | etag@~1.8.1: 814 | version "1.8.1" 815 | resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" 816 | integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== 817 | 818 | ethers@^5.7.0: 819 | version "5.7.0" 820 | resolved "https://registry.npmjs.org/ethers/-/ethers-5.7.0.tgz" 821 | integrity sha512-5Xhzp2ZQRi0Em+0OkOcRHxPzCfoBfgtOQA+RUylSkuHbhTEaQklnYi2hsWbRgs3ztJsXVXd9VKBcO1ScWL8YfA== 822 | dependencies: 823 | "@ethersproject/abi" "5.7.0" 824 | "@ethersproject/abstract-provider" "5.7.0" 825 | "@ethersproject/abstract-signer" "5.7.0" 826 | "@ethersproject/address" "5.7.0" 827 | "@ethersproject/base64" "5.7.0" 828 | "@ethersproject/basex" "5.7.0" 829 | "@ethersproject/bignumber" "5.7.0" 830 | "@ethersproject/bytes" "5.7.0" 831 | "@ethersproject/constants" "5.7.0" 832 | "@ethersproject/contracts" "5.7.0" 833 | "@ethersproject/hash" "5.7.0" 834 | "@ethersproject/hdnode" "5.7.0" 835 | "@ethersproject/json-wallets" "5.7.0" 836 | "@ethersproject/keccak256" "5.7.0" 837 | "@ethersproject/logger" "5.7.0" 838 | "@ethersproject/networks" "5.7.0" 839 | "@ethersproject/pbkdf2" "5.7.0" 840 | "@ethersproject/properties" "5.7.0" 841 | "@ethersproject/providers" "5.7.0" 842 | "@ethersproject/random" "5.7.0" 843 | "@ethersproject/rlp" "5.7.0" 844 | "@ethersproject/sha2" "5.7.0" 845 | "@ethersproject/signing-key" "5.7.0" 846 | "@ethersproject/solidity" "5.7.0" 847 | "@ethersproject/strings" "5.7.0" 848 | "@ethersproject/transactions" "5.7.0" 849 | "@ethersproject/units" "5.7.0" 850 | "@ethersproject/wallet" "5.7.0" 851 | "@ethersproject/web" "5.7.0" 852 | "@ethersproject/wordlists" "5.7.0" 853 | 854 | express@^4.18.1: 855 | version "4.18.1" 856 | resolved "https://registry.npmjs.org/express/-/express-4.18.1.tgz" 857 | integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q== 858 | dependencies: 859 | accepts "~1.3.8" 860 | array-flatten "1.1.1" 861 | body-parser "1.20.0" 862 | content-disposition "0.5.4" 863 | content-type "~1.0.4" 864 | cookie "0.5.0" 865 | cookie-signature "1.0.6" 866 | debug "2.6.9" 867 | depd "2.0.0" 868 | encodeurl "~1.0.2" 869 | escape-html "~1.0.3" 870 | etag "~1.8.1" 871 | finalhandler "1.2.0" 872 | fresh "0.5.2" 873 | http-errors "2.0.0" 874 | merge-descriptors "1.0.1" 875 | methods "~1.1.2" 876 | on-finished "2.4.1" 877 | parseurl "~1.3.3" 878 | path-to-regexp "0.1.7" 879 | proxy-addr "~2.0.7" 880 | qs "6.10.3" 881 | range-parser "~1.2.1" 882 | safe-buffer "5.2.1" 883 | send "0.18.0" 884 | serve-static "1.15.0" 885 | setprototypeof "1.2.0" 886 | statuses "2.0.1" 887 | type-is "~1.6.18" 888 | utils-merge "1.0.1" 889 | vary "~1.1.2" 890 | 891 | ext@^1.1.2: 892 | version "1.6.0" 893 | resolved "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz" 894 | integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== 895 | dependencies: 896 | type "^2.5.0" 897 | 898 | fill-range@^7.0.1: 899 | version "7.0.1" 900 | resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" 901 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 902 | dependencies: 903 | to-regex-range "^5.0.1" 904 | 905 | finalhandler@1.2.0: 906 | version "1.2.0" 907 | resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" 908 | integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== 909 | dependencies: 910 | debug "2.6.9" 911 | encodeurl "~1.0.2" 912 | escape-html "~1.0.3" 913 | on-finished "2.4.1" 914 | parseurl "~1.3.3" 915 | statuses "2.0.1" 916 | unpipe "~1.0.0" 917 | 918 | follow-redirects@^1.14.8: 919 | version "1.15.1" 920 | resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz" 921 | integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== 922 | 923 | forwarded@0.2.0: 924 | version "0.2.0" 925 | resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" 926 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 927 | 928 | fresh@0.5.2: 929 | version "0.5.2" 930 | resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" 931 | integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== 932 | 933 | fsevents@~2.3.2: 934 | version "2.3.2" 935 | resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" 936 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 937 | 938 | function-bind@^1.1.1: 939 | version "1.1.1" 940 | resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" 941 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 942 | 943 | get-intrinsic@^1.0.2: 944 | version "1.1.2" 945 | resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz" 946 | integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== 947 | dependencies: 948 | function-bind "^1.1.1" 949 | has "^1.0.3" 950 | has-symbols "^1.0.3" 951 | 952 | glob-parent@~5.1.2: 953 | version "5.1.2" 954 | resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" 955 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 956 | dependencies: 957 | is-glob "^4.0.1" 958 | 959 | has-flag@^3.0.0: 960 | version "3.0.0" 961 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" 962 | integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== 963 | 964 | has-flag@^4.0.0: 965 | version "4.0.0" 966 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 967 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 968 | 969 | has-symbols@^1.0.3: 970 | version "1.0.3" 971 | resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" 972 | integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== 973 | 974 | has@^1.0.3: 975 | version "1.0.3" 976 | resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" 977 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 978 | dependencies: 979 | function-bind "^1.1.1" 980 | 981 | hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: 982 | version "1.1.7" 983 | resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" 984 | integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== 985 | dependencies: 986 | inherits "^2.0.3" 987 | minimalistic-assert "^1.0.1" 988 | 989 | hmac-drbg@^1.0.1: 990 | version "1.0.1" 991 | resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" 992 | integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== 993 | dependencies: 994 | hash.js "^1.0.3" 995 | minimalistic-assert "^1.0.0" 996 | minimalistic-crypto-utils "^1.0.1" 997 | 998 | http-errors@2.0.0: 999 | version "2.0.0" 1000 | resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" 1001 | integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== 1002 | dependencies: 1003 | depd "2.0.0" 1004 | inherits "2.0.4" 1005 | setprototypeof "1.2.0" 1006 | statuses "2.0.1" 1007 | toidentifier "1.0.1" 1008 | 1009 | iconv-lite@0.4.24: 1010 | version "0.4.24" 1011 | resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" 1012 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 1013 | dependencies: 1014 | safer-buffer ">= 2.1.2 < 3" 1015 | 1016 | ignore-by-default@^1.0.1: 1017 | version "1.0.1" 1018 | resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz" 1019 | integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA== 1020 | 1021 | inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4: 1022 | version "2.0.4" 1023 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" 1024 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 1025 | 1026 | ipaddr.js@1.9.1: 1027 | version "1.9.1" 1028 | resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" 1029 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 1030 | 1031 | is-binary-path@~2.1.0: 1032 | version "2.1.0" 1033 | resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" 1034 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 1035 | dependencies: 1036 | binary-extensions "^2.0.0" 1037 | 1038 | is-extglob@^2.1.1: 1039 | version "2.1.1" 1040 | resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" 1041 | integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== 1042 | 1043 | is-glob@^4.0.1, is-glob@~4.0.1: 1044 | version "4.0.3" 1045 | resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" 1046 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 1047 | dependencies: 1048 | is-extglob "^2.1.1" 1049 | 1050 | is-number@^7.0.0: 1051 | version "7.0.0" 1052 | resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" 1053 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 1054 | 1055 | is-typedarray@^1.0.0: 1056 | version "1.0.0" 1057 | resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" 1058 | integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== 1059 | 1060 | js-sha3@0.8.0: 1061 | version "0.8.0" 1062 | resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" 1063 | integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== 1064 | 1065 | lodash@^4.17.15: 1066 | version "4.17.21" 1067 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" 1068 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 1069 | 1070 | make-error@^1.1.1: 1071 | version "1.3.6" 1072 | resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" 1073 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== 1074 | 1075 | media-typer@0.3.0: 1076 | version "0.3.0" 1077 | resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" 1078 | integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== 1079 | 1080 | merge-descriptors@1.0.1: 1081 | version "1.0.1" 1082 | resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" 1083 | integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== 1084 | 1085 | methods@~1.1.2: 1086 | version "1.1.2" 1087 | resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" 1088 | integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== 1089 | 1090 | mime-db@1.52.0: 1091 | version "1.52.0" 1092 | resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" 1093 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 1094 | 1095 | mime-types@~2.1.24, mime-types@~2.1.34: 1096 | version "2.1.35" 1097 | resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" 1098 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 1099 | dependencies: 1100 | mime-db "1.52.0" 1101 | 1102 | mime@1.6.0: 1103 | version "1.6.0" 1104 | resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" 1105 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 1106 | 1107 | minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: 1108 | version "1.0.1" 1109 | resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" 1110 | integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== 1111 | 1112 | minimalistic-crypto-utils@^1.0.1: 1113 | version "1.0.1" 1114 | resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" 1115 | integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== 1116 | 1117 | minimatch@^3.0.4: 1118 | version "3.1.2" 1119 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" 1120 | integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== 1121 | dependencies: 1122 | brace-expansion "^1.1.7" 1123 | 1124 | ms@2.0.0: 1125 | version "2.0.0" 1126 | resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 1127 | integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== 1128 | 1129 | ms@2.1.3: 1130 | version "2.1.3" 1131 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" 1132 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1133 | 1134 | ms@^2.1.1: 1135 | version "2.1.2" 1136 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" 1137 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1138 | 1139 | negotiator@0.6.3: 1140 | version "0.6.3" 1141 | resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" 1142 | integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== 1143 | 1144 | next-tick@^1.1.0: 1145 | version "1.1.0" 1146 | resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz" 1147 | integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== 1148 | 1149 | node-gyp-build@^4.3.0: 1150 | version "4.5.0" 1151 | resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz" 1152 | integrity sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg== 1153 | 1154 | nodemon@^2.0.19: 1155 | version "2.0.19" 1156 | resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.19.tgz" 1157 | integrity sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A== 1158 | dependencies: 1159 | chokidar "^3.5.2" 1160 | debug "^3.2.7" 1161 | ignore-by-default "^1.0.1" 1162 | minimatch "^3.0.4" 1163 | pstree.remy "^1.1.8" 1164 | semver "^5.7.1" 1165 | simple-update-notifier "^1.0.7" 1166 | supports-color "^5.5.0" 1167 | touch "^3.1.0" 1168 | undefsafe "^2.0.5" 1169 | 1170 | nopt@~1.0.10: 1171 | version "1.0.10" 1172 | resolved "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz" 1173 | integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg== 1174 | dependencies: 1175 | abbrev "1" 1176 | 1177 | normalize-path@^3.0.0, normalize-path@~3.0.0: 1178 | version "3.0.0" 1179 | resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" 1180 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 1181 | 1182 | object-assign@^4: 1183 | version "4.1.1" 1184 | resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" 1185 | integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== 1186 | 1187 | object-inspect@^1.9.0: 1188 | version "1.12.2" 1189 | resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" 1190 | integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== 1191 | 1192 | on-finished@2.4.1: 1193 | version "2.4.1" 1194 | resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" 1195 | integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== 1196 | dependencies: 1197 | ee-first "1.1.1" 1198 | 1199 | parseurl@~1.3.3: 1200 | version "1.3.3" 1201 | resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" 1202 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 1203 | 1204 | path-to-regexp@0.1.7: 1205 | version "0.1.7" 1206 | resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" 1207 | integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== 1208 | 1209 | picomatch@^2.0.4, picomatch@^2.2.1: 1210 | version "2.3.1" 1211 | resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" 1212 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 1213 | 1214 | prettier@^2.5.1: 1215 | version "2.5.1" 1216 | resolved "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz" 1217 | integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== 1218 | 1219 | prisma@^4.2.1: 1220 | version "4.2.1" 1221 | resolved "https://registry.npmjs.org/prisma/-/prisma-4.2.1.tgz" 1222 | integrity sha512-HuYqnTDgH8atjPGtYmY0Ql9XrrJnfW7daG1PtAJRW0E6gJxc50lY3vrIDn0yjMR3TvRlypjTcspQX8DT+xD4Sg== 1223 | dependencies: 1224 | "@prisma/engines" "4.2.1" 1225 | 1226 | proxy-addr@~2.0.7: 1227 | version "2.0.7" 1228 | resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" 1229 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 1230 | dependencies: 1231 | forwarded "0.2.0" 1232 | ipaddr.js "1.9.1" 1233 | 1234 | pstree.remy@^1.1.8: 1235 | version "1.1.8" 1236 | resolved "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz" 1237 | integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== 1238 | 1239 | qs@6.10.3: 1240 | version "6.10.3" 1241 | resolved "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz" 1242 | integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== 1243 | dependencies: 1244 | side-channel "^1.0.4" 1245 | 1246 | range-parser@~1.2.1: 1247 | version "1.2.1" 1248 | resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" 1249 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 1250 | 1251 | raw-body@2.5.1: 1252 | version "2.5.1" 1253 | resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz" 1254 | integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== 1255 | dependencies: 1256 | bytes "3.1.2" 1257 | http-errors "2.0.0" 1258 | iconv-lite "0.4.24" 1259 | unpipe "1.0.0" 1260 | 1261 | readdirp@~3.6.0: 1262 | version "3.6.0" 1263 | resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" 1264 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 1265 | dependencies: 1266 | picomatch "^2.2.1" 1267 | 1268 | safe-buffer@5.2.1: 1269 | version "5.2.1" 1270 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" 1271 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1272 | 1273 | "safer-buffer@>= 2.1.2 < 3": 1274 | version "2.1.2" 1275 | resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" 1276 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1277 | 1278 | scrypt-js@3.0.1: 1279 | version "3.0.1" 1280 | resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" 1281 | integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== 1282 | 1283 | semver@^5.7.1: 1284 | version "5.7.1" 1285 | resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" 1286 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1287 | 1288 | semver@~7.0.0: 1289 | version "7.0.0" 1290 | resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" 1291 | integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== 1292 | 1293 | send@0.18.0: 1294 | version "0.18.0" 1295 | resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" 1296 | integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== 1297 | dependencies: 1298 | debug "2.6.9" 1299 | depd "2.0.0" 1300 | destroy "1.2.0" 1301 | encodeurl "~1.0.2" 1302 | escape-html "~1.0.3" 1303 | etag "~1.8.1" 1304 | fresh "0.5.2" 1305 | http-errors "2.0.0" 1306 | mime "1.6.0" 1307 | ms "2.1.3" 1308 | on-finished "2.4.1" 1309 | range-parser "~1.2.1" 1310 | statuses "2.0.1" 1311 | 1312 | serve-static@1.15.0: 1313 | version "1.15.0" 1314 | resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" 1315 | integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== 1316 | dependencies: 1317 | encodeurl "~1.0.2" 1318 | escape-html "~1.0.3" 1319 | parseurl "~1.3.3" 1320 | send "0.18.0" 1321 | 1322 | setprototypeof@1.2.0: 1323 | version "1.2.0" 1324 | resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" 1325 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 1326 | 1327 | side-channel@^1.0.4: 1328 | version "1.0.4" 1329 | resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz" 1330 | integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== 1331 | dependencies: 1332 | call-bind "^1.0.0" 1333 | get-intrinsic "^1.0.2" 1334 | object-inspect "^1.9.0" 1335 | 1336 | simple-update-notifier@^1.0.7: 1337 | version "1.0.7" 1338 | resolved "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz" 1339 | integrity sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew== 1340 | dependencies: 1341 | semver "~7.0.0" 1342 | 1343 | statuses@2.0.1: 1344 | version "2.0.1" 1345 | resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" 1346 | integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== 1347 | 1348 | sturdy-websocket@^0.2.1: 1349 | version "0.2.1" 1350 | resolved "https://registry.npmjs.org/sturdy-websocket/-/sturdy-websocket-0.2.1.tgz" 1351 | integrity sha512-NnzSOEKyv4I83qbuKw9ROtJrrT6Z/Xt7I0HiP/e6H6GnpeTDvzwGIGeJ8slai+VwODSHQDooW2CAilJwT9SpRg== 1352 | 1353 | supports-color@^5.5.0: 1354 | version "5.5.0" 1355 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" 1356 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1357 | dependencies: 1358 | has-flag "^3.0.0" 1359 | 1360 | supports-color@^7.1.0: 1361 | version "7.2.0" 1362 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1363 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1364 | dependencies: 1365 | has-flag "^4.0.0" 1366 | 1367 | to-regex-range@^5.0.1: 1368 | version "5.0.1" 1369 | resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" 1370 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1371 | dependencies: 1372 | is-number "^7.0.0" 1373 | 1374 | toidentifier@1.0.1: 1375 | version "1.0.1" 1376 | resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" 1377 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== 1378 | 1379 | touch@^3.1.0: 1380 | version "3.1.0" 1381 | resolved "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz" 1382 | integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== 1383 | dependencies: 1384 | nopt "~1.0.10" 1385 | 1386 | ts-essentials@^7.0.1: 1387 | version "7.0.3" 1388 | resolved "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz" 1389 | integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== 1390 | 1391 | ts-node@^10.9.1: 1392 | version "10.9.1" 1393 | resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" 1394 | integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== 1395 | dependencies: 1396 | "@cspotcode/source-map-support" "^0.8.0" 1397 | "@tsconfig/node10" "^1.0.7" 1398 | "@tsconfig/node12" "^1.0.7" 1399 | "@tsconfig/node14" "^1.0.0" 1400 | "@tsconfig/node16" "^1.0.2" 1401 | acorn "^8.4.1" 1402 | acorn-walk "^8.1.1" 1403 | arg "^4.1.0" 1404 | create-require "^1.1.0" 1405 | diff "^4.0.1" 1406 | make-error "^1.1.1" 1407 | v8-compile-cache-lib "^3.0.1" 1408 | yn "3.1.1" 1409 | 1410 | type-is@~1.6.18: 1411 | version "1.6.18" 1412 | resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" 1413 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 1414 | dependencies: 1415 | media-typer "0.3.0" 1416 | mime-types "~2.1.24" 1417 | 1418 | type@^1.0.1: 1419 | version "1.2.0" 1420 | resolved "https://registry.npmjs.org/type/-/type-1.2.0.tgz" 1421 | integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== 1422 | 1423 | type@^2.5.0: 1424 | version "2.7.2" 1425 | resolved "https://registry.npmjs.org/type/-/type-2.7.2.tgz" 1426 | integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== 1427 | 1428 | typedarray-to-buffer@^3.1.5: 1429 | version "3.1.5" 1430 | resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" 1431 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== 1432 | dependencies: 1433 | is-typedarray "^1.0.0" 1434 | 1435 | typescript@^4.6.2: 1436 | version "4.6.2" 1437 | resolved "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz" 1438 | integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== 1439 | 1440 | undefsafe@^2.0.5: 1441 | version "2.0.5" 1442 | resolved "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz" 1443 | integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== 1444 | 1445 | unpipe@1.0.0, unpipe@~1.0.0: 1446 | version "1.0.0" 1447 | resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" 1448 | integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== 1449 | 1450 | utf-8-validate@^5.0.2: 1451 | version "5.0.9" 1452 | resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz" 1453 | integrity sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q== 1454 | dependencies: 1455 | node-gyp-build "^4.3.0" 1456 | 1457 | utils-merge@1.0.1: 1458 | version "1.0.1" 1459 | resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" 1460 | integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== 1461 | 1462 | v8-compile-cache-lib@^3.0.1: 1463 | version "3.0.1" 1464 | resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" 1465 | integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== 1466 | 1467 | vary@^1, vary@~1.1.2: 1468 | version "1.1.2" 1469 | resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" 1470 | integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== 1471 | 1472 | websocket@^1.0.34: 1473 | version "1.0.34" 1474 | resolved "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz" 1475 | integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== 1476 | dependencies: 1477 | bufferutil "^4.0.1" 1478 | debug "^2.2.0" 1479 | es5-ext "^0.10.50" 1480 | typedarray-to-buffer "^3.1.5" 1481 | utf-8-validate "^5.0.2" 1482 | yaeti "^0.0.6" 1483 | 1484 | ws@7.4.6: 1485 | version "7.4.6" 1486 | resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" 1487 | integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== 1488 | 1489 | yaeti@^0.0.6: 1490 | version "0.0.6" 1491 | resolved "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz" 1492 | integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== 1493 | 1494 | yn@3.1.1: 1495 | version "3.1.1" 1496 | resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" 1497 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 1498 | --------------------------------------------------------------------------------