diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..71e48fa 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,12 @@ { - "extends": "next/core-web-vitals" + "root": true, + "extends": ["next/core-web-vitals", "plugin:react/recommended", "prettier"], + "plugins": ["prettier"], + "rules": { + "prettier/prettier": "error", + "quotes": ["error", "double"], + "react/react-in-jsx-scope": "off", + "react-hooks/exhaustive-deps": "off", + "react/prop-types": "off" + } } diff --git a/.github/workflows/gha_app_zq2-staking.yml b/.github/workflows/gha_app_zq2-staking.yml index 32df090..c4bc386 100644 --- a/.github/workflows/gha_app_zq2-staking.yml +++ b/.github/workflows/gha_app_zq2-staking.yml @@ -24,10 +24,7 @@ jobs: strategy: fail-fast: false matrix: - application: - [ - zq2-staking/zq2-staking-frontend, - ] + application: [zq2-staking/zq2-staking-frontend] include: - application: zq2-staking/zq2-staking-frontend image_name: zq2-staking-frontend @@ -68,10 +65,7 @@ jobs: strategy: fail-fast: false matrix: - application: - [ - zq2-staking/zq2-staking-frontend, - ] + application: [zq2-staking/zq2-staking-frontend] include: - application: zq2-staking/zq2-staking-frontend image_name: zq2-staking-frontend diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml new file mode 100644 index 0000000..d6d89a5 --- /dev/null +++ b/.github/workflows/linting.yaml @@ -0,0 +1,36 @@ +name: Lint and Format Check + +on: + pull_request: + branches: [main] + +jobs: + check: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Lint + run: npm run lint:check + continue-on-error: false + + - name: Format Check + id: format_check + run: | + npm run format + if [[ $(git status --porcelain | wc -l) -gt 0 ]]; then + echo "changed=true" >> $GITHUB_OUTPUT # Use environment file + echo "::error file=:: Files were formatted. Please commit the changes." + exit 1 + else + echo "changed=false" >> $GITHUB_OUTPUT # Use environment file + fi diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..05b20cc --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,13 @@ +/** + * @see https://prettier.io/docs/en/configuration.html + * @type {import("prettier").Config} + */ +const config = { + trailingComma: "es5", + tabWidth: 2, + semi: false, + singleQuote: false, + arrowParens: "always", +} + +module.exports = config diff --git a/README.md b/README.md index ab49e6c..406d280 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,17 @@ ## Running locally 1. Install dependencies + ```sh npm install ``` + 2. Run the development server + ```sh npm run dev ``` + 3. Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. ## Environments @@ -22,8 +26,8 @@ This enables easy UX/UI workflow where you can modify the wallet states in the c ### .env.local_zq2 -This one makes the app connected to locally run docker-compose ZQ2 network. +This one makes the app connected to locally run docker-compose ZQ2 network. ## Adding new Delegator -1. Fetch delegator static data using `npx tsx src/script/fetchPoolStaticData.ts` \ No newline at end of file +1. Fetch delegator static data using `npx tsx src/script/fetchPoolStaticData.ts` diff --git a/next.config.mjs b/next.config.mjs index 960903e..9b551d2 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -19,11 +19,11 @@ const nextConfig = { images: { remotePatterns: [ { - protocol: 'https', - hostname: '**', + protocol: "https", + hostname: "**", }, ], }, -}; +} -export default nextConfig; +export default nextConfig diff --git a/package-lock.json b/package-lock.json index f1ea2e7..b51a0b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,9 +25,13 @@ "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "autoprefixer": "10.4.20", - "eslint": "8.57.1", - "eslint-config-next": "14.2.18", + "eslint": "^8.57.1", + "eslint-config-next": "^14.2.18", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-react": "^7.37.4", "postcss": "8.4.49", + "prettier": "^3.4.2", "tailwindcss": "3.4.15", "typescript": "5.7.2" } @@ -3704,6 +3708,19 @@ "node": ">=14" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@rainbow-me/rainbowkit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@rainbow-me/rainbowkit/-/rainbowkit-2.2.0.tgz", @@ -5709,13 +5726,14 @@ } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" @@ -5803,15 +5821,16 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5837,19 +5856,19 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -5882,6 +5901,16 @@ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", @@ -6305,15 +6334,44 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -7025,14 +7083,15 @@ "dev": true }, "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -7042,29 +7101,31 @@ } }, "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/inspect-js" } }, "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" }, @@ -7288,6 +7349,20 @@ "node": ">=6.0.0" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexify": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", @@ -7445,57 +7520,63 @@ } }, "node_modules/es-abstract": { - "version": "1.23.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz", - "integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==", + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "dev": true, + "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", - "gopd": "^1.0.1", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.5", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.3", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" }, "engines": { "node": ">= 0.4" @@ -7505,12 +7586,10 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -7524,26 +7603,28 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", - "integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", + "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", - "gopd": "^1.0.1", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "iterator.prototype": "^1.1.3", - "safe-array-concat": "^1.1.2" + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" }, "engines": { "node": ">= 0.4" @@ -7553,7 +7634,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, "dependencies": { "es-errors": "^1.3.0" }, @@ -7562,14 +7642,16 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -7632,6 +7714,7 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -7687,6 +7770,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.18.tgz", "integrity": "sha512-SuDRcpJY5VHBkhz5DijJ4iA4bVnBA0n48Rb+YSJSCDr+h7kKAcb1mZHusLbW+WA8LDB6edSolomXA55eG3eOVA==", "dev": true, + "license": "MIT", "dependencies": { "@next/eslint-plugin-next": "14.2.18", "@rushstack/eslint-patch": "^1.3.3", @@ -7709,6 +7793,19 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.0.1.tgz", + "integrity": "sha512-lZBts941cyJyeaooiKxAtzoPHTN+GbQTJFAIdQbRhA4/8whaAraEh47Whw/ZFfrjNSnlAxqfm9i0XVAEkULjCw==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "build/bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -7882,29 +7979,61 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, + "node_modules/eslint-plugin-prettier": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz", + "integrity": "sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.9.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { - "version": "7.37.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz", - "integrity": "sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==", + "version": "7.37.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", + "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.2", + "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.1.0", + "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.values": "^1.2.0", + "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11", + "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "engines": { @@ -8290,6 +8419,13 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -8562,15 +8698,18 @@ } }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -8615,15 +8754,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -8654,6 +8799,19 @@ "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.1.2.tgz", "integrity": "sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==" }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -8667,14 +8825,15 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -8785,11 +8944,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8852,9 +9012,14 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -8863,9 +9028,10 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -9098,14 +9264,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -9143,13 +9310,15 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -9165,12 +9334,17 @@ "peer": true }, "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -9180,12 +9354,16 @@ } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9203,13 +9381,14 @@ } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.1.tgz", + "integrity": "sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -9253,11 +9432,14 @@ } }, "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, + "license": "MIT", "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" }, "engines": { @@ -9268,12 +9450,14 @@ } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -9315,12 +9499,13 @@ } }, "node_modules/is-finalizationregistry": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz", - "integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -9398,18 +9583,7 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -9426,12 +9600,14 @@ } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -9462,13 +9638,16 @@ } }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -9482,6 +9661,7 @@ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -9490,12 +9670,13 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -9516,12 +9697,14 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -9531,12 +9714,15 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -9546,11 +9732,12 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -9564,6 +9751,7 @@ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -9572,25 +9760,30 @@ } }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.0.tgz", + "integrity": "sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -9694,16 +9887,18 @@ } }, "node_modules/iterator.prototype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", - "integrity": "sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -10376,6 +10571,15 @@ "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==", "peer": true }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-query-parser": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/media-query-parser/-/media-query-parser-2.0.2.tgz", @@ -11247,6 +11451,7 @@ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -11264,14 +11469,17 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -11328,12 +11536,14 @@ } }, "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, @@ -11432,6 +11642,24 @@ "node": ">= 0.8.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/ox": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ox/-/ox-0.1.2.tgz", @@ -11930,6 +12158,35 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -13167,18 +13424,20 @@ } }, "node_modules/reflect.getprototypeof": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz", - "integrity": "sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", + "es-abstract": "^1.23.9", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "which-builtin-type": "^1.1.4" + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -13393,14 +13652,16 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, "engines": { @@ -13429,15 +13690,33 @@ } ] }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "is-regex": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -13644,6 +13923,21 @@ "node": ">= 0.4" } }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -13703,15 +13997,73 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -14008,23 +14360,25 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", - "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", + "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.7", - "regexp.prototype.flags": "^1.5.2", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -14044,15 +14398,19 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -14062,15 +14420,20 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -14225,6 +14588,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/system-architecture": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", @@ -14640,30 +15020,32 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -14673,18 +15055,19 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz", - "integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "reflect.getprototypeof": "^1.0.6" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { "node": ">= 0.4" @@ -14765,15 +15148,19 @@ } }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -15241,40 +15628,45 @@ } }, "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", "dev": true, + "license": "MIT", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-builtin-type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.0.tgz", - "integrity": "sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", + "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", + "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", + "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", - "which-typed-array": "^1.1.15" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -15288,6 +15680,7 @@ "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -15307,14 +15700,16 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", + "integrity": "sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==", + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "for-each": "^0.3.3", - "gopd": "^1.0.1", + "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, "engines": { diff --git a/package.json b/package.json index 11d1fac..2874f27 100644 --- a/package.json +++ b/package.json @@ -4,10 +4,11 @@ "private": true, "scripts": { "dev": "next dev", - "local_z": "npx tsx scripts/run-dev.ts", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "eslint . --fix", + "lint:check": "eslint .", + "format": "prettier --write ." }, "dependencies": { "@rainbow-me/rainbowkit": "^2.2.0", @@ -27,9 +28,13 @@ "@types/react": "18.3.12", "@types/react-dom": "18.3.1", "autoprefixer": "10.4.20", - "eslint": "8.57.1", - "eslint-config-next": "14.2.18", + "eslint": "^8.57.1", + "eslint-config-next": "^14.2.18", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-react": "^7.37.4", "postcss": "8.4.49", + "prettier": "^3.4.2", "tailwindcss": "3.4.15", "typescript": "5.7.2" } diff --git a/postcss.config.js b/postcss.config.js index cdbe50f..8e266ab 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,7 +1,7 @@ module.exports = { plugins: { - 'tailwindcss/nesting': {}, + "tailwindcss/nesting": {}, tailwindcss: {}, autoprefixer: {}, }, -}; +} diff --git a/scripts/run-dev.ts b/scripts/run-dev.ts index bf1abe7..bd0c65c 100644 --- a/scripts/run-dev.ts +++ b/scripts/run-dev.ts @@ -1,20 +1,20 @@ -const cli = require("next/dist/cli/next-dev"); +const cli = require("next/dist/cli/next-dev") -const overridePort = process.env.Z_LISTEN_PORT; +const overridePort = process.env.Z_LISTEN_PORT if (process.argv.length > 2 && process.argv[2] === "set_env") { - process.env.Z_CONFIG = "../etc/testnet"; + process.env.Z_CONFIG = "../etc/testnet" } if (overridePort === undefined) { - console.log("running on default nextjs port"); + console.log("running on default nextjs port") cli.nextDev({ _: [null], - }); + }) } else { - console.log("overridePort", overridePort); + console.log("overridePort", overridePort) cli.nextDev({ _: [null], - "port": Number.parseInt(overridePort), - }); + port: Number.parseInt(overridePort), + }) } diff --git a/src/components/dummyWalletSelector.tsx b/src/components/dummyWalletSelector.tsx index 8a4e679..8301360 100644 --- a/src/components/dummyWalletSelector.tsx +++ b/src/components/dummyWalletSelector.tsx @@ -1,22 +1,19 @@ -import { WalletConnector } from "@/contexts/walletConnector"; -import { dummyWallets } from "@/misc/walletsConfig"; -import { Modal, Radio, Space } from "antd"; -import { useState } from "react"; - - +import { WalletConnector } from "@/contexts/walletConnector" +import { dummyWallets } from "@/misc/walletsConfig" +import { Modal, Radio, Space } from "antd" +import { useState } from "react" const DummyWalletSelector: React.FC = () => { - const { isDummyWalletSelectorOpen, selectDummyWallet, disconnectDummyWallet, - } = WalletConnector.useContainer(); + } = WalletConnector.useContainer() - const [walletIndex, setValue] = useState(0); + const [walletIndex, setValue] = useState(0) const selectedWalletChanged = (e: any) => { - setValue(e.target.value); + setValue(e.target.value) } return ( @@ -27,20 +24,20 @@ const DummyWalletSelector: React.FC = () => { okText="Connect" onOk={() => selectDummyWallet(dummyWallets[walletIndex])} onCancel={disconnectDummyWallet} - okButtonProps={{ className: 'btn-primary-cyan' }} + okButtonProps={{ className: "btn-primary-cyan" }} > - - { - dummyWallets.map((wallet, index) => ( - {wallet.name} - )) - } - - + + {dummyWallets.map((wallet, index) => ( + + {wallet.name} + + ))} + + - ); -}; + ) +} -export default DummyWalletSelector; \ No newline at end of file +export default DummyWalletSelector diff --git a/src/components/loginView.tsx b/src/components/loginView.tsx index 3a979f0..7318929 100644 --- a/src/components/loginView.tsx +++ b/src/components/loginView.tsx @@ -1,10 +1,10 @@ -import Image from 'next/image'; -import ArrowRight from '../assets/svgs/arrow-right-black.svg' -import { AppConfigStorage } from "@/contexts/appConfigStorage"; -import { WalletConnector } from "@/contexts/walletConnector"; -import { MOCK_CHAIN } from "@/misc/chainConfig"; -import { ConnectButton } from "@rainbow-me/rainbowkit"; -import { Button } from "antd"; +import Image from "next/image" +import ArrowRight from "../assets/svgs/arrow-right-black.svg" +import { AppConfigStorage } from "@/contexts/appConfigStorage" +import { WalletConnector } from "@/contexts/walletConnector" +import { MOCK_CHAIN } from "@/misc/chainConfig" +import { ConnectButton } from "@rainbow-me/rainbowkit" +import { Button } from "antd" const CustomConnectButton = () => { return ( @@ -23,16 +23,16 @@ const CustomConnectButton = () => { onClick={openConnectModal} className="btn-primary-gradient-aqua !w-fit px-14 group flex items-center" > - Connect Wallet + Connect Wallet {`arrow - ); + ) } // Wrong network @@ -41,77 +41,68 @@ const CustomConnectButton = () => { - ); + ) } // Connected and correct network return ( - - ); + ) }} - ); -}; + ) +} const LoginView: React.FC = () => { - - const { - appConfig - } = AppConfigStorage.useContainer(); + const { appConfig } = AppConfigStorage.useContainer() - const { - connectDummyWallet, - isDummyWalletConnecting, - } = WalletConnector.useContainer(); + const { connectDummyWallet, isDummyWalletConnecting } = + WalletConnector.useContainer() - const connectWallet = appConfig.chainId === MOCK_CHAIN.id ? ( - ) : ( - ); + ) return (

Staking Portal

- Help us Empower and secure the Zilliqa Chain{' '} + Help us Empower and secure the Zilliqa Chain{" "}

-
- {connectWallet} -
+
{connectWallet}
- ); -}; + ) +} -export default LoginView; +export default LoginView diff --git a/src/components/sortBtn.tsx b/src/components/sortBtn.tsx index 73aa3b3..492d1a4 100644 --- a/src/components/sortBtn.tsx +++ b/src/components/sortBtn.tsx @@ -1,16 +1,12 @@ -import React, { useState } from 'react'; +import React, { useState } from "react" interface SortBtnProps { - variable: String; - isClicked: Boolean; - onClick: () => void; + variable: String + isClicked: Boolean + onClick: () => void } -const SortBtn: React.FC = ({ - variable, - isClicked, - onClick, -}) => { +const SortBtn: React.FC = ({ variable, isClicked, onClick }) => { return (
= ({ fill="none" xmlns="http://www.w3.org/2000/svg" className={`duration-700 stroke-gray1 group-hover:stroke-white ease-in-out ${ - isClicked ? 'scale-y-[-1]' : '' + isClicked ? "scale-y-[-1]" : "" }`} > @@ -57,7 +53,7 @@ const SortBtn: React.FC = ({ {variable}
- ); -}; + ) +} -export default SortBtn; +export default SortBtn diff --git a/src/components/stakingCalculator.tsx b/src/components/stakingCalculator.tsx index d84122e..4fdee69 100644 --- a/src/components/stakingCalculator.tsx +++ b/src/components/stakingCalculator.tsx @@ -1,84 +1,88 @@ -import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage"; -import { useEffect, useState } from "react"; -import { Button, Input, Tooltip } from "antd"; -import { WalletConnector } from "@/contexts/walletConnector"; -import { formatPercentage, convertZilValueInToken, getTxExplorerUrl, formatAddress } from "@/misc/formatting"; -import { formatUnits, parseEther } from "viem"; -import { StakingOperations } from "@/contexts/stakingOperations"; - import { AppConfigStorage } from "@/contexts/appConfigStorage"; -import Link from "next/link"; - +import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage" +import { useEffect, useState } from "react" +import { Button, Input, Tooltip } from "antd" +import { WalletConnector } from "@/contexts/walletConnector" +import { + formatPercentage, + convertZilValueInToken, + getTxExplorerUrl, + formatAddress, +} from "@/misc/formatting" +import { formatUnits, parseEther } from "viem" +import { StakingOperations } from "@/contexts/stakingOperations" +import { AppConfigStorage } from "@/contexts/appConfigStorage" +import Link from "next/link" const StakingCalculator: React.FC = () => { - const { - appConfig - } = AppConfigStorage.useContainer(); + const { appConfig } = AppConfigStorage.useContainer() - const { - zilAvailable, - } = WalletConnector.useContainer(); + const { zilAvailable } = WalletConnector.useContainer() const { stake, isStakingInProgress, stakingCallTxHash, stakeContractCallError, - } = StakingOperations.useContainer(); + } = StakingOperations.useContainer() - const { - stakingPoolForView - } = StakingPoolsStorage.useContainer(); + const { stakingPoolForView } = StakingPoolsStorage.useContainer() - const [zilToStake, setZilToStake] = useState(formatUnits(stakingPoolForView?.stakingPool.definition.minimumStake || 0n, 18)); + const [zilToStake, setZilToStake] = useState( + formatUnits( + stakingPoolForView?.stakingPool.definition.minimumStake || 0n, + 18 + ) + ) useEffect(() => { - onMinClick(); - }, [stakingPoolForView]); + onMinClick() + }, [stakingPoolForView]) const handleChange = (e: React.ChangeEvent) => { - const { value: inputValue } = e.target; - const reg = /^-?\d*(\.\d*)?$/; - if ( - reg.test(inputValue) || - inputValue === '' || - inputValue === '-' - ) { - setZilToStake(inputValue); + const { value: inputValue } = e.target + const reg = /^-?\d*(\.\d*)?$/ + if (reg.test(inputValue) || inputValue === "" || inputValue === "-") { + setZilToStake(inputValue) } - }; + } const handleFocus = () => { - if (zilToStake === '') onMinClick(); - }; + if (zilToStake === "") onMinClick() + } const handleBlur = () => { - let valueTemp = zilToStake; - + let valueTemp = zilToStake + if ( - zilToStake.charAt(zilToStake.length - 1) === '.' || - zilToStake === '-' + zilToStake.charAt(zilToStake.length - 1) === "." || + zilToStake === "-" ) { - valueTemp = zilToStake.slice(0, -1); + valueTemp = zilToStake.slice(0, -1) } - setZilToStake(valueTemp.replace(/0*(\d+)/, '$1')); + setZilToStake(valueTemp.replace(/0*(\d+)/, "$1")) - if (zilToStake === '') onMinClick(); - }; + if (zilToStake === "") onMinClick() + } + + const zilToStakeNumber = parseFloat(zilToStake) - const zilToStakeNumber = parseFloat(zilToStake); - - const zilInWei = parseEther(zilToStake); - const zilToStakeOk = !isNaN(zilToStakeNumber) && zilToStakeNumber <= (zilAvailable || 0n); - const canStake = stakingPoolForView?.stakingPool.data && zilToStakeNumber > 0 && zilToStakeNumber <= (zilAvailable || 0n); + const zilInWei = parseEther(zilToStake) + const zilToStakeOk = + !isNaN(zilToStakeNumber) && zilToStakeNumber <= (zilAvailable || 0n) + const canStake = + stakingPoolForView?.stakingPool.data && + zilToStakeNumber > 0 && + zilToStakeNumber <= (zilAvailable || 0n) const onMinClick = () => { - setZilToStake(`${formatUnits(stakingPoolForView?.stakingPool.definition.minimumStake || 0n, 18) }`) + setZilToStake( + `${formatUnits(stakingPoolForView?.stakingPool.definition.minimumStake || 0n, 18)}` + ) } const onMaxClick = () => { - setZilToStake(`${formatUnits(zilAvailable || 0n, 18) }`) + setZilToStake(`${formatUnits(zilAvailable || 0n, 18)}`) } - return ( stakingPoolForView && ( @@ -87,35 +91,31 @@ const StakingCalculator: React.FC = () => {
{stakingPoolForView!.stakingPool.data ? ( <> ~ - { - !isNaN(zilToStakeNumber) && !isNaN(stakingPoolForView.stakingPool.data - .zilToTokenRate) - ? convertZilValueInToken(zilToStakeNumber, stakingPoolForView.stakingPool.data - .zilToTokenRate) - : "" - } - {' '} - { - stakingPoolForView.stakingPool.definition - .tokenSymbol - }{' '} + {!isNaN(zilToStakeNumber) && + !isNaN(stakingPoolForView.stakingPool.data.zilToTokenRate) + ? convertZilValueInToken( + zilToStakeNumber, + stakingPoolForView.stakingPool.data.zilToTokenRate + ) + : ""}{" "} + {stakingPoolForView.stakingPool.definition.tokenSymbol}{" "} ~ @@ -150,7 +150,7 @@ const StakingCalculator: React.FC = () => {
- Commission Fee:{' '} + Commission Fee:{" "} {stakingPoolForView!.stakingPool.data ? ( <> {formatPercentage( @@ -162,25 +162,30 @@ const StakingCalculator: React.FC = () => { )}
- Max transaction cost: {zilToStake ? '0.01' : '0'}$ + Max transaction cost: {zilToStake ? "0.01" : "0"}$
Rate
- {stakingPoolForView!.stakingPool.data && ( -
{`1 ZIL = ~${ stakingPoolForView.stakingPool.data.zilToTokenRate} ${stakingPoolForView.stakingPool.definition.tokenSymbol}`}
- )} + {stakingPoolForView!.stakingPool.data && ( +
{`1 ZIL = ~${stakingPoolForView.stakingPool.data.zilToTokenRate} ${stakingPoolForView.stakingPool.definition.tokenSymbol}`}
+ )}
- - APR - + + APR + {stakingPoolForView!.stakingPool.data ? ( <> - ~{formatPercentage( - stakingPoolForView!.stakingPool.data.apr - )} + ~ + {formatPercentage(stakingPoolForView!.stakingPool.data.apr)} ) : (
@@ -195,31 +200,40 @@ const StakingCalculator: React.FC = () => { size="large" className="btn-primary-gradient-aqua-lg lg:btn-primary-gradient-aqua" disabled={!canStake} - onClick={() => stake(stakingPoolForView.stakingPool.definition.address, zilInWei)} - loading={isStakingInProgress} > + onClick={() => + stake( + stakingPoolForView.stakingPool.definition.address, + zilInWei + ) + } + loading={isStakingInProgress} + > STAKE
- { - stakingCallTxHash !== undefined && ( -
- - Last staking transaction: {formatAddress(stakingCallTxHash)} - -
- ) - } + {stakingCallTxHash !== undefined && ( +
+ + Last staking transaction: {formatAddress(stakingCallTxHash)} + +
+ )} {stakeContractCallError && (
{stakeContractCallError.message}
)} - + ) - ); -}; + ) +} -export default StakingCalculator; \ No newline at end of file +export default StakingCalculator diff --git a/src/components/stakingPoolCard.tsx b/src/components/stakingPoolCard.tsx index 1ae8a0f..2afcad3 100644 --- a/src/components/stakingPoolCard.tsx +++ b/src/components/stakingPoolCard.tsx @@ -1,17 +1,14 @@ -import { - formatPercentage, - formatUnitsToHumanReadable, -} from '@/misc/formatting'; -import { StakingPool } from '@/misc/stakingPoolsConfig'; -import { UserStakingPoolData } from '@/misc/walletsConfig'; -import { Tooltip } from 'antd'; -import Image from 'next/image'; +import { formatPercentage, formatUnitsToHumanReadable } from "@/misc/formatting" +import { StakingPool } from "@/misc/stakingPoolsConfig" +import { UserStakingPoolData } from "@/misc/walletsConfig" +import { Tooltip } from "antd" +import Image from "next/image" interface StakingPoolCardProps { - stakingPoolData: StakingPool; - userStakingPoolData?: UserStakingPoolData; - isStakingPoolSelected?: boolean; - onClick: () => void; + stakingPoolData: StakingPool + userStakingPoolData?: UserStakingPoolData + isStakingPoolSelected?: boolean + onClick: () => void } const StakingPoolCard: React.FC = ({ @@ -24,16 +21,14 @@ const StakingPoolCard: React.FC = ({
= ({
= 50 - ? 'text-red2' + ? "text-red2" : stakingPoolData.data.votingPower * 100 >= 30 - ? 'text-orange1' - : '' + ? "text-orange1" + : "" }`} > - VP{' '} - {( - stakingPoolData.data.votingPower * 100 - ).toPrecision(3)} + VP {(stakingPoolData.data.votingPower * 100).toPrecision(3)} %
) : ( @@ -84,14 +76,9 @@ const StakingPoolCard: React.FC = ({ )}
- Commission{' '} + Commission{" "} {stakingPoolData.data ? ( - <> - {Math.floor( - stakingPoolData.data.commission * 100 - )} - % - + <>{Math.floor(stakingPoolData.data.commission * 100)}% ) : ( )} @@ -115,7 +102,7 @@ const StakingPoolCard: React.FC = ({ )}
-
+
{userStakingPoolData && userStakingPoolData.stakingTokenAmount ? ( @@ -130,9 +117,7 @@ const StakingPoolCard: React.FC = ({ - )}
-
- {stakingPoolData.definition.tokenSymbol} -
+
{stakingPoolData.definition.tokenSymbol}
@@ -155,7 +140,7 @@ const StakingPoolCard: React.FC = ({
- ); -}; + ) +} -export default StakingPoolCard; +export default StakingPoolCard diff --git a/src/components/stakingPoolDetailsView.tsx b/src/components/stakingPoolDetailsView.tsx index b50a288..ff9d7dd 100644 --- a/src/components/stakingPoolDetailsView.tsx +++ b/src/components/stakingPoolDetailsView.tsx @@ -1,54 +1,46 @@ -import StakingCalculator from '@/components/stakingCalculator'; -import UnstakingCalculator from '@/components/unstakingCalculator'; -import WithdrawZilPanel from '@/components/withdrawUnstakedZilPanel'; -import { WalletConnector } from '@/contexts/walletConnector'; -import { getViemClient } from '@/misc/chainConfig'; -import { - formatPercentage, - formatUnitsToHumanReadable, -} from '@/misc/formatting'; -import { StakingPool } from '@/misc/stakingPoolsConfig'; +import StakingCalculator from "@/components/stakingCalculator" +import UnstakingCalculator from "@/components/unstakingCalculator" +import WithdrawZilPanel from "@/components/withdrawUnstakedZilPanel" +import { WalletConnector } from "@/contexts/walletConnector" +import { getViemClient } from "@/misc/chainConfig" +import { formatPercentage, formatUnitsToHumanReadable } from "@/misc/formatting" +import { StakingPool } from "@/misc/stakingPoolsConfig" import { UserStakingPoolData, UserUnstakingPoolData, -} from '@/misc/walletsConfig'; -import { Button } from 'antd'; -import { DateTime } from 'luxon'; -import { useState } from 'react'; -import { useWatchAsset } from 'wagmi'; -import { useWalletClient } from 'wagmi'; -import Plus from '../assets/svgs/plus.svg' -import Image from 'next/image'; +} from "@/misc/walletsConfig" +import { Button } from "antd" +import { DateTime } from "luxon" +import { useState } from "react" +import { useWatchAsset } from "wagmi" +import { useWalletClient } from "wagmi" +import Plus from "../assets/svgs/plus.svg" +import Image from "next/image" interface StakingPoolDetailsViewProps { - stakingPoolData: StakingPool; - userStakingPoolData?: UserStakingPoolData; - userUnstakingPoolData?: Array; - selectStakingPoolForStaking: (stakingPoolId: string) => void; + stakingPoolData: StakingPool + userStakingPoolData?: UserStakingPoolData + userUnstakingPoolData?: Array + selectStakingPoolForStaking: (stakingPoolId: string) => void } -const StakingPoolDetailsView: React.FC< - StakingPoolDetailsViewProps -> = ({ +const StakingPoolDetailsView: React.FC = ({ stakingPoolData, userStakingPoolData, userUnstakingPoolData, }) => { - const { zilAvailable } = WalletConnector.useContainer(); + const { zilAvailable } = WalletConnector.useContainer() - const [selectedPane, setSelectedPane] = useState('Stake'); + const [selectedPane, setSelectedPane] = useState("Stake") const colorInfoEntry = (title: string, value: string | null) => (
{value}
{title}
- ); + ) - const greyInfoEntry = ( - title: string, - value: string | JSX.Element | null - ) => ( + const greyInfoEntry = (title: string, value: string | JSX.Element | null) => (
{value ? (
@@ -57,38 +49,33 @@ const StakingPoolDetailsView: React.FC< ) : (
)} -
- {title} -
+
{title}
- ); + ) const pendingUnstakesValue = userUnstakingPoolData ?.filter((item) => item.availableAt > DateTime.now()) - .reduce((acc, item) => acc + item.zilAmount, 0n); + .reduce((acc, item) => acc + item.zilAmount, 0n) const availableToClaim = userUnstakingPoolData ?.filter((item) => item.availableAt <= DateTime.now()) - .reduce((acc, item) => acc + item.zilAmount, 0n); + .reduce((acc, item) => acc + item.zilAmount, 0n) const doesUserHoldAnyFundsInThisPool = !!( userStakingPoolData?.stakingTokenAmount || pendingUnstakesValue || availableToClaim - ); + ) const humanReadableStakingToken = (value: bigint) => - formatUnitsToHumanReadable( - value, - stakingPoolData.definition.tokenDecimals - ); + formatUnitsToHumanReadable(value, stakingPoolData.definition.tokenDecimals) + + const { watchAsset } = useWatchAsset() - const { watchAsset } = useWatchAsset(); - const handleClickAaddToken = () => watchAsset( { - type: 'ERC20', + type: "ERC20", options: { address: stakingPoolData.definition.tokenAddress, symbol: stakingPoolData.definition.tokenSymbol, @@ -97,13 +84,13 @@ const StakingPoolDetailsView: React.FC< }, { onSuccess: (data) => { - console.log('Asset watched successfully:', data); + console.log("Asset watched successfully:", data) }, onError: (error) => { - console.error('Failed to watch the asset:', error); + console.error("Failed to watch the asset:", error) }, } - ); + ) return (
- Add Token + /> + + Add Token +
@@ -141,62 +130,57 @@ const StakingPoolDetailsView: React.FC< {doesUserHoldAnyFundsInThisPool && (
{colorInfoEntry( - 'Available to stake', - `${formatUnitsToHumanReadable( - zilAvailable || 0n, - 18 - )} ZIL` + "Available to stake", + `${formatUnitsToHumanReadable(zilAvailable || 0n, 18)} ZIL` )} {colorInfoEntry( - 'Staked', + "Staked", `${humanReadableStakingToken( userStakingPoolData?.stakingTokenAmount || 0n )} ${stakingPoolData.definition.tokenSymbol}` )} {colorInfoEntry( - 'Unstake', + "Unstake", pendingUnstakesValue ? `${humanReadableStakingToken( pendingUnstakesValue )} ${stakingPoolData.definition.tokenSymbol}` - : '-' + : "-" )} {colorInfoEntry( - 'Available to claim', + "Available to claim", availableToClaim ? `${humanReadableStakingToken(availableToClaim)} ${ stakingPoolData.definition.tokenSymbol }` - : '-' + : "-" )}
)}
{greyInfoEntry( - 'Voting power', + "Voting power", stakingPoolData.data && formatPercentage(stakingPoolData.data.votingPower) )} {greyInfoEntry( - 'Total supply', + "Total supply", stakingPoolData.data && `${humanReadableStakingToken( stakingPoolData.data.tvl )} ${stakingPoolData.definition.tokenSymbol}` )} {greyInfoEntry( - 'Commission', + "Commission", stakingPoolData.data && formatPercentage(stakingPoolData.data.commission) )} {greyInfoEntry( - '', + "", stakingPoolData.data && ( <> 1 ZIL ~
- {stakingPoolData.data.zilToTokenRate.toPrecision( - 3 - )}{' '} + {stakingPoolData.data.zilToTokenRate.toPrecision(3)}{" "} {stakingPoolData.definition.tokenSymbol} ) @@ -204,13 +188,13 @@ const StakingPoolDetailsView: React.FC<
- {['Stake', 'Unstake', 'Claim'].map((pane) => ( + {["Stake", "Unstake", "Claim"].map((pane) => (
setSelectedPane(pane)} > @@ -219,9 +203,9 @@ const StakingPoolDetailsView: React.FC< ))}
- {selectedPane === 'Stake' ? ( + {selectedPane === "Stake" ? ( - ) : selectedPane === 'Unstake' ? ( + ) : selectedPane === "Unstake" ? ( ) : ( )}
- ); -}; + ) +} -export default StakingPoolDetailsView; +export default StakingPoolDetailsView diff --git a/src/components/stakingPoolsList.tsx b/src/components/stakingPoolsList.tsx index 4bf6aad..2a224ea 100644 --- a/src/components/stakingPoolsList.tsx +++ b/src/components/stakingPoolsList.tsx @@ -1,131 +1,134 @@ -import { StakingPoolsStorage } from '@/contexts/stakingPoolsStorage'; -import StakingPoolCard from './stakingPoolCard'; -import SortBtn from './sortBtn'; -import { useState } from 'react'; +import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage" +import StakingPoolCard from "./stakingPoolCard" +import SortBtn from "./sortBtn" +import { useState } from "react" const StakingPoolsList: React.FC = () => { const { combinedStakingPoolsData, selectStakingPoolForView, stakingPoolForView, - } = StakingPoolsStorage.useContainer(); + } = StakingPoolsStorage.useContainer() - const [sortCriteria, setSortCriteria] = useState< 'APR' | 'VP' | 'Commission' | null >(null); + const [sortCriteria, setSortCriteria] = useState< + "APR" | "VP" | "Commission" | null + >(null) - const [isAscending, setIsAscending] = useState(true); + const [isAscending, setIsAscending] = useState(true) // Function to get the value to sort by based on the criteria const getSortValue = (data: any, criteria: string | null) => { - if (!data) return 0; + if (!data) return 0 switch (criteria) { - case 'APR': - return data.apr || 0; - case 'VP': - return (data.votingPower || 0) * 100; - case 'Commission': - return (data.commission || 0) * 100; + case "APR": + return data.apr || 0 + case "VP": + return (data.votingPower || 0) * 100 + case "Commission": + return (data.commission || 0) * 100 default: - return 0; + return 0 } - }; + } // Sort the staking pools based on the selected criteria - const sortedStakingPoolsData = [...combinedStakingPoolsData].sort( - (a, b) => { - const aValue = getSortValue(a.stakingPool.data, sortCriteria); - const bValue = getSortValue(b.stakingPool.data, sortCriteria); - return isAscending ? aValue - bValue : bValue - aValue; - } - ); - - const handleSortClick = (criteria: 'APR' | 'VP' | 'Commission') => { + const sortedStakingPoolsData = [...combinedStakingPoolsData].sort((a, b) => { + const aValue = getSortValue(a.stakingPool.data, sortCriteria) + const bValue = getSortValue(b.stakingPool.data, sortCriteria) + return isAscending ? aValue - bValue : bValue - aValue + }) + + const handleSortClick = (criteria: "APR" | "VP" | "Commission") => { if (sortCriteria === criteria) { - setIsAscending(!isAscending); + setIsAscending(!isAscending) } else { - setSortCriteria(criteria); - setIsAscending(true); + setSortCriteria(criteria) + setIsAscending(true) } - }; + } const tabs = [ { - name: 'Liquid staking', + name: "Liquid staking", }, { - name: 'Normal Staking ', - }, - ]; + name: "Normal Staking ", + }, + ] - const [activeTab, setActiveTab] = useState(0); + const [activeTab, setActiveTab] = useState(0) return ( <> {/*
Liquid Validators
*/} - - {activeTab === 0 && ( -<> -
- handleSortClick('APR')} - /> - handleSortClick('VP')} - /> - handleSortClick('Commission')} - /> -
- -
- {sortedStakingPoolsData.map(({ stakingPool, userData }) => ( - - selectStakingPoolForView(stakingPool.definition.id) - } - /> + activeTab === index + ? "border-aqua1" + : "border-transparent" + }`} + onClick={() => { + setActiveTab(index) + }} + > + {tab.name} + ))} -
)} + + {activeTab === 0 && ( + <> +
+ handleSortClick("APR")} + /> + handleSortClick("VP")} + /> + handleSortClick("Commission")} + /> +
+ +
+ {sortedStakingPoolsData.map(({ stakingPool, userData }) => ( + + selectStakingPoolForView(stakingPool.definition.id) + } + /> + ))} +
+ + )} - ); -}; + ) +} -export default StakingPoolsList; +export default StakingPoolsList diff --git a/src/components/unstakingCalculator.tsx b/src/components/unstakingCalculator.tsx index 9ef317e..7933316 100644 --- a/src/components/unstakingCalculator.tsx +++ b/src/components/unstakingCalculator.tsx @@ -1,82 +1,79 @@ -import { StakingPoolsStorage } from '@/contexts/stakingPoolsStorage'; -import { useEffect, useState } from 'react'; -import { Button, Input, Tooltip } from 'antd'; +import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage" +import { useEffect, useState } from "react" +import { Button, Input, Tooltip } from "antd" import { formatPercentage, convertTokenToZil, formatUnitsToHumanReadable, getHumanFormDuration, -} from '@/misc/formatting'; -import { formatUnits, parseEther } from 'viem'; -import { StakingOperations } from '@/contexts/stakingOperations'; -import { DateTime } from 'luxon'; +} from "@/misc/formatting" +import { formatUnits, parseEther } from "viem" +import { StakingOperations } from "@/contexts/stakingOperations" +import { DateTime } from "luxon" const UnstakingCalculator: React.FC = () => { - const { stakingPoolForView } = StakingPoolsStorage.useContainer(); + const { stakingPoolForView } = StakingPoolsStorage.useContainer() const { unstake, isUnstakingInProgress, unstakeContractCallError } = - StakingOperations.useContainer(); + StakingOperations.useContainer() - const [zilToUnstake, setZilToUnstake] = useState('0'); + const [zilToUnstake, setZilToUnstake] = useState("0") const handleChange = (e: React.ChangeEvent) => { - const { value: inputValue } = e.target; - const reg = /^-?\d*(\.\d*)?$/; - if ( - reg.test(inputValue) || - inputValue === '' || - inputValue === '-' - ) { - setZilToUnstake(inputValue); + const { value: inputValue } = e.target + const reg = /^-?\d*(\.\d*)?$/ + if (reg.test(inputValue) || inputValue === "" || inputValue === "-") { + setZilToUnstake(inputValue) } - }; + } const handleFocus = () => { - if (zilToUnstake === '') onMaxClick(); - }; + if (zilToUnstake === "") onMaxClick() + } const handleBlur = () => { - let valueTemp = zilToUnstake; + let valueTemp = zilToUnstake if ( - zilToUnstake.charAt(zilToUnstake.length - 1) === '.' || - zilToUnstake === '-' + zilToUnstake.charAt(zilToUnstake.length - 1) === "." || + zilToUnstake === "-" ) { - valueTemp = zilToUnstake.slice(0, -1); + valueTemp = zilToUnstake.slice(0, -1) } - setZilToUnstake(valueTemp.replace(/0*(\d+)/, '$1')); - if (zilToUnstake === '') onMaxClick(); - }; + setZilToUnstake(valueTemp.replace(/0*(\d+)/, "$1")) + if (zilToUnstake === "") onMaxClick() + } useEffect(() => { - setZilToUnstake('1'); - }, [stakingPoolForView]); + setZilToUnstake("1") + }, [stakingPoolForView]) const stakedTokenAvailable = - stakingPoolForView?.userData?.staked?.stakingTokenAmount || 0; + stakingPoolForView?.userData?.staked?.stakingTokenAmount || 0 - const zilToUnstakeNumber = parseFloat(zilToUnstake); - const zilInWei = parseEther(zilToUnstake); + const zilToUnstakeNumber = parseFloat(zilToUnstake) + const zilInWei = parseEther(zilToUnstake) const zilToUnstakeOk = - !isNaN(zilToUnstakeNumber) && - zilToUnstakeNumber <= stakedTokenAvailable; + !isNaN(zilToUnstakeNumber) && zilToUnstakeNumber <= stakedTokenAvailable const canUnstake = stakingPoolForView?.stakingPool.data && zilToUnstakeNumber > 0 && - zilToUnstakeNumber <= stakedTokenAvailable; + zilToUnstakeNumber <= stakedTokenAvailable const onMaxClick = () => { setZilToUnstake( `${formatUnits( - stakingPoolForView?.userData?.staked?.stakingTokenAmount || - 0n, + stakingPoolForView?.userData?.staked?.stakingTokenAmount || 0n, stakingPoolForView?.stakingPool.definition.tokenDecimals || 18 )}` - ); - }; + ) + } - const unboudingPeriod = getHumanFormDuration(( - DateTime.now().plus({ minutes: stakingPoolForView?.stakingPool.definition.withdrawPeriodInMinutes || 0 }) - )); + const unboudingPeriod = getHumanFormDuration( + DateTime.now().plus({ + minutes: + stakingPoolForView?.stakingPool.definition.withdrawPeriodInMinutes || 0, + }) + ) return ( stakingPoolForView && ( @@ -85,7 +82,7 @@ const UnstakingCalculator: React.FC = () => {
{ onChange={handleChange} onBlur={handleBlur} onFocus={handleFocus} - prefix={ - stakingPoolForView.stakingPool.definition - .tokenSymbol - } - status={!zilToUnstakeOk ? 'error' : undefined} + prefix={stakingPoolForView.stakingPool.definition.tokenSymbol} + status={!zilToUnstakeOk ? "error" : undefined} />
@@ -107,8 +101,7 @@ const UnstakingCalculator: React.FC = () => { {formatUnitsToHumanReadable( convertTokenToZil( zilInWei, - stakingPoolForView.stakingPool.data - .zilToTokenRate + stakingPoolForView.stakingPool.data.zilToTokenRate ), 18 )} @@ -118,7 +111,7 @@ const UnstakingCalculator: React.FC = () => { )} ZIL - { unboudingPeriod } + {unboudingPeriod}
@@ -130,7 +123,7 @@ const UnstakingCalculator: React.FC = () => { @@ -140,23 +133,23 @@ const UnstakingCalculator: React.FC = () => {
- Commission Fee:{' '} + Commission Fee:{" "} {stakingPoolForView!.stakingPool.data ? ( <> - {' '} + {" "} {formatPercentage( stakingPoolForView!.stakingPool.data.commission - )}{' '} + )}{" "} ) : (
)}
- Max transaction cost: {zilToUnstake ? '0.01' : '0'}$ + Max transaction cost: {zilToUnstake ? "0.01" : "0"}$
- Unbonding Period: { unboudingPeriod } + Unbonding Period: {unboudingPeriod}
@@ -165,22 +158,16 @@ const UnstakingCalculator: React.FC = () => {
{stakingPoolForView!.stakingPool.data ? ( <> - 1{' '} - { - stakingPoolForView.stakingPool.definition - .tokenSymbol - }{' '} + 1 {stakingPoolForView.stakingPool.definition.tokenSymbol}{" "} = ~ {formatUnitsToHumanReadable( convertTokenToZil( - parseEther('1'), - stakingPoolForView.stakingPool.data - .zilToTokenRate + parseEther("1"), + stakingPoolForView.stakingPool.data.zilToTokenRate ), 18 )} - - + ) : (
)} @@ -188,15 +175,19 @@ const UnstakingCalculator: React.FC = () => {
- - APR - + + APR + {stakingPoolForView!.stakingPool.data ? ( <> ~ - {formatPercentage( - stakingPoolForView!.stakingPool.data.apr - )} + {formatPercentage(stakingPoolForView!.stakingPool.data.apr)} ) : (
@@ -230,7 +221,7 @@ const UnstakingCalculator: React.FC = () => {
) - ); -}; + ) +} -export default UnstakingCalculator; +export default UnstakingCalculator diff --git a/src/components/withdrawUnstakedZilPanel.tsx b/src/components/withdrawUnstakedZilPanel.tsx index 00c49d8..a87754f 100644 --- a/src/components/withdrawUnstakedZilPanel.tsx +++ b/src/components/withdrawUnstakedZilPanel.tsx @@ -1,20 +1,20 @@ -import { AppConfigStorage } from '@/contexts/appConfigStorage'; -import { StakingOperations } from '@/contexts/stakingOperations'; +import { AppConfigStorage } from "@/contexts/appConfigStorage" +import { StakingOperations } from "@/contexts/stakingOperations" import { formatAddress, getHumanFormDuration, getTxExplorerUrl, -} from '@/misc/formatting'; -import { StakingPool } from '@/misc/stakingPoolsConfig'; -import { UserUnstakingPoolData } from '@/misc/walletsConfig'; -import { Button } from 'antd'; -import { DateTime } from 'luxon'; -import Link from 'next/link'; -import { formatUnits } from 'viem'; +} from "@/misc/formatting" +import { StakingPool } from "@/misc/stakingPoolsConfig" +import { UserUnstakingPoolData } from "@/misc/walletsConfig" +import { Button } from "antd" +import { DateTime } from "luxon" +import Link from "next/link" +import { formatUnits } from "viem" interface WithdrawZilPanelProps { - stakingPoolData: StakingPool; - userUnstakingPoolData?: Array; + stakingPoolData: StakingPool + userUnstakingPoolData?: Array } const WithdrawZilPanel: React.FC = ({ @@ -22,23 +22,23 @@ const WithdrawZilPanel: React.FC = ({ stakingPoolData, }) => { const { claim, isClaimingInProgress, claimCallTxHash } = - StakingOperations.useContainer(); + StakingOperations.useContainer() - const { appConfig } = AppConfigStorage.useContainer(); + const { appConfig } = AppConfigStorage.useContainer() const pendingUnstake = userUnstakingPoolData ?.filter((claim) => claim.availableAt > DateTime.now()) .toSorted( (claimA, claimB) => claimA.availableAt.diff(claimB.availableAt).milliseconds - ); + ) const availableUnstake = userUnstakingPoolData ?.filter((claim) => claim.availableAt <= DateTime.now()) .toSorted( (claimA, claimB) => claimA.availableAt.diff(claimB.availableAt).milliseconds - ); + ) return (
@@ -47,10 +47,7 @@ const WithdrawZilPanel: React.FC = ({ Last staking transaction: {formatAddress(claimCallTxHash)} @@ -60,57 +57,50 @@ const WithdrawZilPanel: React.FC = ({ {!!availableUnstake?.length ? ( availableUnstake.map((item, claimIdx) => ( -
{stakingPoolData.data ? ( -
-
- {parseFloat( - formatUnits(item.zilAmount, 18) - ).toFixed(3)}{' '} - ZIL -
-
avZIL
- -
+
+
+ {parseFloat(formatUnits(item.zilAmount, 18)).toFixed(3)} ZIL +
+
avZIL
+
) : (
)} -
+
-
+
)) ) : !!pendingUnstake?.length ? (
-
- Next available reward
-
- - {stakingPoolData.data ? ( -
- {parseFloat( - formatUnits(pendingUnstake[0].zilAmount, 18) - ).toFixed(3)}{' '} - ZIL -
- ) : ( -
- )} +
Next available reward
+
+ {stakingPoolData.data ? (
- {getHumanFormDuration(pendingUnstake[0].availableAt)} + {parseFloat( + formatUnits(pendingUnstake[0].zilAmount, 18) + ).toFixed(3)}{" "} + ZIL
-
-
+ ) : ( +
+ )} +
{getHumanFormDuration(pendingUnstake[0].availableAt)}
+
+
) : (
No available Claims @@ -119,31 +109,32 @@ const WithdrawZilPanel: React.FC = ({ {!!pendingUnstake?.length && (
-
- Pending Requests -
+
Pending Requests
{pendingUnstake?.map((claim, claimIdx) => ( -
+
{stakingPoolData.data ? ( -
-
- {parseFloat( - formatUnits(claim.zilAmount, 18) - ).toFixed(3)}{' '} - ZIL -
+
+
+ {parseFloat(formatUnits(claim.zilAmount, 18)).toFixed(3)}{" "} + ZIL +
) : (
)} -
{getHumanFormDuration(claim.availableAt)}
+
+ {getHumanFormDuration(claim.availableAt)} +
))}
)}
- ); -}; + ) +} -export default WithdrawZilPanel; +export default WithdrawZilPanel diff --git a/src/components/withdrawZilView.tsx b/src/components/withdrawZilView.tsx index ab50b5a..4072221 100644 --- a/src/components/withdrawZilView.tsx +++ b/src/components/withdrawZilView.tsx @@ -1,130 +1,135 @@ -import { StakingOperations } from "@/contexts/stakingOperations"; -import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage"; -import { convertTokenToZil, formatUnitsToHumanReadable, getHumanFormDuration } from "@/misc/formatting"; -import { Button } from "antd"; -import Image from 'next/image'; +import { StakingOperations } from "@/contexts/stakingOperations" +import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage" +import { + convertTokenToZil, + formatUnitsToHumanReadable, + getHumanFormDuration, +} from "@/misc/formatting" +import { Button } from "antd" +import Image from "next/image" const WithdrawZilView: React.FC = () => { const { availableForUnstaking, pendingUnstaking, selectStakingPoolForView, - isUnstakingDataLoading - } = StakingPoolsStorage.useContainer(); + isUnstakingDataLoading, + } = StakingPoolsStorage.useContainer() - const { - claim, - } = StakingOperations.useContainer(); + const { claim } = StakingOperations.useContainer() const unstakingItems = [ ...availableForUnstaking.map((item) => ({ ...item, available: true })), - ...pendingUnstaking.map((item) => ({ ...item, available: false })) + ...pendingUnstaking.map((item) => ({ ...item, available: false })), ] return ( -
+ flex flex-col gap-2" + >

Staking Portal Claims

- Below are withdrawal claims waiting for you + Below are withdrawal claims waiting for you

- { - unstakingItems.length > 0 ? ( - -
- { - unstakingItems.map((item, claimIdx) => ( -
-
-
- {`${item.stakingPool.definition.name} -
- {item.stakingPool.definition.name} -
-
-
-
- { - item.stakingPool.data ? <> - { - formatUnitsToHumanReadable( - convertTokenToZil(item.unstakeInfo.zilAmount, item.stakingPool.data!.zilToTokenRate), - 18 - ) - } ZIL - - : - <> -
- - } - -
-
{item.unstakeInfo.zilAmount} {item.stakingPool.definition.tokenSymbol}
-
+ " + > + {unstakingItems.map((item, claimIdx) => ( +
+
+
+ {`${item.stakingPool.definition.name} +
+ {item.stakingPool.definition.name}
-
-
- -
-
- -
+
+
+
+ {item.stakingPool.data ? ( + <> + {formatUnitsToHumanReadable( + convertTokenToZil( + item.unstakeInfo.zilAmount, + item.stakingPool.data!.zilToTokenRate + ), + 18 + )}{" "} + ZIL + + ) : ( + <> +
+ + )}
- +
+ {item.unstakeInfo.zilAmount}{" "} + {item.stakingPool.definition.tokenSymbol} +
+
+
+
+
+
- )) - } -
- ) : ( -
- { - isUnstakingDataLoading ? ( -
- ) : ( - - Here is the testing ground for the new Zilliqa portal. - Explore and give us you feedback. - - ) - } -
- ) - } +
+ +
+
+
+ ))} +
+ ) : ( +
+ {isUnstakingDataLoading ? ( +
+ ) : ( + + Here is the testing ground for the new Zilliqa portal. Explore and + give us you feedback. + + )} +
+ )}
) - } -export default WithdrawZilView; \ No newline at end of file +export default WithdrawZilView diff --git a/src/contexts/appConfigStorage.tsx b/src/contexts/appConfigStorage.tsx index 8e35ac7..01cac41 100644 --- a/src/contexts/appConfigStorage.tsx +++ b/src/contexts/appConfigStorage.tsx @@ -1,12 +1,12 @@ -"use client"; +"use client" -import { AppConfig } from "@/pages/api/config"; -import { createContainer } from "./context"; +import { AppConfig } from "@/pages/api/config" +import { createContainer } from "./context" const useAppConfigStorage = (initialState?: { appConfig: AppConfig }) => { return { - appConfig: initialState!.appConfig - }; -}; + appConfig: initialState!.appConfig, + } +} -export const AppConfigStorage = createContainer(useAppConfigStorage); +export const AppConfigStorage = createContainer(useAppConfigStorage) diff --git a/src/contexts/context.tsx b/src/contexts/context.tsx index 432eb30..c6b0e87 100644 --- a/src/contexts/context.tsx +++ b/src/contexts/context.tsx @@ -1,4 +1,4 @@ -"use client"; +"use client" /** * This file is a copy of https://github.com/jamiebuilds/unstated-next/blob/master/src/unstated-next.tsx * The reason it is the copy is that the project is no longer maintained and we are using new version of React @@ -6,49 +6,49 @@ * In theory, this should land in the "@zilliqa/zilliqa-ui" but then you need to set up jsx transpilation * if you are reading that and have time to do it, please do! */ -import React from "react"; +import React from "react" -const EMPTY: unique symbol = Symbol(); +const EMPTY: unique symbol = Symbol() export interface ContainerProviderProps { - initialState?: State; - children: React.ReactNode; + initialState?: State + children: React.ReactNode } export interface Container { - Provider: React.ComponentType>; - useContainer: () => Value; - MockProvider: React.ComponentType>>; + Provider: React.ComponentType> + useContainer: () => Value + MockProvider: React.ComponentType>> } export function createContainer( useHook: (initialState?: State) => Value, - mockkContextCreator?: (overrides: Partial) => Value, + mockkContextCreator?: (overrides: Partial) => Value ): Container { - let Context = React.createContext(EMPTY); + let Context = React.createContext(EMPTY) function Provider(props: ContainerProviderProps) { - let value = useHook(props.initialState); - return {props.children}; + let value = useHook(props.initialState) + return {props.children} } function MockProvider(props: ContainerProviderProps>) { if (!mockkContextCreator) { throw new Error( - "MockProvider can only be used when mockkContextCreator is provided", - ); + "MockProvider can only be used when mockkContextCreator is provided" + ) } - let value = mockkContextCreator(props.initialState || {}); - return {props.children}; + let value = mockkContextCreator(props.initialState || {}) + return {props.children} } function useContainer(): Value { - let value = React.useContext(Context); + let value = React.useContext(Context) if (value === EMPTY) { - throw new Error("Component must be wrapped with "); + throw new Error("Component must be wrapped with ") } - return value; + return value } - return { Provider, useContainer, MockProvider }; + return { Provider, useContainer, MockProvider } } diff --git a/src/contexts/stakingOperations.tsx b/src/contexts/stakingOperations.tsx index 5ec74e3..473af99 100644 --- a/src/contexts/stakingOperations.tsx +++ b/src/contexts/stakingOperations.tsx @@ -1,39 +1,38 @@ -import { notification } from "antd"; -import { useEffect, useState } from "react"; -import { useWaitForTransactionReceipt } from "wagmi"; -import { createContainer } from "./context"; -import { WalletConnector } from "./walletConnector"; -import { StakingPoolsStorage } from "./stakingPoolsStorage"; -import { Address } from "viem"; -import { delegatorAbi } from "@/misc/stakingAbis"; -import { writeContract } from "wagmi/actions"; -import { useConfig } from 'wagmi' +import { notification } from "antd" +import { useEffect, useState } from "react" +import { useWaitForTransactionReceipt } from "wagmi" +import { createContainer } from "./context" +import { WalletConnector } from "./walletConnector" +import { StakingPoolsStorage } from "./stakingPoolsStorage" +import { Address } from "viem" +import { delegatorAbi } from "@/misc/stakingAbis" +import { writeContract } from "wagmi/actions" +import { useConfig } from "wagmi" const useStakingOperations = () => { + const { isDummyWalletConnected, updateWalletBalance } = + WalletConnector.useContainer() - const { - isDummyWalletConnected, - updateWalletBalance, - } = WalletConnector.useContainer(); - - const { - reloadUserStakingPoolsData, - stakingPoolForView, - } = StakingPoolsStorage.useContainer(); + const { reloadUserStakingPoolsData, stakingPoolForView } = + StakingPoolsStorage.useContainer() const wagmiConfig = useConfig() - const [isDummyWalletPopupOpen, setIsDummyWalletPopupOpen] = useState(false); - const [dummyWalletPopupContent, setDummyWalletPopupContent] = useState(null); + const [isDummyWalletPopupOpen, setIsDummyWalletPopupOpen] = useState(false) + const [dummyWalletPopupContent, setDummyWalletPopupContent] = useState< + string | null + >(null) - const stakingPoolId = stakingPoolForView?.stakingPool.definition.id; + const stakingPoolId = stakingPoolForView?.stakingPool.definition.id /** * STAKING */ - const [stakingCallTxHash, setStakingCallTxHash] = useState
(undefined); - const [preparingStakingTx, setPreparingStakingTx] = useState(false); + const [stakingCallTxHash, setStakingCallTxHash] = useState< + Address | undefined + >(undefined) + const [preparingStakingTx, setPreparingStakingTx] = useState(false) const { isLoading: submittingStakingTx, @@ -44,67 +43,64 @@ const useStakingOperations = () => { }) const stake = (delegatorAddress: string, weiToStake: bigint) => { - setPreparingStakingTx(true); + setPreparingStakingTx(true) if (isDummyWalletConnected) { - setDummyWalletPopupContent(`Now User gonna approve the wallet transaction for staking ZIL`); - setIsDummyWalletPopupOpen(true); - setStakingCallTxHash("0x1234567890234567890234567890234567890" as Address); - setPreparingStakingTx(false); + setDummyWalletPopupContent( + "Now User gonna approve the wallet transaction for staking ZIL" + ) + setIsDummyWalletPopupOpen(true) + setStakingCallTxHash("0x1234567890234567890234567890234567890" as Address) + setPreparingStakingTx(false) } else { - writeContract( - wagmiConfig, - { - address: delegatorAddress as Address, - abi: delegatorAbi, - functionName: 'stake', - args: [], - value: weiToStake - } - ).then( - (txHash) => { - setStakingCallTxHash(txHash); - } - ).catch( - (error) => { + writeContract(wagmiConfig, { + address: delegatorAddress as Address, + abi: delegatorAbi, + functionName: "stake", + args: [], + value: weiToStake, + }) + .then((txHash) => { + setStakingCallTxHash(txHash) + }) + .catch((error) => { notification.error({ message: "Staking failed", - description: error?.message || "There was an error while staking ZIL", - placement: "topRight" - }); - } - ).finally( - () => setPreparingStakingTx(false) - ) + description: + error?.message || "There was an error while staking ZIL", + placement: "topRight", + }) + }) + .finally(() => setPreparingStakingTx(false)) } } - useEffect( - () => { - if (stakingCallReceiptStatus === "success") { - notification.success({ - message: "Staking successful", - description: `You have successfully staked ZIL`, - placement: "topRight" - }); - reloadUserStakingPoolsData(); - updateWalletBalance(); - } else if (stakingCallReceiptStatus === "error") { - notification.error({ - message: "Staking failed", - description: `There was an error while staking ZIL`, - placement: "topRight" - }); - } - }, [stakingCallReceiptStatus] - ) + useEffect(() => { + if (stakingCallReceiptStatus === "success") { + notification.success({ + message: "Staking successful", + description: "You have successfully staked ZIL", + placement: "topRight", + }) + reloadUserStakingPoolsData() + updateWalletBalance() + } else if (stakingCallReceiptStatus === "error") { + notification.error({ + message: "Staking failed", + description: "There was an error while staking ZIL", + placement: "topRight", + }) + } + }, [stakingCallReceiptStatus]) /** * UNSTAKING */ - const [unstakingCallTxHash, setUnstakingCallTxHash] = useState
(undefined); - const [preparingUnstakingTx, setPreparingUnstakingTx] = useState(false); + const [unstakingCallTxHash, setUnstakingCallTxHash] = useState< + Address | undefined + >(undefined) + const [preparingUnstakingTx, setPreparingUnstakingTx] = useState(false) const { isLoading: submittingUnstakingTx, @@ -115,65 +111,64 @@ const useStakingOperations = () => { }) const unstake = (delegatorAddress: string, tokensToUnstake: bigint) => { - setPreparingUnstakingTx(true); + setPreparingUnstakingTx(true) if (isDummyWalletConnected) { - setDummyWalletPopupContent(`Now User gonna approve the wallet transaction for unstaking ${tokensToUnstake} staked tokens`); - setIsDummyWalletPopupOpen(true); - setUnstakingCallTxHash("0x1234567890234567890234567890234567890" as Address); - setPreparingUnstakingTx(false); + setDummyWalletPopupContent( + `Now User gonna approve the wallet transaction for unstaking ${tokensToUnstake} staked tokens` + ) + setIsDummyWalletPopupOpen(true) + setUnstakingCallTxHash( + "0x1234567890234567890234567890234567890" as Address + ) + setPreparingUnstakingTx(false) } else { - writeContract( - wagmiConfig, - { - address: delegatorAddress as Address, - abi: delegatorAbi, - functionName: 'unstake', - args: [tokensToUnstake] - } - ).then( - (txHash) => { - setUnstakingCallTxHash(txHash); - } - ).catch( - (error) => { + writeContract(wagmiConfig, { + address: delegatorAddress as Address, + abi: delegatorAbi, + functionName: "unstake", + args: [tokensToUnstake], + }) + .then((txHash) => { + setUnstakingCallTxHash(txHash) + }) + .catch((error) => { notification.error({ message: "Unstaking failed", - description: error?.message || "There was an error while unstaking ZIL", - placement: "topRight" - }); - } - ).finally( - () => setPreparingUnstakingTx(false) - ) + description: + error?.message || "There was an error while unstaking ZIL", + placement: "topRight", + }) + }) + .finally(() => setPreparingUnstakingTx(false)) } } - useEffect( - () => { - if (unstakeCallReceiptStatus === "success") { - notification.success({ - message: "Unstaking successful", - description: `You have successfully unstaked ZIL`, - placement: "topRight" - }); - reloadUserStakingPoolsData(); - updateWalletBalance(); - } else if (unstakeCallReceiptStatus === "error") { - notification.error({ - message: "Unstaking failed", - description: `There was an error while unstaking ZIL`, - placement: "topRight" - }); - } - }, [unstakeCallReceiptStatus] - ) + useEffect(() => { + if (unstakeCallReceiptStatus === "success") { + notification.success({ + message: "Unstaking successful", + description: "You have successfully unstaked ZIL", + placement: "topRight", + }) + reloadUserStakingPoolsData() + updateWalletBalance() + } else if (unstakeCallReceiptStatus === "error") { + notification.error({ + message: "Unstaking failed", + description: "There was an error while unstaking ZIL", + placement: "topRight", + }) + } + }, [unstakeCallReceiptStatus]) /** * CLAIMING */ - const [claimCallTxHash, setClaimCallTxHash] = useState
(undefined); - const [preparingClaimTx, setPreparingClaimTx] = useState(false); + const [claimCallTxHash, setClaimCallTxHash] = useState
( + undefined + ) + const [preparingClaimTx, setPreparingClaimTx] = useState(false) const { isLoading: submittingClaimTx, @@ -184,58 +179,53 @@ const useStakingOperations = () => { }) const claim = (delegatorAddress: string) => { - setPreparingClaimTx(true); + setPreparingClaimTx(true) if (isDummyWalletConnected) { - setDummyWalletPopupContent(`Now User gonna approve the wallet transaction for withdrawing/claiming ZIL`); - setIsDummyWalletPopupOpen(true); - setClaimCallTxHash("0x1234567890234567890234567890234567890" as Address); - setPreparingClaimTx(false); + setDummyWalletPopupContent( + "Now User gonna approve the wallet transaction for withdrawing/claiming ZIL" + ) + setIsDummyWalletPopupOpen(true) + setClaimCallTxHash("0x1234567890234567890234567890234567890" as Address) + setPreparingClaimTx(false) } else { - writeContract( - wagmiConfig, - { - address: delegatorAddress as Address, - abi: delegatorAbi, - functionName: 'claim', - args: [] - } - ).then( - (txHash) => { - setClaimCallTxHash(txHash); - } - ).catch( - (error) => { + writeContract(wagmiConfig, { + address: delegatorAddress as Address, + abi: delegatorAbi, + functionName: "claim", + args: [], + }) + .then((txHash) => { + setClaimCallTxHash(txHash) + }) + .catch((error) => { notification.error({ message: "Claiming failed", - description: error?.message || "There was an error while claiming ZIL", - placement: "topRight" - }); - } - ).finally( - () => setPreparingClaimTx(false) - ) + description: + error?.message || "There was an error while claiming ZIL", + placement: "topRight", + }) + }) + .finally(() => setPreparingClaimTx(false)) } } - useEffect( - () => { - if (claimCallReceiptStatus === "success") { - notification.success({ - message: "Claiming successful", - description: `You have successfully claimed ZIL`, - placement: "topRight" - }); - reloadUserStakingPoolsData(); - updateWalletBalance(); - } else if (claimCallReceiptStatus === "error") { - notification.error({ - message: "Claiming failed", - description: `There was an error while claiming ZIL`, - placement: "topRight" - }); - } - }, [claimCallReceiptStatus] - ) + useEffect(() => { + if (claimCallReceiptStatus === "success") { + notification.success({ + message: "Claiming successful", + description: "You have successfully claimed ZIL", + placement: "topRight", + }) + reloadUserStakingPoolsData() + updateWalletBalance() + } else if (claimCallReceiptStatus === "error") { + notification.error({ + message: "Claiming failed", + description: "There was an error while claiming ZIL", + placement: "topRight", + }) + } + }, [claimCallReceiptStatus]) /** * OTHER @@ -243,9 +233,9 @@ const useStakingOperations = () => { useEffect( function clearStateOnDelegatorChange() { - setStakingCallTxHash(undefined); - setUnstakingCallTxHash(undefined); - setClaimCallTxHash(undefined); + setStakingCallTxHash(undefined) + setUnstakingCallTxHash(undefined) + setClaimCallTxHash(undefined) }, [stakingPoolId] ) @@ -270,7 +260,6 @@ const useStakingOperations = () => { claimCallTxHash, claimContractCallError, } +} -}; - -export const StakingOperations = createContainer(useStakingOperations); \ No newline at end of file +export const StakingOperations = createContainer(useStakingOperations) diff --git a/src/contexts/stakingPoolsStorage.tsx b/src/contexts/stakingPoolsStorage.tsx index 8779a89..f6ee606 100644 --- a/src/contexts/stakingPoolsStorage.tsx +++ b/src/contexts/stakingPoolsStorage.tsx @@ -1,66 +1,86 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { createContainer } from "./context"; -import { WalletConnector } from "./walletConnector"; -import { DateTime } from "luxon"; -import { StakingPool, stakingPoolsConfigForChainId } from "@/misc/stakingPoolsConfig"; -import { getWalletStakingData, getWalletUnstakingData, UserStakingPoolData, UserUnstakingPoolData } from "@/misc/walletsConfig"; -import { AppConfigStorage } from "./appConfigStorage"; +"use client" + +import { useEffect, useState } from "react" +import { createContainer } from "./context" +import { WalletConnector } from "./walletConnector" +import { DateTime } from "luxon" +import { + StakingPool, + stakingPoolsConfigForChainId, +} from "@/misc/stakingPoolsConfig" +import { + getWalletStakingData, + getWalletUnstakingData, + UserStakingPoolData, + UserUnstakingPoolData, +} from "@/misc/walletsConfig" +import { AppConfigStorage } from "./appConfigStorage" const useStakingPoolsStorage = () => { - const { - walletAddress, - } = WalletConnector.useContainer(); + const { walletAddress } = WalletConnector.useContainer() - const { - appConfig - } = AppConfigStorage.useContainer(); + const { appConfig } = AppConfigStorage.useContainer() - const [availableStakingPoolsData, setAvailableStakingPoolsData] = useState([]); + const [availableStakingPoolsData, setAvailableStakingPoolsData] = useState< + StakingPool[] + >([]) - const [userStakingPoolsData, setUserStakingPoolsData] = useState([]); - const [userUnstakesData, setUserUnstakesData] = useState([]); + const [userStakingPoolsData, setUserStakingPoolsData] = useState< + UserStakingPoolData[] + >([]) + const [userUnstakesData, setUserUnstakesData] = useState< + UserUnstakingPoolData[] + >([]) - const [stakingPoolForView, setSelectedStakingPool] = useState(null); + const [stakingPoolForView, setSelectedStakingPool] = + useState(null) - const [stakingPoolForStaking, setStakingPoolForStaking] = useState(null); - const [stakingPoolForUnstaking, setStakingPoolForUnstaking] = useState(null); + const [stakingPoolForStaking, setStakingPoolForStaking] = + useState(null) + const [stakingPoolForUnstaking, setStakingPoolForUnstaking] = + useState(null) - const [isUnstakingDataLoading, setIsUnstakingDataLoading] = useState(false); + const [isUnstakingDataLoading, setIsUnstakingDataLoading] = useState(false) const reloadUserStakingPoolsData = () => { if (!walletAddress) { - setUserStakingPoolsData([]); + setUserStakingPoolsData([]) return } - getWalletStakingData(walletAddress, appConfig!.chainId).then(setUserStakingPoolsData).catch(console.error); - setIsUnstakingDataLoading(true); + getWalletStakingData(walletAddress, appConfig!.chainId) + .then(setUserStakingPoolsData) + .catch(console.error) + setIsUnstakingDataLoading(true) getWalletUnstakingData(walletAddress, appConfig!.chainId) .then(setUserUnstakesData) .catch(console.error) - .finally(() => setIsUnstakingDataLoading(false)); + .finally(() => setIsUnstakingDataLoading(false)) } useEffect( function triggerUserDataLoadingOnWalletConnect() { - reloadUserStakingPoolsData(); + reloadUserStakingPoolsData() }, [walletAddress] - ); + ) - useEffect( - function populateStakingPoolsDefinitionsAndTriggerDataLoading () { - const stakingPoolsConfig = stakingPoolsConfigForChainId[appConfig.chainId]; + useEffect(function populateStakingPoolsDefinitionsAndTriggerDataLoading() { + const stakingPoolsConfig = stakingPoolsConfigForChainId[appConfig.chainId] - setAvailableStakingPoolsData(stakingPoolsConfig.map((configEntry) => ({ + setAvailableStakingPoolsData( + stakingPoolsConfig.map((configEntry) => ({ definition: configEntry.definition, data: null, - }))); + })) + ) - Promise.all(stakingPoolsConfig.map(async (config) => { - const data = await config.delegatorDataProvider(config.definition, appConfig.chainId); + Promise.all( + stakingPoolsConfig.map(async (config) => { + const data = await config.delegatorDataProvider( + config.definition, + appConfig.chainId + ) setAvailableStakingPoolsData((prev) => { const updated = prev.map((entry) => { @@ -68,122 +88,159 @@ const useStakingPoolsStorage = () => { return { ...entry, data, - }; + } } - return entry; - }); + return entry + }) - return updated; - } - ) - })); - }, []); // eslint-disable-line react-hooks/exhaustive-deps + return updated + }) + }) + ) + }, []) // eslint-disable-line react-hooks/exhaustive-deps useEffect( - function updateStakingForViewOnStakingPoolsDataChange () { + function updateStakingForViewOnStakingPoolsDataChange() { if (stakingPoolForView) { - const updatedStakingPool = availableStakingPoolsData.find((pool) => pool.definition.id === stakingPoolForView.definition.id); + const updatedStakingPool = availableStakingPoolsData.find( + (pool) => pool.definition.id === stakingPoolForView.definition.id + ) if (updatedStakingPool) { - setSelectedStakingPool(updatedStakingPool); + setSelectedStakingPool(updatedStakingPool) } } }, [availableStakingPoolsData] - ); + ) const selectStakingPoolForView = (stakingPoolId: string | null) => { if (!stakingPoolId) { - setSelectedStakingPool(null); - return; + setSelectedStakingPool(null) + return } - const selectedPool = availableStakingPoolsData.find((pool) => pool.definition.id === stakingPoolId); + const selectedPool = availableStakingPoolsData.find( + (pool) => pool.definition.id === stakingPoolId + ) if (selectedPool) { if (selectedPool?.definition.id === stakingPoolForView?.definition.id) { - setSelectedStakingPool(null); + setSelectedStakingPool(null) } else { - setSelectedStakingPool(selectedPool); + setSelectedStakingPool(selectedPool) } } - setStakingPoolForStaking(null); + setStakingPoolForStaking(null) } const selectStakingPoolForStaking = (stakingPoolId: string | null) => { if (!stakingPoolId) { - setStakingPoolForStaking(null); - return; + setStakingPoolForStaking(null) + return } - - const selectedPool = availableStakingPoolsData.find((pool) => pool.definition.id === stakingPoolId); + + const selectedPool = availableStakingPoolsData.find( + (pool) => pool.definition.id === stakingPoolId + ) if (selectedPool) { - setStakingPoolForStaking(selectedPool); + setStakingPoolForStaking(selectedPool) } } const selectStakingPoolForUnstaking = (stakingPoolId: string | null) => { if (!stakingPoolId) { - setStakingPoolForUnstaking(null); - return; + setStakingPoolForUnstaking(null) + return } - - const selectedPool = availableStakingPoolsData.find((pool) => pool.definition.id === stakingPoolId); + + const selectedPool = availableStakingPoolsData.find( + (pool) => pool.definition.id === stakingPoolId + ) if (selectedPool) { - setStakingPoolForUnstaking(selectedPool); + setStakingPoolForUnstaking(selectedPool) } } - const combinedStakingPoolsData = availableStakingPoolsData.map((stakingPool) => { - const userStakingPoolData = userStakingPoolsData.find((userPool) => userPool.address === stakingPool.definition.address); + const combinedStakingPoolsData = availableStakingPoolsData + .map((stakingPool) => { + const userStakingPoolData = userStakingPoolsData.find( + (userPool) => userPool.address === stakingPool.definition.address + ) - return { - stakingPool, - userData: userStakingPoolData, - } - }).toSorted( - (a, b) => { - const diff = (b.userData?.stakingTokenAmount || 0n) - (a.userData?.stakingTokenAmount || 0n); + return { + stakingPool, + userData: userStakingPoolData, + } + }) + .toSorted((a, b) => { + const diff = + (b.userData?.stakingTokenAmount || 0n) - + (a.userData?.stakingTokenAmount || 0n) if (diff === 0n) { - return a.stakingPool.definition.name.localeCompare(b.stakingPool.definition.name); + return a.stakingPool.definition.name.localeCompare( + b.stakingPool.definition.name + ) } - return diff > 0 ? 1 : -1; - } - ); - - const combinedSelectedStakingPoolForViewData = stakingPoolForView ? { - stakingPool: stakingPoolForView, - userData: { - staked: userStakingPoolsData.find((userPoolData) => userPoolData.address === stakingPoolForView.definition.address), - unstaked: userUnstakesData.filter((userPoolData) => userPoolData.address === stakingPoolForView.definition.address) - } - } : null; - - const combinedSelectedStakingPoolForStakingData = stakingPoolForStaking ? { - stakingPool: stakingPoolForStaking, - userData: userStakingPoolsData.find((userPool) => userPool.address === stakingPoolForStaking.definition.address), - } : null; + return diff > 0 ? 1 : -1 + }) - const combinedSelectedStakingPoolForUnstakingData = stakingPoolForUnstaking ? { - stakingPool: stakingPoolForUnstaking, - userData: userStakingPoolsData.find((userPool) => userPool.address === stakingPoolForUnstaking.definition.address), - } : null; + const combinedSelectedStakingPoolForViewData = stakingPoolForView + ? { + stakingPool: stakingPoolForView, + userData: { + staked: userStakingPoolsData.find( + (userPoolData) => + userPoolData.address === stakingPoolForView.definition.address + ), + unstaked: userUnstakesData.filter( + (userPoolData) => + userPoolData.address === stakingPoolForView.definition.address + ), + }, + } + : null + + const combinedSelectedStakingPoolForStakingData = stakingPoolForStaking + ? { + stakingPool: stakingPoolForStaking, + userData: userStakingPoolsData.find( + (userPool) => + userPool.address === stakingPoolForStaking.definition.address + ), + } + : null + + const combinedSelectedStakingPoolForUnstakingData = stakingPoolForUnstaking + ? { + stakingPool: stakingPoolForUnstaking, + userData: userStakingPoolsData.find( + (userPool) => + userPool.address === stakingPoolForUnstaking.definition.address + ), + } + : null - const combinedUserUnstakesData = userUnstakesData?.map( - (unstakeInfo) => ({ + const combinedUserUnstakesData = + userUnstakesData?.map((unstakeInfo) => ({ unstakeInfo, - stakingPool: availableStakingPoolsData.find((pool) => pool.definition.address === unstakeInfo.address)!, - }) - ) || []; - - const availableForUnstaking = combinedUserUnstakesData.filter((unstakeData) => unstakeData.unstakeInfo.availableAt <= DateTime.now()); - const pendingUnstaking = combinedUserUnstakesData.filter((unstakeData) => unstakeData.unstakeInfo.availableAt > DateTime.now()); + stakingPool: availableStakingPoolsData.find( + (pool) => pool.definition.address === unstakeInfo.address + )!, + })) || [] + + const availableForUnstaking = combinedUserUnstakesData.filter( + (unstakeData) => unstakeData.unstakeInfo.availableAt <= DateTime.now() + ) + const pendingUnstaking = combinedUserUnstakesData.filter( + (unstakeData) => unstakeData.unstakeInfo.availableAt > DateTime.now() + ) return { availableStakingPools: availableStakingPoolsData, @@ -199,7 +256,7 @@ const useStakingPoolsStorage = () => { pendingUnstaking, reloadUserStakingPoolsData, isUnstakingDataLoading, - }; -}; + } +} -export const StakingPoolsStorage = createContainer(useStakingPoolsStorage); +export const StakingPoolsStorage = createContainer(useStakingPoolsStorage) diff --git a/src/contexts/walletConnector.tsx b/src/contexts/walletConnector.tsx index 3042374..cf7c2e3 100644 --- a/src/contexts/walletConnector.tsx +++ b/src/contexts/walletConnector.tsx @@ -1,97 +1,94 @@ -"use client"; +"use client" -import { useEffect, useState } from "react"; -import { createContainer } from "./context"; -import { DummyWallet } from "@/misc/walletsConfig"; -import { useWalletClient } from "wagmi"; -import { getBalance } from "viem/actions"; -import { Address } from "viem"; -import { getViemClient } from "@/misc/chainConfig"; -import { AppConfigStorage } from "./appConfigStorage"; +import { useEffect, useState } from "react" +import { createContainer } from "./context" +import { DummyWallet } from "@/misc/walletsConfig" +import { useWalletClient } from "wagmi" +import { getBalance } from "viem/actions" +import { Address } from "viem" +import { getViemClient } from "@/misc/chainConfig" +import { AppConfigStorage } from "./appConfigStorage" export enum ConnectedWalletType { None, MockWallet, - RealWallet + RealWallet, } const useWalletConnector = () => { - const [zilAvailable, setZilAvailable] = useState(null); + const [zilAvailable, setZilAvailable] = useState(null) - const { - appConfig - } = AppConfigStorage.useContainer(); + const { appConfig } = AppConfigStorage.useContainer() /** * Dummy Wallet section */ - const [isDummyWalletConnected, setIsDummyWalletConnected] = useState(false); - const [isDummyWalletConnecting, setIsDummyWalletConnecting] = useState(false); - const [isDummyWalletSelectorOpen, setIsDummyWalletSelectorOpen] = useState(false); - const [dummyWallet, setDummyWallet] = useState(null); + const [isDummyWalletConnected, setIsDummyWalletConnected] = useState(false) + const [isDummyWalletConnecting, setIsDummyWalletConnecting] = useState(false) + const [isDummyWalletSelectorOpen, setIsDummyWalletSelectorOpen] = + useState(false) + const [dummyWallet, setDummyWallet] = useState(null) const connectDummyWallet = () => { - setIsDummyWalletConnecting(true); - setIsDummyWalletSelectorOpen(true); + setIsDummyWalletConnecting(true) + setIsDummyWalletSelectorOpen(true) } const selectDummyWallet = (wallet: DummyWallet) => { - setDummyWallet(wallet); - setTimeout( - () => { - setZilAvailable(wallet.currentZil); - }, - 1500 - ) - - setIsDummyWalletConnected(true); - setIsDummyWalletSelectorOpen(false); - setIsDummyWalletConnecting(false); + setDummyWallet(wallet) + setTimeout(() => { + setZilAvailable(wallet.currentZil) + }, 1500) + + setIsDummyWalletConnected(true) + setIsDummyWalletSelectorOpen(false) + setIsDummyWalletConnecting(false) } const disconnectDummyWallet = () => { - setIsDummyWalletConnected(false); - setDummyWallet(null); - setIsDummyWalletConnecting(false); - setIsDummyWalletSelectorOpen(false); - setZilAvailable(0n); - }; + setIsDummyWalletConnected(false) + setDummyWallet(null) + setIsDummyWalletConnecting(false) + setIsDummyWalletSelectorOpen(false) + setZilAvailable(0n) + } /** * Rainbow wallet section */ - const { - data: walletClient, - } = useWalletClient(); + const { data: walletClient } = useWalletClient() /** * Wallet data */ - const isWalletConnected = walletClient || isDummyWalletConnected; - const connectedWalletType = walletClient ? ConnectedWalletType.RealWallet : isDummyWalletConnected ? ConnectedWalletType.MockWallet : ConnectedWalletType.None; - const walletAddress = walletClient ? walletClient.account.address : isDummyWalletConnected ? dummyWallet!.address : null; + const isWalletConnected = walletClient || isDummyWalletConnected + const connectedWalletType = walletClient + ? ConnectedWalletType.RealWallet + : isDummyWalletConnected + ? ConnectedWalletType.MockWallet + : ConnectedWalletType.None + const walletAddress = walletClient + ? walletClient.account.address + : isDummyWalletConnected + ? dummyWallet!.address + : null const updateWalletBalance = () => { if (!walletAddress) { - setZilAvailable(null); - return; + setZilAvailable(null) + return } getBalance(getViemClient(appConfig.chainId), { address: walletAddress as Address, - }).then( - (balanceInWei) => { - setZilAvailable(balanceInWei); - } - ); + }).then((balanceInWei) => { + setZilAvailable(balanceInWei) + }) } - useEffect( - updateWalletBalance, - [walletAddress] - ); + useEffect(updateWalletBalance, [walletAddress]) return { isWalletConnected, @@ -105,7 +102,7 @@ const useWalletConnector = () => { selectDummyWallet, connectedWalletType, updateWalletBalance, - }; -}; + } +} -export const WalletConnector = createContainer(useWalletConnector); +export const WalletConnector = createContainer(useWalletConnector) diff --git a/src/misc/chainConfig.ts b/src/misc/chainConfig.ts index d467fd7..fbec6b4 100644 --- a/src/misc/chainConfig.ts +++ b/src/misc/chainConfig.ts @@ -1,90 +1,98 @@ -import { connectorsForWallets } from '@rainbow-me/rainbowkit'; -import { coinbaseWallet, ledgerWallet, metaMaskWallet, phantomWallet, rabbyWallet, rainbowWallet, trustWallet, walletConnectWallet } from '@rainbow-me/rainbowkit/wallets'; -import { createClient, createPublicClient, defineChain, http } from 'viem'; -import { createConfig } from 'wagmi'; - +import { connectorsForWallets } from "@rainbow-me/rainbowkit" +import { + coinbaseWallet, + ledgerWallet, + metaMaskWallet, + phantomWallet, + rabbyWallet, + rainbowWallet, + trustWallet, + walletConnectWallet, +} from "@rainbow-me/rainbowkit/wallets" +import { createClient, createPublicClient, defineChain, http } from "viem" +import { createConfig } from "wagmi" export const CHAIN_ZQ2_DEVNET = defineChain({ id: 33469, - name: 'Zq2 Devnet', - nativeCurrency: { name: 'ZIL', symbol: 'ZIL', decimals: 18 }, + name: "Zq2 Devnet", + nativeCurrency: { name: "ZIL", symbol: "ZIL", decimals: 18 }, rpcUrls: { default: { - http: ['https://api.zq2-devnet.zilliqa.com'], + http: ["https://api.zq2-devnet.zilliqa.com"], }, }, blockExplorers: { default: { - name: 'Otterscan', - url: 'https://explorer.zq2-devnet.zilliqa.com', + name: "Otterscan", + url: "https://explorer.zq2-devnet.zilliqa.com", }, }, }) export const CHAIN_ZQ2_PROTOTESTNET = defineChain({ id: 33103, - name: 'Zq2 ProtoTestnet', - nativeCurrency: { name: 'ZIL', symbol: 'ZIL', decimals: 18 }, + name: "Zq2 ProtoTestnet", + nativeCurrency: { name: "ZIL", symbol: "ZIL", decimals: 18 }, rpcUrls: { default: { - http: ['https://api.zq2-prototestnet.zilliqa.com'], + http: ["https://api.zq2-prototestnet.zilliqa.com"], }, }, blockExplorers: { default: { - name: 'Otterscan', - url: 'https://explorer.zq2-prototestnet.zilliqa.com', + name: "Otterscan", + url: "https://explorer.zq2-prototestnet.zilliqa.com", }, }, }) export const CHAIN_ZQ2_PROTOMAINNET = defineChain({ id: 32770, - name: 'Zq2 ProtoMainnet', - nativeCurrency: { name: 'ZIL', symbol: 'ZIL', decimals: 18 }, + name: "Zq2 ProtoMainnet", + nativeCurrency: { name: "ZIL", symbol: "ZIL", decimals: 18 }, rpcUrls: { default: { - http: ['https://api.zq2-protomainnet.zilliqa.com'], + http: ["https://api.zq2-protomainnet.zilliqa.com"], }, }, blockExplorers: { default: { - name: 'Otterscan', - url: 'https://explorer.zq2-protomainnet.zilliqa.com', + name: "Otterscan", + url: "https://explorer.zq2-protomainnet.zilliqa.com", }, }, }) export const CHAIN_ZQ2_DOCKERCOMPOSE = defineChain({ id: 87362, - name: 'Zq2 Dockercompose', - nativeCurrency: { name: 'ZIL', symbol: 'ZIL', decimals: 18 }, + name: "Zq2 Dockercompose", + nativeCurrency: { name: "ZIL", symbol: "ZIL", decimals: 18 }, rpcUrls: { default: { - http: ['http://localhost:4201'], + http: ["http://localhost:4201"], }, }, blockExplorers: { default: { - name: 'Otterscan', - url: 'http://localhost:5100/', + name: "Otterscan", + url: "http://localhost:5100/", }, }, }) export const MOCK_CHAIN = defineChain({ id: 9999999, - name: 'Mock Chain', - nativeCurrency: { name: 'ZIL', symbol: 'ZIL', decimals: 18 }, + name: "Mock Chain", + nativeCurrency: { name: "ZIL", symbol: "ZIL", decimals: 18 }, rpcUrls: { default: { - http: ['NOT_USED'], + http: ["NOT_USED"], }, }, blockExplorers: { default: { - name: 'NOT_USED', - url: 'NOT_USED', + name: "NOT_USED", + url: "NOT_USED", }, }, }) @@ -93,7 +101,7 @@ function getConnectorsForWallets(walletConnectApiKey: string) { return connectorsForWallets( [ { - groupName: 'Recommended', + groupName: "Recommended", wallets: [ metaMaskWallet, walletConnectWallet, @@ -102,13 +110,13 @@ function getConnectorsForWallets(walletConnectApiKey: string) { trustWallet, ledgerWallet, rainbowWallet, - phantomWallet + phantomWallet, ], }, ], { - appName: 'ZQ2 Staking', - projectId: walletConnectApiKey + appName: "ZQ2 Staking", + projectId: walletConnectApiKey, } ) } @@ -120,15 +128,13 @@ export function getChain(chainId: number) { CHAIN_ZQ2_PROTOMAINNET, CHAIN_ZQ2_DOCKERCOMPOSE, MOCK_CHAIN, - ].find( - (chain) => chain.id === chainId - ); + ].find((chain) => chain.id === chainId) if (!chain) { - throw new Error(`Active chain [${chainId}] is not defined`); + throw new Error(`Active chain [${chainId}] is not defined`) } - return chain; + return chain } export function getWagmiConfig(chainId: number, walletConnectApiKey: string) { @@ -138,12 +144,12 @@ export function getWagmiConfig(chainId: number, walletConnectApiKey: string) { return createClient({ chain, transport: http() }) }, connectors: getConnectorsForWallets(walletConnectApiKey), - }); + }) } export function getViemClient(chainId: number) { return createPublicClient({ chain: getChain(chainId), transport: http(), - }); -} \ No newline at end of file + }) +} diff --git a/src/misc/formatting.ts b/src/misc/formatting.ts index a317f4c..e747efc 100644 --- a/src/misc/formatting.ts +++ b/src/misc/formatting.ts @@ -1,63 +1,75 @@ -import { DateTime } from "luxon"; -import { formatUnits } from "viem"; -import { getChain } from "./chainConfig"; +import { DateTime } from "luxon" +import { formatUnits } from "viem" +import { getChain } from "./chainConfig" export function formatPercentage(value: number) { - return `${parseFloat((value * 100).toFixed(2))}%`; + return `${parseFloat((value * 100).toFixed(2))}%` } export function formatAddress(address: string) { - return `${address.slice(0, 5)}...${address.slice(-3)}`; + return `${address.slice(0, 5)}...${address.slice(-3)}` } export function getHumanFormDuration(availableAt: DateTime) { - const units = availableAt.diff(DateTime.now()).shiftTo('days', 'hours', 'minutes').toHuman({ - unitDisplay: 'long', - listStyle: 'narrow', - maximumFractionDigits: 0, - }) + const units = availableAt + .diff(DateTime.now()) + .shiftTo("days", "hours", "minutes") + .toHuman({ + unitDisplay: "long", + listStyle: "narrow", + maximumFractionDigits: 0, + }) const mostSignificantUnit = units - .split(',') - .map(units => units.trim()) + .split(",") + .map((units) => units.trim()) .reduce((acc, unit) => { - if (acc !== '') { + if (acc !== "") { return acc } // check if unit starts with smh different that 0 // e.g., 0 days 2 hours 5 minutes should return "2 hours" - if (unit[0] !== '0') { + if (unit[0] !== "0") { return unit } return acc - }, '') + }, "") - return `~${mostSignificantUnit || '< 1 minute'}` + return `~${mostSignificantUnit || "< 1 minute"}` } -export function convertTokenToZil(tokenAmount: bigint, zilToTokenRate: number): bigint { - const rate = BigInt(Math.round((1 / zilToTokenRate) * 100)); - const amount = (tokenAmount * rate) / 100n; - return amount; +export function convertTokenToZil( + tokenAmount: bigint, + zilToTokenRate: number +): bigint { + const rate = BigInt(Math.round((1 / zilToTokenRate) * 100)) + const amount = (tokenAmount * rate) / 100n + return amount } -export function convertZilValueInToken(zilAmount: number, zilToTokenRate: number) { - return `${(zilAmount * zilToTokenRate).toFixed(2)}` +export function convertZilValueInToken( + zilAmount: number, + zilToTokenRate: number +) { + return `${(zilAmount * zilToTokenRate).toFixed(2)}` } -export function formatUnitsToHumanReadable(value: bigint, decimals: number): string { - const raw = parseFloat(formatUnits(value, decimals)); +export function formatUnitsToHumanReadable( + value: bigint, + decimals: number +): string { + const raw = parseFloat(formatUnits(value, decimals)) - const formatter = new Intl.NumberFormat('en-US', { - notation: 'compact', - compactDisplay: 'short', - }); + const formatter = new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }) - return formatter.format(raw); + return formatter.format(raw) } export function getTxExplorerUrl(txHash: string, chainId: number) { - return `${getChain(chainId).blockExplorers.default.url}/tx/${txHash}`; -} \ No newline at end of file + return `${getChain(chainId).blockExplorers.default.url}/tx/${txHash}` +} diff --git a/src/misc/stakingAbis.ts b/src/misc/stakingAbis.ts index b403fb4..edbaf06 100644 --- a/src/misc/stakingAbis.ts +++ b/src/misc/stakingAbis.ts @@ -1,30 +1,30 @@ export const depositAbi = [ { - "inputs": [], - "name": "getFutureTotalStake", - "outputs": [ + inputs: [], + name: "getFutureTotalStake", + outputs: [ { - "internalType": "uint256", - "name": "", - "type": "uint256" - } + internalType: "uint256", + name: "", + type: "uint256", + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: "view", + type: "function", }, { - "inputs": [], - "name": "withdrawalPeriod", - "outputs": [ + inputs: [], + name: "withdrawalPeriod", + outputs: [ { - "internalType": "uint256", - "name": "", - "type": "uint256" - } + internalType: "uint256", + name: "", + type: "uint256", + }, ], - "stateMutability": "view", - "type": "function" - } + stateMutability: "view", + type: "function", + }, ] export const delegatorAbi = [ @@ -32,129 +32,129 @@ export const delegatorAbi = [ * from Delegation.sol */ { - "inputs": [], - "name": "stake", - "outputs": [], - "stateMutability": "payable", - "type": "function" + inputs: [], + name: "stake", + outputs: [], + stateMutability: "payable", + type: "function", }, { - "inputs": [ + inputs: [ { - "internalType": "uint256", - "name": "shares", - "type": "uint256" - } + internalType: "uint256", + name: "shares", + type: "uint256", + }, ], - "name": "unstake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + name: "unstake", + outputs: [], + stateMutability: "nonpayable", + type: "function", }, { - "inputs": [], - "name": "claim", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" + inputs: [], + name: "claim", + outputs: [], + stateMutability: "nonpayable", + type: "function", }, { - "inputs": [], - "name": "getPendingClaims", - "outputs": [ + inputs: [], + name: "getPendingClaims", + outputs: [ { - "internalType": "uint256[2][]", - "name": "claims", - "type": "uint256[2][]" - } + internalType: "uint256[2][]", + name: "claims", + type: "uint256[2][]", + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: "view", + type: "function", }, { - "inputs": [], - "name": "getMinDelegation", - "outputs": [ + inputs: [], + name: "getMinDelegation", + outputs: [ { - "internalType": "uint256", - "name": "", - "type": "uint256" - } + internalType: "uint256", + name: "", + type: "uint256", + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: "view", + type: "function", }, { - "inputs": [], - "name": "getCommission", - "outputs": [ + inputs: [], + name: "getCommission", + outputs: [ { - "internalType": "uint256", - "name": "", - "type": "uint256" + internalType: "uint256", + name: "", + type: "uint256", }, { - "internalType": "uint256", - "name": "", - "type": "uint256" - } + internalType: "uint256", + name: "", + type: "uint256", + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: "view", + type: "function", }, { - "inputs": [], - "name": "getStake", - "outputs": [ + inputs: [], + name: "getStake", + outputs: [ { - "internalType": "uint256", - "name": "", - "type": "uint256" - } + internalType: "uint256", + name: "", + type: "uint256", + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: "view", + type: "function", }, { - "inputs": [], - "name": "getClaimable", - "outputs": [ + inputs: [], + name: "getClaimable", + outputs: [ { - "internalType": "uint256", - "name": "", - "type": "uint256" - } + internalType: "uint256", + name: "", + type: "uint256", + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: "view", + type: "function", }, /** * From ILiquidDelegation.sol */ { - "inputs": [], - "name": "getLST", - "outputs": [ + inputs: [], + name: "getLST", + outputs: [ { - "internalType": "address", - "name": "", - "type": "address" - } + internalType: "address", + name: "", + type: "address", + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: "view", + type: "function", }, { - "inputs": [], - "name": "getPrice", - "outputs": [ + inputs: [], + name: "getPrice", + outputs: [ { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } + internalType: "uint256", + name: "amount", + type: "uint256", + }, ], - "stateMutability": "view", - "type": "function" + stateMutability: "view", + type: "function", }, -] \ No newline at end of file +] diff --git a/src/misc/stakingPoolsConfig.ts b/src/misc/stakingPoolsConfig.ts index ecb318d..0036c11 100644 --- a/src/misc/stakingPoolsConfig.ts +++ b/src/misc/stakingPoolsConfig.ts @@ -1,54 +1,71 @@ -import { Address, erc20Abi, formatUnits, parseUnits } from "viem"; -import { CHAIN_ZQ2_PROTOTESTNET, CHAIN_ZQ2_DOCKERCOMPOSE, getViemClient, MOCK_CHAIN, CHAIN_ZQ2_DEVNET, CHAIN_ZQ2_PROTOMAINNET } from "./chainConfig"; -import { readContract } from "viem/actions"; -import { delegatorAbi, depositAbi } from "./stakingAbis"; +import { Address, erc20Abi, formatUnits, parseUnits } from "viem" +import { + CHAIN_ZQ2_PROTOTESTNET, + CHAIN_ZQ2_DOCKERCOMPOSE, + getViemClient, + MOCK_CHAIN, + CHAIN_ZQ2_DEVNET, + CHAIN_ZQ2_PROTOMAINNET, +} from "./chainConfig" +import { readContract } from "viem/actions" +import { delegatorAbi, depositAbi } from "./stakingAbis" /** * Deposit address is always the same */ -const DEPOSIT_ADDRESS = "0x00000000005a494c4445504f53495450524f5859" as Address; +const DEPOSIT_ADDRESS = "0x00000000005a494c4445504f53495450524f5859" as Address export interface StakingPoolDefinition { - id: string; - name: string; - address: string; - tokenAddress: string; - tokenDecimals: number; - tokenSymbol: string; - iconUrl: string; - minimumStake: bigint; - withdrawPeriodInMinutes: number; + id: string + name: string + address: string + tokenAddress: string + tokenDecimals: number + tokenSymbol: string + iconUrl: string + minimumStake: bigint + withdrawPeriodInMinutes: number } export interface StakingPoolData { - tvl: bigint; - apr: number; - commission: number; - votingPower: number; - zilToTokenRate: number; + tvl: bigint + apr: number + commission: number + votingPower: number + zilToTokenRate: number } export interface StakingPool { - definition: StakingPoolDefinition; - data: StakingPoolData | null; + definition: StakingPoolDefinition + data: StakingPoolData | null } export interface StakingPoolConfig { - definition: StakingPoolDefinition; - delegatorDataProvider: (definition: StakingPoolDefinition, chainId: number) => Promise; + definition: StakingPoolDefinition + delegatorDataProvider: ( + definition: StakingPoolDefinition, + chainId: number + ) => Promise } -async function mockDelegatorDataProvider(mockData: StakingPoolData, loadingMiliseconds: number, definition: StakingPoolDefinition, chainId: number): Promise { +async function mockDelegatorDataProvider( + mockData: StakingPoolData, + loadingMiliseconds: number, + definition: StakingPoolDefinition, + chainId: number +): Promise { return new Promise((resolve) => { setTimeout(() => { - resolve(mockData); - }, loadingMiliseconds); - }); + resolve(mockData) + }, loadingMiliseconds) + }) } -async function fetchDelegatorDataFromNetwork(definition: StakingPoolDefinition, chainId: number): Promise { - - const viemClient = getViemClient(chainId); +async function fetchDelegatorDataFromNetwork( + definition: StakingPoolDefinition, + chainId: number +): Promise { + const viemClient = getViemClient(chainId) const readDelegatorContract = async (functionName: string): Promise => { return (await readContract(viemClient, { @@ -58,8 +75,16 @@ async function fetchDelegatorDataFromNetwork(definition: StakingPoolDefinition, })) as T } - const readTokenContract = async (functionName: "symbol" | "name" | "totalSupply" | "allowance" | "balanceOf" | "decimals"): Promise => { - return await (readContract(viemClient, { + const readTokenContract = async ( + functionName: + | "symbol" + | "name" + | "totalSupply" + | "allowance" + | "balanceOf" + | "decimals" + ): Promise => { + return (await readContract(viemClient, { address: definition.tokenAddress as Address, abi: erc20Abi, functionName, @@ -67,7 +92,7 @@ async function fetchDelegatorDataFromNetwork(definition: StakingPoolDefinition, } const readDepositContract = async (functionName: string): Promise => { - return await (readContract(viemClient, { + return (await readContract(viemClient, { address: DEPOSIT_ADDRESS, abi: depositAbi, functionName, @@ -80,45 +105,53 @@ async function fetchDelegatorDataFromNetwork(definition: StakingPoolDefinition, zilToTokenRateWei, delegatorStake, depositTotalStake, - [commissionNumerator, commissionDenominator] + [commissionNumerator, commissionDenominator], ] = await Promise.all([ readTokenContract("totalSupply"), readDelegatorContract("getPrice"), readDelegatorContract("getStake"), readDepositContract("getFutureTotalStake"), readDelegatorContract<[bigint, bigint]>("getCommission"), - ]); + ]) - const zilToTokenRate = 1 / parseFloat(formatUnits(zilToTokenRateWei, 18)); + const zilToTokenRate = 1 / parseFloat(formatUnits(zilToTokenRateWei, 18)) - const bigintDivisionPrecision = 1000000n; + const bigintDivisionPrecision = 1000000n - const commission = Number((commissionNumerator * bigintDivisionPrecision) / commissionDenominator) / Number(bigintDivisionPrecision); - const votingPower = Number(((delegatorStake * bigintDivisionPrecision) / depositTotalStake)) / Number(bigintDivisionPrecision); - const rewardsPerYearInZil = 51000 * 24 * 365; + const commission = + Number( + (commissionNumerator * bigintDivisionPrecision) / commissionDenominator + ) / Number(bigintDivisionPrecision) + const votingPower = + Number((delegatorStake * bigintDivisionPrecision) / depositTotalStake) / + Number(bigintDivisionPrecision) + const rewardsPerYearInZil = 51000 * 24 * 365 - const delegatorYearReward = votingPower * rewardsPerYearInZil; - const delegatorRewardForShare = delegatorYearReward * (1 - commission); - const apr = delegatorRewardForShare / parseFloat(formatUnits(delegatorStake, 18)); + const delegatorYearReward = votingPower * rewardsPerYearInZil + const delegatorRewardForShare = delegatorYearReward * (1 - commission) + const apr = + delegatorRewardForShare / parseFloat(formatUnits(delegatorStake, 18)) return { tvl: totalSupply, commission, zilToTokenRate, votingPower, - apr: apr - + apr: apr, } } catch (error) { - console.error("Error fetching total supply:", error); - throw error; + console.error("Error fetching total supply:", error) + throw error } } -const twoWeeksInMinutes = 60 * 24 * 14; -const fiveMinutesInMinutes = 5; +const twoWeeksInMinutes = 60 * 24 * 14 +const fiveMinutesInMinutes = 5 -export const stakingPoolsConfigForChainId: Record> = { +export const stakingPoolsConfigForChainId: Record< + string, + Array +> = { [MOCK_CHAIN.id]: [ { definition: { @@ -133,7 +166,8 @@ export const stakingPoolsConfigForChainId: Record; - zilAmount: Array; - currentZil: bigint; + name: string + address: string + stakingTokenAmount: Array + zilAmount: Array + currentZil: bigint } export const dummyWallets: Array = [ @@ -66,12 +66,12 @@ export const dummyWallets: Array = [ { address: "0x1234567890234567890234567890234567890", stakingTokenAmount: parseUnits("1000.50", 18), - rewardAcumulated: 10 + rewardAcumulated: 10, }, { address: "0x96525678902345678902345678918278372212", stakingTokenAmount: parseUnits("60.50", 18), - rewardAcumulated: 50 + rewardAcumulated: 50, }, ], zilAmount: [], @@ -84,12 +84,12 @@ export const dummyWallets: Array = [ { address: "0x1234567890234567890234567890234567890", stakingTokenAmount: parseUnits("1000", 18), - rewardAcumulated: 10 + rewardAcumulated: 10, }, { address: "0x96525678902345678902345678918278372212", stakingTokenAmount: parseUnits("9991119", 18), - rewardAcumulated: 50 + rewardAcumulated: 50, }, ], zilAmount: [ @@ -128,116 +128,121 @@ export const dummyWallets: Array = [ { address: "0x96525678902345678902345678918278372212", stakingTokenAmount: parseUnits("123.522039320", 18), - rewardAcumulated: 40 + rewardAcumulated: 40, }, { address: "0x82245678902345678902345678918278372382", stakingTokenAmount: parseUnits("99999", 18), - rewardAcumulated: 0 + rewardAcumulated: 0, }, ], zilAmount: [], }, ] -export async function getWalletStakingData(wallet: string, chainId: number): Promise { +export async function getWalletStakingData( + wallet: string, + chainId: number +): Promise { if (chainId === MOCK_CHAIN.id) { return new Promise((resolve) => { setTimeout(() => { - resolve(dummyWallets.find((dw) => dw.address === wallet)?.stakingTokenAmount || []); - }, 1000); - }); + resolve( + dummyWallets.find((dw) => dw.address === wallet) + ?.stakingTokenAmount || [] + ) + }, 1000) + }) } else { const stakingData: UserStakingPoolData[] = await Promise.all( - stakingPoolsConfigForChainId[chainId].map( - async (pool) => { - return { - address: pool.definition.address, - stakingTokenAmount: await readContract(getViemClient(chainId), { - address: pool.definition.tokenAddress as Address, - abi: erc20Abi, - functionName: "balanceOf", - args: [wallet as Address], - }), - rewardAcumulated: 0, - } + stakingPoolsConfigForChainId[chainId].map(async (pool) => { + return { + address: pool.definition.address, + stakingTokenAmount: await readContract(getViemClient(chainId), { + address: pool.definition.tokenAddress as Address, + abi: erc20Abi, + functionName: "balanceOf", + args: [wallet as Address], + }), + rewardAcumulated: 0, } - ) + }) ) - return stakingData; + return stakingData } } -export async function getWalletUnstakingData(wallet: string, chainId: number): Promise { +export async function getWalletUnstakingData( + wallet: string, + chainId: number +): Promise { if (chainId === MOCK_CHAIN.id) { return new Promise((resolve) => { setTimeout(() => { - resolve(dummyWallets.find((dw) => dw.address === wallet)?.zilAmount || []); - }, 1000); - }); + resolve( + dummyWallets.find((dw) => dw.address === wallet)?.zilAmount || [] + ) + }, 1000) + }) } else { - const currentBlockNumber = await getViemClient(chainId).getBlockNumber(); + const currentBlockNumber = await getViemClient(chainId).getBlockNumber() // get unstaking data from contracts - const unstakingWalletData = await Promise.all( - stakingPoolsConfigForChainId[chainId].map( - async (pool) => { - return { - address: pool.definition.address, - blockNumberAndAmount: (await readContract(getViemClient(chainId), { - address: pool.definition.address as Address, - abi: delegatorAbi, - functionName: "getPendingClaims", - account: wallet as Address, - })) as bigint[][], - claimableNow: await readContract(getViemClient(chainId), { - address: pool.definition.address as Address, - abi: delegatorAbi, - functionName: "getClaimable", - account: wallet as Address, - }) as bigint - } + const unstakingWalletData = await Promise.all( + stakingPoolsConfigForChainId[chainId].map(async (pool) => { + return { + address: pool.definition.address, + blockNumberAndAmount: (await readContract(getViemClient(chainId), { + address: pool.definition.address as Address, + abi: delegatorAbi, + functionName: "getPendingClaims", + account: wallet as Address, + })) as bigint[][], + claimableNow: (await readContract(getViemClient(chainId), { + address: pool.definition.address as Address, + abi: delegatorAbi, + functionName: "getClaimable", + account: wallet as Address, + })) as bigint, } - ) + }) ) // convert contracts raw data into application data - const result: UserUnstakingPoolData[] = unstakingWalletData.filter( - (uwd) => uwd.blockNumberAndAmount.length > 0 || uwd.claimableNow > 0 - ).map( - (uwd) => { - - const claims: UserUnstakingPoolData[] = []; + const result: UserUnstakingPoolData[] = unstakingWalletData + .filter( + (uwd) => uwd.blockNumberAndAmount.length > 0 || uwd.claimableNow > 0 + ) + .map((uwd) => { + const claims: UserUnstakingPoolData[] = [] if (uwd.claimableNow > 0) { claims.push({ zilAmount: uwd.claimableNow, availableAt: DateTime.now().minus({ days: 1 }), // just to make sure it displays address: uwd.address, - }); + }) } if (uwd.blockNumberAndAmount.length > 0) { claims.push( - ...uwd.blockNumberAndAmount.map( - (bna) => { - const blocksRemaining = Number(bna[0] - currentBlockNumber); + ...uwd.blockNumberAndAmount.map((bna) => { + const blocksRemaining = Number(bna[0] - currentBlockNumber) - return { - zilAmount: bna[1], - availableAt: DateTime.now().plus({ seconds: blocksRemaining }), // we assume block takes a second - address: uwd.address, - } + return { + zilAmount: bna[1], + availableAt: DateTime.now().plus({ seconds: blocksRemaining }), // we assume block takes a second + address: uwd.address, } - ) - ); + }) + ) } - return claims; - } - ).flat(); + return claims + }) + .flat() - return result; + return result } } diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index f51cfaa..6e03782 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,103 +1,103 @@ -import "@/styles/globals.css"; -import 'tailwindcss/tailwind.css'; -import '@rainbow-me/rainbowkit/styles.css'; -import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage"; -import type { AppProps } from "next/app"; -import { WalletConnector } from "@/contexts/walletConnector"; -import DummyWalletSelector from "@/components/dummyWalletSelector"; -import { ConfigProvider } from 'antd'; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { WagmiProvider } from "wagmi"; -import { RainbowKitProvider } from "@rainbow-me/rainbowkit"; -import { StakingOperations } from "@/contexts/stakingOperations"; -import { getWagmiConfig } from "@/misc/chainConfig"; -import { useEffect, useState } from "react"; -import { AppConfig } from "./api/config"; -import { AppConfigStorage } from "@/contexts/appConfigStorage"; +import "@/styles/globals.css" +import "tailwindcss/tailwind.css" +import "@rainbow-me/rainbowkit/styles.css" +import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage" +import type { AppProps } from "next/app" +import { WalletConnector } from "@/contexts/walletConnector" +import DummyWalletSelector from "@/components/dummyWalletSelector" +import { ConfigProvider } from "antd" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" +import { WagmiProvider } from "wagmi" +import { RainbowKitProvider } from "@rainbow-me/rainbowkit" +import { StakingOperations } from "@/contexts/stakingOperations" +import { getWagmiConfig } from "@/misc/chainConfig" +import { useEffect, useState } from "react" +import { AppConfig } from "./api/config" +import { AppConfigStorage } from "@/contexts/appConfigStorage" export default function App({ Component, pageProps }: AppProps) { - const queryClient = new QueryClient(); - const [appConfig, setAppConfig] = useState(null); - const [loadingPercentage, setLoadingPercentage] = useState(0); - const [displayedPercentage, setDisplayedPercentage] = useState(0); - const [fadeOut, setFadeOut] = useState(false); + const queryClient = new QueryClient() + const [appConfig, setAppConfig] = useState(null) + const [loadingPercentage, setLoadingPercentage] = useState(0) + const [displayedPercentage, setDisplayedPercentage] = useState(0) + const [fadeOut, setFadeOut] = useState(false) useEffect(() => { const fetchConfig = async () => { - const startTime = Date.now(); - let progress = 0; + const startTime = Date.now() + let progress = 0 - const interval = setInterval(() => { - progress += 10; - setLoadingPercentage(progress); + const interval = setInterval(() => { + progress += 10 + setLoadingPercentage(progress) if (progress >= 100) { - clearInterval(interval); + clearInterval(interval) } - }, 50); + }, 50) try { - const res = await fetch("/api/config"); - const data = await res.json(); - const elapsedTime = Date.now() - startTime; + const res = await fetch("/api/config") + const data = await res.json() + const elapsedTime = Date.now() - startTime - const remainingTime = Math.max(1000 - elapsedTime, 0); + const remainingTime = Math.max(1000 - elapsedTime, 0) setTimeout(() => { - clearInterval(interval); - setLoadingPercentage(100); + clearInterval(interval) + setLoadingPercentage(100) setTimeout(() => { - setAppConfig(data); - }, 500); - setFadeOut(true); - }, remainingTime); + setAppConfig(data) + }, 500) + setFadeOut(true) + }, remainingTime) } catch (error) { - console.error("Error loading config:", error); + console.error("Error loading config:", error) } - }; + } - fetchConfig(); - }, []); + fetchConfig() + }, []) useEffect(() => { - const duration = 500; - const frameRate = 16; - const totalFrames = duration / frameRate; - const increment = (loadingPercentage - displayedPercentage) / totalFrames; + const duration = 500 + const frameRate = 16 + const totalFrames = duration / frameRate + const increment = (loadingPercentage - displayedPercentage) / totalFrames if (increment !== 0) { - let currentFrame = 0; + let currentFrame = 0 const easingInterval = setInterval(() => { setDisplayedPercentage((prev) => { - currentFrame += 1; - const next = prev + increment; + currentFrame += 1 + const next = prev + increment if ( currentFrame >= totalFrames || (increment > 0 && next >= loadingPercentage) || (increment < 0 && next <= loadingPercentage) ) { - clearInterval(easingInterval); - return loadingPercentage; + clearInterval(easingInterval) + return loadingPercentage } - return next; - }); - }, frameRate); + return next + }) + }, frameRate) - return () => clearInterval(easingInterval); + return () => clearInterval(easingInterval) } - }, [loadingPercentage]); + }, [loadingPercentage]) if (!appConfig) { return (
-
+ className={`h-screen bg-black text-white transition-opacity duration-500 ${ + fadeOut ? "opacity-0" : "opacity-100" + }`} + > +
@@ -106,13 +106,18 @@ export default function App({ Component, pageProps }: AppProps) {
- ); + ) } return ( - + @@ -128,5 +133,5 @@ export default function App({ Component, pageProps }: AppProps) { - ); + ) } diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx index e2b4f05..aa815db 100644 --- a/src/pages/_document.tsx +++ b/src/pages/_document.tsx @@ -1,4 +1,4 @@ -import { Html, Head, Main, NextScript } from 'next/document'; +import { Html, Head, Main, NextScript } from "next/document" export default function Document() { return ( @@ -15,5 +15,5 @@ export default function Document() { - ); + ) } diff --git a/src/pages/api/config.ts b/src/pages/api/config.ts index a8726ee..999eae2 100644 --- a/src/pages/api/config.ts +++ b/src/pages/api/config.ts @@ -1,40 +1,41 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next" export type AppConfig = { - chainId: number; - walletConnectPrivateKey: string; -}; + chainId: number + walletConnectPrivateKey: string +} function getStringFromEnv(name: string): string { - const value = process.env[name]; + const value = process.env[name] if (!value) { - throw new Error(`${name} is not defined`); + throw new Error(`${name} is not defined`) } - return value; + return value } function getNumberFromEnv(name: string): number { - const value = getStringFromEnv(name); - const number = parseInt(value); + const value = getStringFromEnv(name) + const number = parseInt(value) if (isNaN(number)) { - throw new Error(`${name} is not a number`); + throw new Error(`${name} is not a number`) } - return number; + return number } const config: AppConfig = { chainId: getNumberFromEnv("ZQ2_STAKING_CHAIN_ID"), - walletConnectPrivateKey: getStringFromEnv("ZQ2_STAKING_WALLET_CONNECT_API_KEY"), - + walletConnectPrivateKey: getStringFromEnv( + "ZQ2_STAKING_WALLET_CONNECT_API_KEY" + ), } export default function handler( req: NextApiRequest, - res: NextApiResponse, + res: NextApiResponse ) { - res.status(200).json(config); + res.status(200).json(config) } diff --git a/src/pages/api/health.ts b/src/pages/api/health.ts index 5b2d5f2..ac3155e 100644 --- a/src/pages/api/health.ts +++ b/src/pages/api/health.ts @@ -1,12 +1,12 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next" type Response = { - name: string; -}; + name: string +} export default function handler( req: NextApiRequest, - res: NextApiResponse, + res: NextApiResponse ) { - res.status(200).json({ name: "ok" }); + res.status(200).json({ name: "ok" }) } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index bea2a7c..367ef97 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,34 +1,33 @@ -import LoginView from '@/components/loginView'; -import StakingPoolDetailsView from '@/components/stakingPoolDetailsView'; -import StakingPoolsList from '@/components/stakingPoolsList'; -import WithdrawZilView from '@/components/withdrawZilView'; -import { AppConfigStorage } from '@/contexts/appConfigStorage'; -import { StakingOperations } from '@/contexts/stakingOperations'; -import { StakingPoolsStorage } from '@/contexts/stakingPoolsStorage'; -import { ConnectedWalletType, WalletConnector } from '@/contexts/walletConnector'; -import { MOCK_CHAIN } from '@/misc/chainConfig'; -import { formatAddress } from '@/misc/formatting'; -import { WalletOutlined } from '@ant-design/icons'; -import { ConnectButton } from '@rainbow-me/rainbowkit'; -import { Button, Modal } from 'antd'; -import Image from 'next/image'; -import { useEffect, useState } from 'react'; -import ArrowBack from '../assets/svgs/arrow-back-white.svg' -import ArrowNext from '../assets/svgs/arrow-next-black.svg' -import Logo from '../assets/svgs/logo.svg' - +import LoginView from "@/components/loginView" +import StakingPoolDetailsView from "@/components/stakingPoolDetailsView" +import StakingPoolsList from "@/components/stakingPoolsList" +import WithdrawZilView from "@/components/withdrawZilView" +import { AppConfigStorage } from "@/contexts/appConfigStorage" +import { StakingOperations } from "@/contexts/stakingOperations" +import { StakingPoolsStorage } from "@/contexts/stakingPoolsStorage" +import { + ConnectedWalletType, + WalletConnector, +} from "@/contexts/walletConnector" +import { MOCK_CHAIN } from "@/misc/chainConfig" +import { formatAddress } from "@/misc/formatting" +import { WalletOutlined } from "@ant-design/icons" +import { ConnectButton } from "@rainbow-me/rainbowkit" +import { Button, Modal } from "antd" +import Image from "next/image" +import { useEffect, useState } from "react" +import ArrowBack from "../assets/svgs/arrow-back-white.svg" +import ArrowNext from "../assets/svgs/arrow-next-black.svg" +import Logo from "../assets/svgs/logo.svg" const HomePage = () => { - - const [isVisible, setIsVisible] = useState(false); + const [isVisible, setIsVisible] = useState(false) useEffect(() => { - setIsVisible(true); - }, []); + setIsVisible(true) + }, []) - const { - appConfig - } = AppConfigStorage.useContainer(); + const { appConfig } = AppConfigStorage.useContainer() const { connectDummyWallet, @@ -37,13 +36,13 @@ const HomePage = () => { walletAddress, disconnectDummyWallet, connectedWalletType, - } = WalletConnector.useContainer(); + } = WalletConnector.useContainer() const { dummyWalletPopupContent, isDummyWalletPopupOpen, setIsDummyWalletPopupOpen, - } = StakingOperations.useContainer(); + } = StakingOperations.useContainer() const { stakingPoolForView, @@ -51,180 +50,191 @@ const HomePage = () => { selectStakingPoolForView, availableForUnstaking, pendingUnstaking, - } = StakingPoolsStorage.useContainer(); + } = StakingPoolsStorage.useContainer() - const [mobileShowClaims, setMobileShowClaims] = useState(false); + const [mobileShowClaims, setMobileShowClaims] = useState(false) const mobileOverlayWrapper = (children: React.ReactNode) => ( -
+
{children}
) const desktopColumnContent = (
- { - !isWalletConnected && !stakingPoolForView ? ( - - ) : stakingPoolForView ? ( -
- { - selectStakingPoolForView(null); - selectStakingPoolForStaking(stakingPoolId); - }} - stakingPoolData={stakingPoolForView.stakingPool} - userStakingPoolData={stakingPoolForView.userData.staked} - userUnstakingPoolData={stakingPoolForView.userData.unstaked} - /> -
- ) : ( - - ) - } + {!isWalletConnected && !stakingPoolForView ? ( + + ) : stakingPoolForView ? ( +
+ { + selectStakingPoolForView(null) + selectStakingPoolForStaking(stakingPoolId) + }} + stakingPoolData={stakingPoolForView.stakingPool} + userStakingPoolData={stakingPoolForView.userData.staked} + userUnstakingPoolData={stakingPoolForView.userData.unstaked} + /> +
+ ) : ( + + )}
) const mobileOverlayContent = mobileShowClaims ? mobileOverlayWrapper() - : stakingPoolForView && mobileOverlayWrapper( - { - selectStakingPoolForView(null); - selectStakingPoolForStaking(stakingPoolId); - }} - stakingPoolData={stakingPoolForView.stakingPool} - userStakingPoolData={stakingPoolForView.userData.staked} - userUnstakingPoolData={stakingPoolForView.userData.unstaked} - /> - ) + : stakingPoolForView && + mobileOverlayWrapper( + { + selectStakingPoolForView(null) + selectStakingPoolForStaking(stakingPoolId) + }} + stakingPoolData={stakingPoolForView.stakingPool} + userStakingPoolData={stakingPoolForView.userData.staked} + userUnstakingPoolData={stakingPoolForView.userData.unstaked} + /> + ) - const connectWallet = appConfig.chainId === MOCK_CHAIN.id ? ( - - ) : ( - - ) + + ) : ( + + ) const mobileBottomNavition = ( -
-
- { - isWalletConnected ? ( +
+
+ {isWalletConnected ? ( <> - { - mobileShowClaims && ( -
-
- ) - } - { - !mobileShowClaims && stakingPoolForView && ( -
+ {mobileShowClaims && ( +
- ) - } - - { - !mobileShowClaims && availableForUnstaking.length + pendingUnstaking.length != 0 && ( -
+ /> + {stakingPoolForView + ? stakingPoolForView?.stakingPool.definition.name + : "Back"} + +
+ )} + {!mobileShowClaims && stakingPoolForView && ( +
+
+ )} + + {!mobileShowClaims && + availableForUnstaking.length + pendingUnstaking.length != 0 && ( +
+
- ) - } + )} ) : ( - <> - { stakingPoolForView && ( -
-
- ) } -
- {connectWallet} -
- - - ) - } -
+ <> + {stakingPoolForView && ( +
+ +
+ )} +
+ {connectWallet} +
+ + )} +
+
) return ( -
- +
{/* Header */}
-
{
- { - !isWalletConnected ? ( - connectWallet - ) : ( - <> - { - connectedWalletType === ConnectedWalletType.MockWallet ? ( - - - - ) : ( - - ) - } - - ) - } + {!isWalletConnected ? ( + connectWallet + ) : ( + <> + {connectedWalletType === ConnectedWalletType.MockWallet ? ( + + ) : ( + + )} + + )}
-
-
- {/* Left column */} -
- -
+
+
+ {/* Left column */} +
+ +
- { desktopColumnContent } + {desktopColumnContent} - { mobileOverlayContent } - { mobileBottomNavition } + {mobileOverlayContent} + {mobileBottomNavition}
setIsDummyWalletPopupOpen(false)} onCancel={() => setIsDummyWalletPopupOpen(false)} > -
- {dummyWalletPopupContent} -
+
{dummyWalletPopupContent}
-
- ); -}; + ) +} -export default HomePage; +export default HomePage diff --git a/src/script/fetchPoolStaticData.ts b/src/script/fetchPoolStaticData.ts index e8a25d5..8a011a4 100644 --- a/src/script/fetchPoolStaticData.ts +++ b/src/script/fetchPoolStaticData.ts @@ -1,27 +1,28 @@ -import yargs from 'yargs/yargs'; -import { hideBin } from 'yargs/helpers'; -import { readContract } from 'viem/actions'; -import { delegatorAbi } from '@/misc/stakingAbis'; -import { Address, erc20Abi } from 'viem'; -import { getViemClient } from '@/misc/chainConfig'; -import { StakingPoolDefinition } from '@/misc/stakingPoolsConfig'; +import yargs from "yargs/yargs" +import { hideBin } from "yargs/helpers" +import { readContract } from "viem/actions" +import { delegatorAbi } from "@/misc/stakingAbis" +import { Address, erc20Abi } from "viem" +import { getViemClient } from "@/misc/chainConfig" +import { StakingPoolDefinition } from "@/misc/stakingPoolsConfig" interface Args { - network_id: string; - contract_address: string; - icon_url: string; - name: string; + network_id: string + contract_address: string + icon_url: string + name: string } const argv = yargs(hideBin(process.argv)) - .option('network_id', { - type: 'string', - description: 'The network id of the network to connect to. It must be defined in chainConfig.ts', + .option("network_id", { + type: "string", + description: + "The network id of the network to connect to. It must be defined in chainConfig.ts", demandOption: true, }) - .option('contract_address', { - type: 'string', - description: 'The contract address in hex format', + .option("contract_address", { + type: "string", + description: "The contract address in hex format", demandOption: true, }) .option("icon_url", { @@ -29,70 +30,63 @@ const argv = yargs(hideBin(process.argv)) description: "The icon url of the pool", demandOption: true, }) - .option('name', { - type: 'string', - description: 'The name of the pool', + .option("name", { + type: "string", + description: "The name of the pool", demandOption: true, - }) + }) .help() - .alias('help', 'h') - .argv as Args; + .alias("help", "h").argv as Args -( - async () => { - console.log(`Network RPC URL: ${argv.network_id}`); - console.log(`Contract Address: ${argv.contract_address}`); +;(async () => { + console.log(`Network RPC URL: ${argv.network_id}`) + console.log(`Contract Address: ${argv.contract_address}`) + const chainid = parseInt(argv.network_id) - const chainid = parseInt(argv.network_id); - - const readDelegatorContract = async (functionName: string): Promise => { - return (await readContract(getViemClient(chainid), { - address: argv.contract_address as Address, - abi: delegatorAbi, - functionName, - })) as T - } - - const [tokenAddress] = await Promise.all([ - readDelegatorContract
("getLST"), - ]); + const readDelegatorContract = async (functionName: string): Promise => { + return (await readContract(getViemClient(chainid), { + address: argv.contract_address as Address, + abi: delegatorAbi, + functionName, + })) as T + } - const readTokenContract = async (functionName: string): Promise => { - return await (readContract(getViemClient(chainid), { - address: tokenAddress, - abi: erc20Abi, - functionName: "decimals", - })) as T - } + const [tokenAddress] = await Promise.all([ + readDelegatorContract
("getLST"), + ]) - const [ - tokenDecimals, - tokenSymbol, - minimumStake, - ] = await Promise.all([ - readTokenContract("decimals"), - readTokenContract("symbol"), - readDelegatorContract("getMinDelegation") - ]); + const readTokenContract = async (functionName: string): Promise => { + return (await readContract(getViemClient(chainid), { + address: tokenAddress, + abi: erc20Abi, + functionName: "decimals", + })) as T + } - const hash = Buffer.from(argv.contract_address + tokenAddress).toString('base64').slice(0, 8); - const twoWeeksInMinutes = 60 * 24 * 14; + const [tokenDecimals, tokenSymbol, minimumStake] = await Promise.all([ + readTokenContract("decimals"), + readTokenContract("symbol"), + readDelegatorContract("getMinDelegation"), + ]) - const definition: StakingPoolDefinition = { - id: hash, - address: argv.contract_address, - tokenAddress, - iconUrl: argv.icon_url, - name: argv.name, - tokenDecimals, - tokenSymbol, - minimumStake: minimumStake as bigint, - withdrawPeriodInMinutes: twoWeeksInMinutes, - } + const hash = Buffer.from(argv.contract_address + tokenAddress) + .toString("base64") + .slice(0, 8) + const twoWeeksInMinutes = 60 * 24 * 14 - console.log("Add following definition to stakingPoolsConfig.ts"); - console.log({ definition, }); + const definition: StakingPoolDefinition = { + id: hash, + address: argv.contract_address, + tokenAddress, + iconUrl: argv.icon_url, + name: argv.name, + tokenDecimals, + tokenSymbol, + minimumStake: minimumStake as bigint, + withdrawPeriodInMinutes: twoWeeksInMinutes, } -)(); + console.log("Add following definition to stakingPoolsConfig.ts") + console.log({ definition }) +})() diff --git a/src/styles/globals.css b/src/styles/globals.css index 09a262d..5672862 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -24,7 +24,7 @@ body { rgb(var(--background-end-rgb)) ) rgb(var(--background-start-rgb)); - font-family: "Montserrat", sans-serif; + font-family: "Montserrat", sans-serif; } @layer utilities { @@ -158,7 +158,7 @@ body { } .base-medium { - @apply font-medium text-12 lg:text-13 leading-5 lg:leading-6 text-white3 ; + @apply font-medium text-12 lg:text-13 leading-5 lg:leading-6 text-white3; } .regular-base { @@ -204,7 +204,6 @@ body { @apply h3 text-18 lg:text-20 xl:text-26 leading-8 lg:leading-10 text-gray3; } - .h3-s { @apply font-extrabold text-12 lg:text-27 leading-6 lg:leading-10 text-white1; } @@ -225,27 +224,17 @@ body { @apply hover:opacity-70 duration-300 ease-in-out; } - - .text-22-bold { @apply font-bold text-18 lg:text-22 leading-4 lg:leading-6 text-white2; } - - .text-12-regular { - @apply font-medium text-11 lg:text-12 lg:leading-4 text-white3 ; + .text-12-regular { + @apply font-medium text-11 lg:text-12 lg:leading-4 text-white3; } - } .animated-gradient { - background: linear-gradient( - -45deg, - #ee7752, - #e73c7e, - #23a6d5, - #23d5ab - ); + background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); background-size: 400% 400%; animation: gradientAnimation 2s ease infinite; border-radius: 10px; @@ -282,7 +271,7 @@ body { } .gradient-bottom-border::before { - content: ''; + content: ""; position: absolute; top: 0px; left: 0px; @@ -316,7 +305,7 @@ body { position: relative; } .gradient-bottom-border-hover:hover::before { - content: ''; + content: ""; position: absolute; top: 0px; left: 0px; @@ -405,9 +394,9 @@ body { :where(.css-dev-only-do-not-override-1wwf28x).ant-input-affix-wrapper .ant-input-prefix { margin-right: 0.5rem; - color: #F1F4F4 !important; + color: #f1f4f4 !important; @media (min-width: 1024px) { margin-right: 1rem; } -} \ No newline at end of file +} diff --git a/tailwind.config.ts b/tailwind.config.ts index c723b1d..edcc3eb 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,4 +1,4 @@ -import type { Config } from "tailwindcss"; +import type { Config } from "tailwindcss" const config: Config = { content: [ @@ -6,98 +6,99 @@ const config: Config = { "./src/components/**/*.{js,ts,jsx,tsx,mdx}", "./src/app/**/*.{js,ts,jsx,tsx,mdx}", ], - safelist: [ - 'h3-inactive', - ], + safelist: ["h3-inactive"], theme: { extend: { backgroundImage: { "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", "gradient-conic": - "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", - 'primary-gradient' : 'radial-gradient(120.62% 683.52% at 110.84% 156.15%, #C5FFFD 6.84%, rgba(111, 255, 194, 0.760784) 48.36%, #00DABA 100%)', - 'gradientbg': 'linear-gradient(129.93deg, rgba(175, 175, 175, 0.12) 16.6%, rgba(17, 243, 179, 0.12) 90.65%)', - 'darkbg': 'linear-gradient(314.92deg, rgba(17, 39, 49, 0.4) 28.08%, rgba(9, 9, 9, 0.4) 97.04%)', - 'colorful-gradient':'linear-gradient(270deg, #00DABA 8%, #4AA1A3 23%, #8A7191 36%, #B15485 46%, #C14981 51%, #A73993 62%, #8726AA 78%, #741BB7 91%, #6D17BD 100%)', - - }, - colors: { - black1: '#010101', - black2: '#202025', - - gray1: '#555555', - gray2: '#454545', - gray3: '#706F6F', - gray4: '#4B4B4B', - gray5: '#AEAEAE', + "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", + "primary-gradient": + "radial-gradient(120.62% 683.52% at 110.84% 156.15%, #C5FFFD 6.84%, rgba(111, 255, 194, 0.760784) 48.36%, #00DABA 100%)", + gradientbg: + "linear-gradient(129.93deg, rgba(175, 175, 175, 0.12) 16.6%, rgba(17, 243, 179, 0.12) 90.65%)", + darkbg: + "linear-gradient(314.92deg, rgba(17, 39, 49, 0.4) 28.08%, rgba(9, 9, 9, 0.4) 97.04%)", + "colorful-gradient": + "linear-gradient(270deg, #00DABA 8%, #4AA1A3 23%, #8A7191 36%, #B15485 46%, #C14981 51%, #A73993 62%, #8726AA 78%, #741BB7 91%, #6D17BD 100%)", + }, + colors: { + black1: "#010101", + black2: "#202025", + + gray1: "#555555", + gray2: "#454545", + gray3: "#706F6F", + gray4: "#4B4B4B", + gray5: "#AEAEAE", + + white1: "#F1F4F4", + white2: "#F7FBFA", + white3: "#E1E2E2", + + blue1: "#1966F7", - white1: '#F1F4F4', - white2: '#F7FBFA', - white3: '#E1E2E2', - - blue1: '#1966F7', + aqua1: "#00D0C6", + aqua2: "#6DD3C2", + aqua3: "#BCE6EC", - aqua1: '#00D0C6', - aqua2: '#6DD3C2', - aqua3:'#BCE6EC', - - purple1:'#7839FF', - purple2:'#B9A9FB', + purple1: "#7839FF", + purple2: "#B9A9FB", - orange1:'#FE9950', + orange1: "#FE9950", - red1:'#D92D20', - red2: '#FF4A4A' + red1: "#D92D20", + red2: "#FF4A4A", + }, + fontSize: { + "10": "10px", + "12": "12px", + "14": "14px", + "13": "13px", + "15": "15px", + "16": "16px", + "17": "17px", + "18": "18px", + "20": "20px", + "22": "22px", + "24": "24px", + "26": "26px", + "27": "27px", + "30": "30px", + "32": "32px", + "38": "38px", + "40": "40px", + "48": "48px", + "64": "64px", + "80": "80px", + "114": "114px", }, - fontSize:{ - '10': '10px', - '12': '12px', - '14': '14px', - '13': '13px', - '15': '15px', - '16': '16px', - '17': '17px', - '18': '18px', - '20': '20px', - '22': '22px', - '24': '24px', - '26': '26px', - '27': '27px', - '30': '30px', - '32': '32px', - '38': '38px', - '40': '40px', - '48': '48px', - '64': '64px', - '80': '80px', - '114': '114px' - }, borderRadius: { - '10': "10px", - '2.5xl' : '1.25rem' - }, - lineHeight:{ - '11': '44px', - '12': '48px', - '16': '64px', - '20': '80px', - }, - padding:{ - '7.5': '30px', - '4.5': '18px', - '21': '84px' + "10": "10px", + "2.5xl": "1.25rem", + }, + lineHeight: { + "11": "44px", + "12": "48px", + "16": "64px", + "20": "80px", + }, + padding: { + "7.5": "30px", + "4.5": "18px", + "21": "84px", + }, + margin: { + "7.5": "30px", + "4.5": "18px", + "12.5": "50px", + "21": "84px", }, - margin:{ - '7.5': '30px', - '4.5': '18px', - '12.5': '50px', - '21': '84px', + screens: { + xs: "450px", }, - screens:{ - xs: '450px' - } }, }, plugins: [], -}; -export default config; +} +export default config