diff --git a/.github/workflows/ci-js.yml b/.github/workflows/ci-js.yml index 1c8f6951..12952ec1 100644 --- a/.github/workflows/ci-js.yml +++ b/.github/workflows/ci-js.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x, 17.x] + node-version: [18.x] target: [client, server] steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 30de94e6..30aa8d00 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -71,6 +71,15 @@ jobs: run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache + # TEMP fix + # Something strange is happening with the manifests when we push which + # breaks the downstream multi-arch-manifest, so pull and push to work + # around this by resubmitting manifests + - name: pull-and-push + run: | + for t in `echo '${{ steps.meta-arch.outputs.tags }}'`; do + docker pull $t && docker push $t + done build-arm64: runs-on: self-hosted @@ -131,6 +140,15 @@ jobs: run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache + # TEMP fix + # Something strange is happening with the manifests when we push which + # breaks the downstream multi-arch-manifest, so pull and push to work + # around this by resubmitting manifests + - name: pull-and-push + run: | + for t in `echo '${{ steps.meta-arch.outputs.tags }}'`; do + docker pull $t && docker push $t + done multi-arch-manifest: runs-on: ubuntu-latest diff --git a/Dockerfile b/Dockerfile index c4ff251b..5fd2e0fa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16 AS base +FROM node:18 AS base FROM base AS builder WORKDIR /code/client @@ -11,11 +11,15 @@ RUN npm run build FROM base AS final WORKDIR /app COPY --from=builder /code/server/index.ts /code/server/package.json /code/server/tsconfig.json ./server/ +COPY --from=builder /code/server/routes ./server/routes/ +COPY --from=builder /code/server/service ./server/service/ +COPY --from=builder /code/server/types ./server/types/ COPY --from=builder /code/server/utils ./server/utils/ +COPY --from=builder /code/server/middlewares ./server/middlewares/ COPY --from=builder /code/server/public ./server/public/ COPY --from=builder /code/server/node_modules ./server/node_modules/ COPY --from=builder /code/client/src/entities/ ./client/src/entities/ COPY --from=builder /code/client/src/services/ ./client/src/services/ COPY --from=builder /code/client/build/ ./client/build/ COPY --chmod=555 docker-entrypoint.sh . -ENTRYPOINT ["/app/docker-entrypoint.sh"] +ENTRYPOINT ["/app/docker-entrypoint.sh"] \ No newline at end of file diff --git a/client/package-lock.json b/client/package-lock.json index b0ec04b2..0209d1e1 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,15 +8,15 @@ "name": "tosidrop-client", "version": "1.0.0", "dependencies": { - "@emurgo/cardano-serialization-lib-asmjs": "^11.1.0", + "@emurgo/cardano-serialization-lib-asmjs": "^11.3.0", "@emurgo/cip14-js": "^3.0.1", - "@fortawesome/fontawesome-common-types": "^6.1.1", - "@fortawesome/fontawesome-svg-core": "^6.1.1", - "@fortawesome/free-brands-svg-icons": "^6.1.1", - "@fortawesome/free-solid-svg-icons": "^6.1.1", - "@fortawesome/react-fontawesome": "^0.1.18", - "@reduxjs/toolkit": "^1.8.1", - "@types/node": "^16.11.25", + "@fortawesome/fontawesome-common-types": "^6.3.0", + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-brands-svg-icons": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@fortawesome/react-fontawesome": "^0.2.0", + "@reduxjs/toolkit": "^1.9.3", + "@types/node": "^18.14.1", "@types/react": "^17.0.39", "@types/react-dom": "^17.0.11", "axios": "^0.27.2", @@ -26,25 +26,25 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-native": "^0.67.4", - "react-qr-code": "^2.0.5", + "react-qr-code": "^2.0.11", "react-redux": "^8.0.0", - "react-router-dom": "^6.2.2", - "react-scripts": "5.0.0", + "react-router-dom": "^6.8.1", + "react-scripts": "^5.0.1", "react-simple-tooltip": "^2.6.3", - "react-spinners": "^0.11.0", - "sass": "^1.49.9", + "react-spinners": "^0.13.8", + "sass": "^1.58.3", "ts-node": "^10.7.0", - "typescript": "^4.5.5", - "web-vitals": "^2.1.4" + "typescript": "^4.9.5", + "web-vitals": "^3.1.1" }, "devDependencies": { - "autoprefixer": "^9.8.8", - "postcss": "^8.4.14", - "tailwindcss": "^3.1.6" + "autoprefixer": "^10.4.13", + "postcss": "^8.4.21", + "tailwindcss": "^3.2.7" }, "engines": { - "node": ">=16", - "npm": ">=8" + "node": ">=18", + "npm": ">=9" } }, "node_modules/@ampproject/remapping": { @@ -2368,79 +2368,6 @@ "postcss-selector-parser": "^6.0.10" } }, - "node_modules/@emotion/babel-plugin": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz", - "integrity": "sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.17.12", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/serialize": "^1.1.1", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.1.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/@emotion/hash": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" - }, - "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" - }, - "node_modules/@emotion/babel-plugin/node_modules/@emotion/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", - "dependencies": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" - }, - "node_modules/@emotion/babel-plugin/node_modules/@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" - }, - "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@emotion/babel-plugin/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@emotion/cache": { "version": "10.0.29", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", @@ -2488,87 +2415,6 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" }, - "node_modules/@emotion/react": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.5.tgz", - "integrity": "sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.10.5", - "@emotion/cache": "^11.10.5", - "@emotion/serialize": "^1.1.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/react/node_modules/@emotion/cache": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", - "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", - "dependencies": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.1", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.1.3" - } - }, - "node_modules/@emotion/react/node_modules/@emotion/hash": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" - }, - "node_modules/@emotion/react/node_modules/@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" - }, - "node_modules/@emotion/react/node_modules/@emotion/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", - "dependencies": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/react/node_modules/@emotion/sheet": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" - }, - "node_modules/@emotion/react/node_modules/@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" - }, - "node_modules/@emotion/react/node_modules/@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" - }, - "node_modules/@emotion/react/node_modules/@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" - }, "node_modules/@emotion/serialize": { "version": "0.11.16", "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", @@ -2601,14 +2447,6 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, - "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", - "peerDependencies": { - "react": ">=16.8.0" - } - }, "node_modules/@emotion/utils": { "version": "0.11.3", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", @@ -2620,9 +2458,9 @@ "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, "node_modules/@emurgo/cardano-serialization-lib-asmjs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-asmjs/-/cardano-serialization-lib-asmjs-11.1.0.tgz", - "integrity": "sha512-wxF/Yle0HBCs19bDue+zpG8pRTP0iZk90TTNX3VfsAUmIRbP2GqheEN6Uwsd0kfCdwkRbOZCSEb7+QLJ6MOCPg==" + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-asmjs/-/cardano-serialization-lib-asmjs-11.3.0.tgz", + "integrity": "sha512-81KVs/LitQF7WVeCe9FdFDaUSynZtyK7iqXToTpgiHOi/VVyEn9OkvU5WOzTehl6DfOwU1dx1xGopZsVqslZWw==" }, "node_modules/@emurgo/cip14-js": { "version": "3.0.1", @@ -2741,60 +2579,60 @@ } }, "node_modules/@fortawesome/fontawesome-common-types": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", - "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", + "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==", "hasInstallScript": true, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/fontawesome-svg-core": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz", - "integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz", + "integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-brands-svg-icons": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.1.tgz", - "integrity": "sha512-L8l4MfdHPmZlJ72PvzdfwOwbwcCAL0vx48tJRnI6u1PJXh+j2f3yDoKyQgO3qjEsgD5Fr2tQV/cPP8F/k6aUig==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.3.0.tgz", + "integrity": "sha512-xI0c+a8xnKItAXCN8rZgCNCJQiVAd2Y7p9e2ND6zN3J3ekneu96qrePieJ7yA7073C1JxxoM3vH1RU7rYsaj8w==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/free-solid-svg-icons": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz", - "integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz", + "integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==", "hasInstallScript": true, "dependencies": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" }, "engines": { "node": ">=6" } }, "node_modules/@fortawesome/react-fontawesome": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", - "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", "dependencies": { "prop-types": "^15.8.1" }, "peerDependencies": { "@fortawesome/fontawesome-svg-core": "~1 || ~6", - "react": ">=16.x" + "react": ">=16.3" } }, "node_modules/@hapi/hoek": { @@ -4013,9 +3851,9 @@ "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==" }, "node_modules/@reduxjs/toolkit": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.0.tgz", - "integrity": "sha512-ak11IrjYcUXRqlhNPwnz6AcvA2ynJTu8PzDbbqQw4a3xR4KZtgiqbNblQD+10CRbfK4+5C79SOyxnT9dhBqFnA==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz", + "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==", "dependencies": { "immer": "^9.0.16", "redux": "^4.2.0", @@ -4036,9 +3874,9 @@ } }, "node_modules/@remix-run/router": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.3.tgz", - "integrity": "sha512-ceuyTSs7PZ/tQqi19YZNBc5X7kj1f8p+4DIyrcIYFY9h+hd1OKm4RqtiWldR9eGEvIiJfsqwM4BsuCtRIuEw6Q==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", + "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==", "engines": { "node": ">=14" } @@ -4723,9 +4561,9 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "node_modules/@types/node": { - "version": "16.18.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz", - "integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==" + "version": "18.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.1.tgz", + "integrity": "sha512-QH+37Qds3E0eDlReeboBxfHbX9omAcBCXEzswCu6jySP642jiM3cYSIkU/REqwhCUqXdonHFuBfJDiAJxMNhaQ==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -5869,52 +5707,41 @@ } }, "node_modules/autoprefixer": { - "version": "9.8.8", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", - "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", - "dev": true, + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], "dependencies": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "picocolors": "^0.2.1", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" }, "bin": { "autoprefixer": "bin/autoprefixer" }, - "funding": { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - }, - "node_modules/autoprefixer/node_modules/postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "dependencies": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - }, "engines": { - "node": ">=6.0.0" + "node": "^10 || ^12 || >=14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/autoprefixer/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/autoprefixer/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/axe-core": { "version": "4.5.2", @@ -15556,12 +15383,6 @@ "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" }, - "node_modules/num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", - "dev": true - }, "node_modules/nwsapi": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", @@ -16282,9 +16103,9 @@ } }, "node_modules/postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "funding": [ { "type": "opencollective", @@ -17342,43 +17163,6 @@ "postcss": "^8.2" } }, - "node_modules/postcss-preset-env/node_modules/autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-preset-env/node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, "node_modules/postcss-pseudo-class-any-link": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", @@ -18167,9 +17951,9 @@ } }, "node_modules/react-qr-code": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.8.tgz", - "integrity": "sha512-zYO9EAPQU8IIeD6c6uAle7NlKOiVKs8ji9hpbWPTGxO+FLqBN2on+XCXQvnhm91nrRd306RvNXUkUNcXXSfhWA==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.11.tgz", + "integrity": "sha512-P7mvVM5vk9NjGdHMt4Z0KWeeJYwRAtonHTghZT2r+AASinLUUKQ9wfsGH2lPKsT++gps7hXmaiMGRvwTDEL9OA==", "dependencies": { "prop-types": "^15.8.1", "qr.js": "0.0.0" @@ -18236,11 +18020,11 @@ } }, "node_modules/react-router": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.3.tgz", - "integrity": "sha512-BT6DoGn6aV1FVP5yfODMOiieakp3z46P1Fk0RNzJMACzE7C339sFuHebfvWtnB4pzBvXXkHP2vscJzWRuUjTtA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz", + "integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==", "dependencies": { - "@remix-run/router": "1.0.3" + "@remix-run/router": "1.3.2" }, "engines": { "node": ">=14" @@ -18250,12 +18034,12 @@ } }, "node_modules/react-router-dom": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.3.tgz", - "integrity": "sha512-MiaYQU8CwVCaOfJdYvt84KQNjT78VF0TJrA17SIQgNHRvLnXDJO6qsFqq8F/zzB1BWZjCFIrQpu4QxcshitziQ==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz", + "integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==", "dependencies": { - "@remix-run/router": "1.0.3", - "react-router": "6.4.3" + "@remix-run/router": "1.3.2", + "react-router": "6.8.1" }, "engines": { "node": ">=14" @@ -18266,9 +18050,9 @@ } }, "node_modules/react-scripts": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz", - "integrity": "sha512-3i0L2CyIlROz7mxETEdfif6Sfhh9Lfpzi10CtcGs1emDQStmZfWjJbAIMtRD0opVUjQuFWqHZyRZ9PPzKCFxWg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", "dependencies": { "@babel/core": "^7.16.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", @@ -18286,7 +18070,7 @@ "dotenv": "^10.0.0", "dotenv-expand": "^5.1.0", "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.0", + "eslint-config-react-app": "^7.0.1", "eslint-webpack-plugin": "^3.1.1", "file-loader": "^6.2.0", "fs-extra": "^10.0.0", @@ -18303,7 +18087,7 @@ "postcss-preset-env": "^7.0.1", "prompts": "^2.4.2", "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.0", + "react-dev-utils": "^12.0.1", "react-refresh": "^0.11.0", "resolve": "^1.20.0", "resolve-url-loader": "^4.0.0", @@ -18526,15 +18310,12 @@ } }, "node_modules/react-spinners": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.11.0.tgz", - "integrity": "sha512-rDZc0ABWn/M1OryboGsWVmIPg8uYWl0L35jPUhr40+Yg+syVPjeHwvnB7XWaRpaKus3M0cG9BiJA+ZB0dAwWyw==", - "dependencies": { - "@emotion/react": "^11.1.4" - }, + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz", + "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", "peerDependencies": { - "react": "^16.0.0 || ^17.0.0", - "react-dom": "^16.0.0 || ^17.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/read-cache": { @@ -19251,9 +19032,9 @@ "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, "node_modules/sass": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", - "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", + "version": "1.58.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.3.tgz", + "integrity": "sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -20398,11 +20179,6 @@ "postcss": "^8.2.15" } }, - "node_modules/stylis": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", - "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" - }, "node_modules/sudo-prompt": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz", @@ -20589,9 +20365,9 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "node_modules/tailwindcss": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz", - "integrity": "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.7.tgz", + "integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==", "dependencies": { "arg": "^5.0.2", "chokidar": "^3.5.3", @@ -20607,12 +20383,12 @@ "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.18", + "postcss": "^8.0.9", "postcss-import": "^14.1.0", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.4", "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.10", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", "resolve": "^1.22.1" @@ -21119,9 +20895,9 @@ } }, "node_modules/typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -21529,9 +21305,9 @@ } }, "node_modules/web-vitals": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", - "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.1.1.tgz", + "integrity": "sha512-qvllU+ZeQChqzBhZ1oyXmWsjJ8a2jHYpH8AMaVuf29yscOPZfTQTjQFRX6+eADTdsDE8IanOZ0cetweHMs8/2A==" }, "node_modules/webidl-conversions": { "version": "6.1.0", @@ -24019,69 +23795,6 @@ "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", "requires": {} }, - "@emotion/babel-plugin": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz", - "integrity": "sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==", - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/plugin-syntax-jsx": "^7.17.12", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/serialize": "^1.1.1", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.1.3" - }, - "dependencies": { - "@emotion/hash": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" - }, - "@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" - }, - "@emotion/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", - "requires": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", - "csstype": "^3.0.2" - } - }, - "@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" - }, - "@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - } - } - }, "@emotion/cache": { "version": "10.0.29", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", @@ -24126,77 +23839,6 @@ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" }, - "@emotion/react": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.5.tgz", - "integrity": "sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==", - "requires": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.10.5", - "@emotion/cache": "^11.10.5", - "@emotion/serialize": "^1.1.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "hoist-non-react-statics": "^3.3.1" - }, - "dependencies": { - "@emotion/cache": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", - "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", - "requires": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.1", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.1.3" - } - }, - "@emotion/hash": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" - }, - "@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" - }, - "@emotion/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", - "requires": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", - "csstype": "^3.0.2" - } - }, - "@emotion/sheet": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" - }, - "@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" - }, - "@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" - }, - "@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" - } - } - }, "@emotion/serialize": { "version": "0.11.16", "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", @@ -24231,12 +23873,6 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" }, - "@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", - "requires": {} - }, "@emotion/utils": { "version": "0.11.3", "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", @@ -24248,9 +23884,9 @@ "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, "@emurgo/cardano-serialization-lib-asmjs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-asmjs/-/cardano-serialization-lib-asmjs-11.1.0.tgz", - "integrity": "sha512-wxF/Yle0HBCs19bDue+zpG8pRTP0iZk90TTNX3VfsAUmIRbP2GqheEN6Uwsd0kfCdwkRbOZCSEb7+QLJ6MOCPg==" + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-asmjs/-/cardano-serialization-lib-asmjs-11.3.0.tgz", + "integrity": "sha512-81KVs/LitQF7WVeCe9FdFDaUSynZtyK7iqXToTpgiHOi/VVyEn9OkvU5WOzTehl6DfOwU1dx1xGopZsVqslZWw==" }, "@emurgo/cip14-js": { "version": "3.0.1", @@ -24333,38 +23969,38 @@ } }, "@fortawesome/fontawesome-common-types": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", - "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz", + "integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg==" }, "@fortawesome/fontawesome-svg-core": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz", - "integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz", + "integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==", "requires": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" } }, "@fortawesome/free-brands-svg-icons": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.1.tgz", - "integrity": "sha512-L8l4MfdHPmZlJ72PvzdfwOwbwcCAL0vx48tJRnI6u1PJXh+j2f3yDoKyQgO3qjEsgD5Fr2tQV/cPP8F/k6aUig==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.3.0.tgz", + "integrity": "sha512-xI0c+a8xnKItAXCN8rZgCNCJQiVAd2Y7p9e2ND6zN3J3ekneu96qrePieJ7yA7073C1JxxoM3vH1RU7rYsaj8w==", "requires": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" } }, "@fortawesome/free-solid-svg-icons": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz", - "integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz", + "integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==", "requires": { - "@fortawesome/fontawesome-common-types": "6.2.1" + "@fortawesome/fontawesome-common-types": "6.3.0" } }, "@fortawesome/react-fontawesome": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.19.tgz", - "integrity": "sha512-Hyb+lB8T18cvLNX0S3llz7PcSOAJMLwiVKBuuzwM/nI5uoBw+gQjnf9il0fR1C3DKOI5Kc79pkJ4/xB0Uw9aFQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", + "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", "requires": { "prop-types": "^15.8.1" } @@ -25336,9 +24972,9 @@ "integrity": "sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==" }, "@reduxjs/toolkit": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.0.tgz", - "integrity": "sha512-ak11IrjYcUXRqlhNPwnz6AcvA2ynJTu8PzDbbqQw4a3xR4KZtgiqbNblQD+10CRbfK4+5C79SOyxnT9dhBqFnA==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.9.3.tgz", + "integrity": "sha512-GU2TNBQVofL09VGmuSioNPQIu6Ml0YLf4EJhgj0AvBadRlCGzUWet8372LjvO4fqKZF2vH1xU0htAa7BrK9pZg==", "requires": { "immer": "^9.0.16", "redux": "^4.2.0", @@ -25347,9 +24983,9 @@ } }, "@remix-run/router": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.0.3.tgz", - "integrity": "sha512-ceuyTSs7PZ/tQqi19YZNBc5X7kj1f8p+4DIyrcIYFY9h+hd1OKm4RqtiWldR9eGEvIiJfsqwM4BsuCtRIuEw6Q==" + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.2.tgz", + "integrity": "sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==" }, "@rollup/plugin-babel": { "version": "5.3.1", @@ -25865,9 +25501,9 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "@types/node": { - "version": "16.18.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.3.tgz", - "integrity": "sha512-jh6m0QUhIRcZpNv7Z/rpN+ZWXOicUUQbSoWks7Htkbb9IjFQj4kzcX/xFCkjstCj5flMsN8FiSvt+q+Tcs4Llg==" + "version": "18.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.1.tgz", + "integrity": "sha512-QH+37Qds3E0eDlReeboBxfHbX9omAcBCXEzswCu6jySP642jiM3cYSIkU/REqwhCUqXdonHFuBfJDiAJxMNhaQ==" }, "@types/parse-json": { "version": "4.0.0", @@ -26724,35 +26360,22 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, "autoprefixer": { - "version": "9.8.8", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz", - "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==", - "dev": true, + "version": "10.4.13", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", + "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", "requires": { - "browserslist": "^4.12.0", - "caniuse-lite": "^1.0.30001109", + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001426", + "fraction.js": "^4.2.0", "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "picocolors": "^0.2.1", - "postcss": "^7.0.32", - "postcss-value-parser": "^4.1.0" + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" }, "dependencies": { - "postcss": { - "version": "7.0.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz", - "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==", - "dev": true, - "requires": { - "picocolors": "^0.2.1", - "source-map": "^0.6.1" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" } } }, @@ -33895,12 +33518,6 @@ "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", - "dev": true - }, "nwsapi": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", @@ -34435,9 +34052,9 @@ "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==" }, "postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -35029,26 +34646,6 @@ "postcss-replace-overflow-wrap": "^4.0.0", "postcss-selector-not": "^6.0.1", "postcss-value-parser": "^4.2.0" - }, - "dependencies": { - "autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", - "requires": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - } } }, "postcss-pseudo-class-any-link": { @@ -35615,9 +35212,9 @@ } }, "react-qr-code": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.8.tgz", - "integrity": "sha512-zYO9EAPQU8IIeD6c6uAle7NlKOiVKs8ji9hpbWPTGxO+FLqBN2on+XCXQvnhm91nrRd306RvNXUkUNcXXSfhWA==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.11.tgz", + "integrity": "sha512-P7mvVM5vk9NjGdHMt4Z0KWeeJYwRAtonHTghZT2r+AASinLUUKQ9wfsGH2lPKsT++gps7hXmaiMGRvwTDEL9OA==", "requires": { "prop-types": "^15.8.1", "qr.js": "0.0.0" @@ -35649,26 +35246,26 @@ "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==" }, "react-router": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.4.3.tgz", - "integrity": "sha512-BT6DoGn6aV1FVP5yfODMOiieakp3z46P1Fk0RNzJMACzE7C339sFuHebfvWtnB4pzBvXXkHP2vscJzWRuUjTtA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz", + "integrity": "sha512-Jgi8BzAJQ8MkPt8ipXnR73rnD7EmZ0HFFb7jdQU24TynGW1Ooqin2KVDN9voSC+7xhqbbCd2cjGUepb6RObnyg==", "requires": { - "@remix-run/router": "1.0.3" + "@remix-run/router": "1.3.2" } }, "react-router-dom": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.4.3.tgz", - "integrity": "sha512-MiaYQU8CwVCaOfJdYvt84KQNjT78VF0TJrA17SIQgNHRvLnXDJO6qsFqq8F/zzB1BWZjCFIrQpu4QxcshitziQ==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.8.1.tgz", + "integrity": "sha512-67EXNfkQgf34P7+PSb6VlBuaacGhkKn3kpE51+P6zYSG2kiRoumXEL6e27zTa9+PGF2MNXbgIUHTVlleLbIcHQ==", "requires": { - "@remix-run/router": "1.0.3", - "react-router": "6.4.3" + "@remix-run/router": "1.3.2", + "react-router": "6.8.1" } }, "react-scripts": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz", - "integrity": "sha512-3i0L2CyIlROz7mxETEdfif6Sfhh9Lfpzi10CtcGs1emDQStmZfWjJbAIMtRD0opVUjQuFWqHZyRZ9PPzKCFxWg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", + "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", "requires": { "@babel/core": "^7.16.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", @@ -35686,7 +35283,7 @@ "dotenv": "^10.0.0", "dotenv-expand": "^5.1.0", "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.0", + "eslint-config-react-app": "^7.0.1", "eslint-webpack-plugin": "^3.1.1", "file-loader": "^6.2.0", "fs-extra": "^10.0.0", @@ -35704,7 +35301,7 @@ "postcss-preset-env": "^7.0.1", "prompts": "^2.4.2", "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.0", + "react-dev-utils": "^12.0.1", "react-refresh": "^0.11.0", "resolve": "^1.20.0", "resolve-url-loader": "^4.0.0", @@ -35827,12 +35424,10 @@ } }, "react-spinners": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.11.0.tgz", - "integrity": "sha512-rDZc0ABWn/M1OryboGsWVmIPg8uYWl0L35jPUhr40+Yg+syVPjeHwvnB7XWaRpaKus3M0cG9BiJA+ZB0dAwWyw==", - "requires": { - "@emotion/react": "^11.1.4" - } + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.13.8.tgz", + "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", + "requires": {} }, "read-cache": { "version": "1.0.0", @@ -36382,9 +35977,9 @@ "integrity": "sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==" }, "sass": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", - "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", + "version": "1.58.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.3.tgz", + "integrity": "sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A==", "requires": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -37256,11 +36851,6 @@ "postcss-selector-parser": "^6.0.4" } }, - "stylis": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", - "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" - }, "sudo-prompt": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/sudo-prompt/-/sudo-prompt-9.2.1.tgz", @@ -37414,9 +37004,9 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, "tailwindcss": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz", - "integrity": "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.7.tgz", + "integrity": "sha512-B6DLqJzc21x7wntlH/GsZwEXTBttVSl1FtCzC8WP4oBc/NKef7kaax5jeihkkCEWc831/5NDJ9gRNDK6NEioQQ==", "requires": { "arg": "^5.0.2", "chokidar": "^3.5.3", @@ -37432,12 +37022,12 @@ "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.18", + "postcss": "^8.0.9", "postcss-import": "^14.1.0", "postcss-js": "^4.0.0", "postcss-load-config": "^3.1.4", "postcss-nested": "6.0.0", - "postcss-selector-parser": "^6.0.10", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "quick-lru": "^5.1.1", "resolve": "^1.22.1" @@ -37794,9 +37384,9 @@ } }, "typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==" + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" }, "uglify-es": { "version": "3.3.9", @@ -38104,9 +37694,9 @@ } }, "web-vitals": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", - "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.1.1.tgz", + "integrity": "sha512-qvllU+ZeQChqzBhZ1oyXmWsjJ8a2jHYpH8AMaVuf29yscOPZfTQTjQFRX6+eADTdsDE8IanOZ0cetweHMs8/2A==" }, "webidl-conversions": { "version": "6.1.0", diff --git a/client/package.json b/client/package.json index 03cb51d6..037cae7f 100644 --- a/client/package.json +++ b/client/package.json @@ -3,19 +3,19 @@ "version": "1.0.0", "description": "TosiDrop Frontend React App", "engines": { - "node": ">=16", - "npm": ">=8" + "node": ">=18", + "npm": ">=9" }, "dependencies": { - "@emurgo/cardano-serialization-lib-asmjs": "^11.1.0", + "@emurgo/cardano-serialization-lib-asmjs": "^11.3.0", "@emurgo/cip14-js": "^3.0.1", - "@fortawesome/fontawesome-common-types": "^6.1.1", - "@fortawesome/fontawesome-svg-core": "^6.1.1", - "@fortawesome/free-brands-svg-icons": "^6.1.1", - "@fortawesome/free-solid-svg-icons": "^6.1.1", - "@fortawesome/react-fontawesome": "^0.1.18", - "@reduxjs/toolkit": "^1.8.1", - "@types/node": "^16.11.25", + "@fortawesome/fontawesome-common-types": "^6.3.0", + "@fortawesome/fontawesome-svg-core": "^6.3.0", + "@fortawesome/free-brands-svg-icons": "^6.3.0", + "@fortawesome/free-solid-svg-icons": "^6.3.0", + "@fortawesome/react-fontawesome": "^0.2.0", + "@reduxjs/toolkit": "^1.9.3", + "@types/node": "^18.14.1", "@types/react": "^17.0.39", "@types/react-dom": "^17.0.11", "axios": "^0.27.2", @@ -25,16 +25,16 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-native": "^0.67.4", - "react-qr-code": "^2.0.5", + "react-qr-code": "^2.0.11", "react-redux": "^8.0.0", - "react-router-dom": "^6.2.2", - "react-scripts": "5.0.0", + "react-router-dom": "^6.8.1", + "react-scripts": "^5.0.1", "react-simple-tooltip": "^2.6.3", - "react-spinners": "^0.11.0", - "sass": "^1.49.9", + "react-spinners": "^0.13.8", + "sass": "^1.58.3", "ts-node": "^10.7.0", - "typescript": "^4.5.5", - "web-vitals": "^2.1.4" + "typescript": "^4.9.5", + "web-vitals": "^3.1.1" }, "scripts": { "start": "PORT=3001 react-scripts --max-old-space-size=8192 start", @@ -64,8 +64,8 @@ ] }, "devDependencies": { - "autoprefixer": "^9.8.8", - "postcss": "^8.4.14", - "tailwindcss": "^3.1.6" + "autoprefixer": "^10.4.13", + "postcss": "^8.4.21", + "tailwindcss": "^3.2.7" } } diff --git a/client/src/App.tsx b/client/src/App.tsx index c7fc4c49..3c002f6d 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,5 +1,5 @@ -import { useEffect } from "react"; -import { useDispatch } from "react-redux"; +import { useCallback, useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; import { useLocation } from "react-router-dom"; import Footer from "src/components/Footer"; import Modal from "src/components/Modal"; @@ -13,10 +13,14 @@ import MenuWrapper from "./layouts/MenuWrapper"; import ThemeWrapper from "./layouts/ThemeWrapper"; import { setChain, setErgoEnabled } from "./reducers/globalSlice"; import { getFeatures } from "./services/common"; +import { RootState } from "./store"; function App() { const location = useLocation().pathname; const dispatch = useDispatch(); + const connectedWallet = useSelector( + (state: RootState) => state.wallet.walletApi + ); const init = async () => { const features = await getFeatures(); @@ -41,12 +45,14 @@ function App() { initLocation(); }, [location]); + const OptHeader = useCallback(() =>
, [connectedWallet]); + return ( <> -
+ diff --git a/client/src/components/Claim/CheckRewardInput.tsx b/client/src/components/Claim/CheckRewardInput.tsx new file mode 100644 index 00000000..0d61508e --- /dev/null +++ b/client/src/components/Claim/CheckRewardInput.tsx @@ -0,0 +1,65 @@ +import { KeyboardEvent } from "react"; +import Spinner from "src/components/Spinner"; + +interface Props { + searchAddress: string; + setSearchAddress: (_: string) => void; + checkRewards: () => void; + isSearchDisabledAndStakingInfoShown: boolean; + isRewardLoading: boolean; + cancelClaim: () => void; +} + +export default function CheckRewardInput({ + searchAddress, + setSearchAddress, + checkRewards, + isSearchDisabledAndStakingInfoShown, + isRewardLoading, + cancelClaim, +}: Props) { + function handleCheckReward(e: KeyboardEvent) { + if (e.key === "Enter") { + checkRewards(); + } + } + + function handleInput(e: KeyboardEvent) { + setSearchAddress((e.target as HTMLInputElement).value); + } + + return ( +
+

Enter your wallet/stake address or $handle to view your rewards

+ +
+ + +
+
+ ); +} diff --git a/client/src/components/Claim/RewardsView.tsx b/client/src/components/Claim/RewardsView.tsx new file mode 100644 index 00000000..19fd549f --- /dev/null +++ b/client/src/components/Claim/RewardsView.tsx @@ -0,0 +1,124 @@ +import { faStar } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import ClaimableTokenBox from "src/components/Claim/ClaimableTokenBox"; +import Spinner from "src/components/Spinner"; +import { ClaimableToken } from "src/entities/vm.entities"; + +interface Props { + claimableTokens: ClaimableToken[]; + handleTokenSelect: (_: number) => void; + numberOfSelectedTokens: number; + claimRewards: () => void; + isLoadingClaimReward: boolean; + selectAll: () => void; + poolInfo?: any; +} + +export default function RewardsView({ + claimableTokens, + handleTokenSelect, + numberOfSelectedTokens, + claimRewards, + isLoadingClaimReward, + selectAll, + poolInfo, +}: Props) { + if (claimableTokens.length > 0) { + return ( +
+
+ {poolInfo != null ? ( + <> + {poolInfo.delegated_pool_logo ? ( + + ) : ( + "" + )} +
+
+ Currently staking  + {poolInfo.total_balance} ADA +  with  + + {poolInfo.delegated_pool_name} +   [{poolInfo.delegated_pool_ticker}] + +
+
+ + ) : ( + <>Unregistered + )} +
+
+
+ +
+ {poolInfo?.isWhitelisted + ? "No TosiFee on claims because you have staked to a TosiDrop core pool" + : "These tokens incur a TosiFee when claiming"} +
+
+ {claimableTokens.map((token, index) => { + return ( + + ); + })} +
+ +
+
Selected {numberOfSelectedTokens} token
+
+ + +
+
+
+ ); + } else { + return null; + } +} diff --git a/client/src/components/Header/index.tsx b/client/src/components/Header/index.tsx index f84f7293..8c4bf076 100644 --- a/client/src/components/Header/index.tsx +++ b/client/src/components/Header/index.tsx @@ -1,6 +1,7 @@ // import BlockchainSelector from "src/components/BlockchainSelector"; import { faBars, faMoon, faSun } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; import { Link } from "react-router-dom"; import logoDark from "src/assets/tosidrop-dark.png"; @@ -16,15 +17,18 @@ function Header() { const dispatch = useDispatch(); const theme = useSelector((state: RootState) => state.global.theme); const chain = useSelector((state: RootState) => state.global.chain); + const connectedWallet = useSelector( + (state: RootState) => state.wallet.walletApi + ); - const RenderWalletConnector = () => { + const RenderWalletConnector = useCallback(() => { switch (chain) { case Blockchain.cardano: return ; case Blockchain.ergo: return ; } - }; + }, [connectedWallet]); return ( <> diff --git a/client/src/components/Pool/index.tsx b/client/src/components/Pool/index.tsx index f906cabe..7a0b6cf2 100644 --- a/client/src/components/Pool/index.tsx +++ b/client/src/components/Pool/index.tsx @@ -1,14 +1,43 @@ +import { useDispatch } from "react-redux"; +import { InfoModalTypes, ModalTypes } from "src/entities/common.entities"; import { PoolInfo } from "src/entities/vm.entities"; +import useStakeToPool from "src/hooks/cardano/useStakeToPool"; +import { showModal } from "src/reducers/globalSlice"; +import Spinner from "../Spinner"; export default function Pool({ pool }: { pool: PoolInfo }) { + const { stakeToPool, loading } = useStakeToPool(); + const dispatch = useDispatch(); + + async function handleStake() { + await stakeToPool(pool.id, () => { + dispatch( + showModal({ + modalType: ModalTypes.info, + details: { + text: `Staking to ${pool.ticker} is successful!`, + type: InfoModalTypes.success, + }, + }) + ); + }); + } + return (
pool logo
-
- [{pool.ticker}] {pool.name} +
+ [{pool.ticker}] {pool.name}{" "} +
{pool.description}
diff --git a/client/src/entities/dto.ts b/client/src/entities/dto.ts index eb04c74b..aa416850 100644 --- a/client/src/entities/dto.ts +++ b/client/src/entities/dto.ts @@ -1,5 +1,25 @@ import { DeliveredReward } from "./common.entities"; -import { PoolInfo } from "./vm.entities"; +import { Assets, ClaimableToken, PoolInfo, VmPoolInfo } from "./vm.entities"; + +export interface GetRewardsDto { + claimable_tokens: ClaimableToken[]; + pool_info: VmPoolInfo; + total_rewards?: number; + consolidated_promises?: Assets; + consolidated_rewards?: Assets; + nfts?: any[]; + assets?: Assets; + min_balance?: number; + vending_address?: string; + withdrawal_fee?: string; + withdraw_all_tokens_deposit?: number; + project_locked_rewards?: { + consolidated_promises: Assets; + consolidated_rewards: Assets; + nfts: any[]; + assets: Assets; + }; +} export interface GetQueueDto { pending_tx: number; @@ -17,3 +37,24 @@ export interface GetDeliveredRewardsDto { export interface ServerErrorDto { error: string; } + +export namespace StakeTxDto { + export interface GetTxRequest { + poolId: string; + address: string; + } + + export interface GetTxResponse { + witness: string; + txBody: string; + } + + export interface PostSignedTxRequest { + signedWitness: string; + txBody: string; + } + + export interface PostSignedTxResponse { + tx: string; + } +} diff --git a/client/src/entities/vm.entities.ts b/client/src/entities/vm.entities.ts index 18b4d2e0..dc516a62 100644 --- a/client/src/entities/vm.entities.ts +++ b/client/src/entities/vm.entities.ts @@ -1,12 +1,6 @@ export interface GetRewardsDto { claimable_tokens: ClaimableToken[]; - pool_info: { - delegated_pool_name: string; - delegated_pool_description: string; - total_balance: string; - delegated_pool_ticker: string; - delegated_pool_logo: string; - }; + pool_info: VmPoolInfo; total_rewards?: number; consolidated_promises?: Assets; consolidated_rewards?: Assets; @@ -24,6 +18,15 @@ export interface GetRewardsDto { }; } +export interface VmPoolInfo { + delegated_pool_name: string; + delegated_pool_description: string; + total_balance: string; + delegated_pool_ticker: string; + delegated_pool_logo: string; + isWhitelisted: boolean; +} + export interface GetCustomRewards { request_id: string; deposit: number; diff --git a/client/src/hooks/cardano/claim/useClaimReward.tsx b/client/src/hooks/cardano/claim/useClaimReward.tsx new file mode 100644 index 00000000..afe19015 --- /dev/null +++ b/client/src/hooks/cardano/claim/useClaimReward.tsx @@ -0,0 +1,194 @@ +import { useSelector } from "react-redux"; + +import { RootState } from "src/store"; + +import { useEffect, useState } from "react"; +import { useDispatch } from "react-redux"; +import { useNavigate } from "react-router-dom"; + +import { + InfoModalTypes, + ModalTypes, + PageRoute, +} from "src/entities/common.entities"; +import { ClaimableToken, VmPoolInfo } from "src/entities/vm.entities"; +import useErrorHandler from "src/hooks/useErrorHandler"; +import { showModal } from "src/reducers/globalSlice"; +import { getCustomRewards, getRewards } from "src/services/claim"; +import { getStakeKey } from "src/services/common"; + +export default function useClaimReward() { + const dispatch = useDispatch(); + const navigate = useNavigate(); + const { handleError } = useErrorHandler(); + const connectedWallet = useSelector( + (state: RootState) => state.wallet.walletApi + ); + const isWrongNetwork = useSelector( + (state: RootState) => state.wallet.isWrongNetwork + ); + + const [searchAddress, setSearchAddress] = useState(""); + const [claimableTokens, setClaimableTokens] = useState([]); + const [poolInfo, setPoolInfo] = useState(null); + const [isCheckRewardLoading, setIsCheckRewardLoading] = useState(false); + const [isClaimRewardLoading, setIsClaimRewardLoading] = useState(false); + const [stakeAddress, setStakeAddress] = useState(""); + const [numberOfSelectedTokens, setNumberOfSelectedTokens] = useState(0); + + useEffect(() => { + async function init() { + if (connectedWallet?.wallet?.api && !isWrongNetwork) { + setSearchAddress(await connectedWallet.getAddress()); + } + } + init(); + }, [connectedWallet?.wallet?.api, connectedWallet, isWrongNetwork]); + + useEffect(() => { + setNumberOfSelectedTokens( + claimableTokens.reduce((agg, i) => { + if (i.selected) { + agg += 1; + } + return agg; + }, 0) + ); + }, [claimableTokens]); + + const selectAllClaimableTokens = () => { + const updatedClaimableTokens = [...claimableTokens]; + if (numberOfSelectedTokens < claimableTokens.length) { + updatedClaimableTokens.forEach((token) => (token.selected = true)); + } else { + updatedClaimableTokens.forEach((token) => (token.selected = false)); + } + setClaimableTokens(updatedClaimableTokens); + }; + + const handleTokenSelect = (position: number) => { + const updatedClaimableTokens = [...claimableTokens]; + updatedClaimableTokens[position].selected = + !updatedClaimableTokens[position].selected; + setClaimableTokens(updatedClaimableTokens); + }; + + const selectAll = () => { + const updatedClaimableTokens = [...claimableTokens]; + if (numberOfSelectedTokens < claimableTokens.length) { + updatedClaimableTokens.forEach((token) => (token.selected = true)); + } else { + updatedClaimableTokens.forEach((token) => (token.selected = false)); + } + setClaimableTokens(updatedClaimableTokens); + }; + + const checkRewards = async () => { + setIsCheckRewardLoading(true); + try { + /** + * check if the inserted address is cardano address, we want the stake address + * if it is cardano address, get the staking address + */ + let address = await getStakeKey(searchAddress); + + address = address.staking_address; + + setStakeAddress(address); + const getRewardsDto = await getRewards(address); + if (getRewardsDto == null) { + throw new Error("Something went wrong when checking reward"); + } + if (getRewardsDto.claimable_tokens.length !== 0) { + setClaimableTokens( + getRewardsDto.claimable_tokens + .map((token) => { + token.selected = false; + return token; + }) + .sort((a, b) => { + if (a.premium === b.premium) { + if (a.ticker < b.ticker) { + return -1; + } else { + return 1; + } + } else { + return a.premium ? -1 : 1; + } + }) + ); + setPoolInfo(getRewardsDto.pool_info); + setIsCheckRewardLoading(false); + } else { + dispatch( + showModal({ + modalType: ModalTypes.info, + details: { + text: "No rewards found for the account, yet.", + type: InfoModalTypes.info, + }, + }) + ); + } + } catch (e: any) { + handleError(e); + } finally { + setIsCheckRewardLoading(false); + } + }; + + const claimRewards = async () => { + if (numberOfSelectedTokens === 0) return; + + setIsClaimRewardLoading(true); + let selectedPremiumToken = false; + + const selectedTokenId: string[] = []; + claimableTokens.forEach((token) => { + if (token.selected) { + if (token.premium) { + selectedPremiumToken = true; + } + selectedTokenId.push(token.assetId); + } + }); + + try { + const res = await getCustomRewards( + stakeAddress, + stakeAddress.slice(0, 40), + selectedTokenId.join(","), + selectedPremiumToken + ); + if (res == null) throw new Error(); + + let depositInfoUrl = `${PageRoute.depositCardano}?stakeAddress=${stakeAddress}&withdrawAddress=${res.withdrawal_address}&requestId=${res.request_id}&selectedTokens=${numberOfSelectedTokens}&unlock=${selectedPremiumToken}&isWhitelisted=${res.is_whitelisted}`; + navigate(depositInfoUrl, { replace: true }); + } catch (e) { + handleError(e); + } finally { + setIsClaimRewardLoading(false); + } + }; + + const cancelClaim = async () => { + setClaimableTokens([]); + }; + + return { + searchAddress, + setSearchAddress, + checkRewards, + claimRewards, + selectAll, + cancelClaim, + claimableTokens, + selectAllClaimableTokens, + handleTokenSelect, + numberOfSelectedTokens, + isCheckRewardLoading, + isClaimRewardLoading, + poolInfo, + }; +} diff --git a/client/src/hooks/cardano/useStakeToPool.tsx b/client/src/hooks/cardano/useStakeToPool.tsx new file mode 100644 index 00000000..9544f9fa --- /dev/null +++ b/client/src/hooks/cardano/useStakeToPool.tsx @@ -0,0 +1,39 @@ +import { useState } from "react"; +import { useSelector } from "react-redux"; +import { createStakeTx, submitStakeTx } from "src/services/common"; +import { RootState } from "src/store"; +import useErrorHandler from "../useErrorHandler"; + +export default function useStakeToPool() { + const [loading, setLoading] = useState(false); + const { handleError } = useErrorHandler(); + const connectedWallet = useSelector( + (state: RootState) => state.wallet.walletApi + ); + + async function stakeToPool(poolId: string, callback?: () => void) { + setLoading(true); + try { + if (connectedWallet == null) { + throw new Error("Please connect your wallet to delegate"); + } + const address = await connectedWallet.getBech32Address(); + const { witness, txBody } = await createStakeTx({ poolId, address }); + const signedWitness = await connectedWallet.signTx(witness); + const { tx } = await submitStakeTx({ signedWitness, txBody }); + await connectedWallet.wallet?.api.submitTx(tx); + if (callback != null) { + callback(); + } + } catch (error) { + handleError(error); + } finally { + setLoading(false); + } + } + + return { + stakeToPool, + loading, + }; +} diff --git a/client/src/hooks/useWallet.tsx b/client/src/hooks/useWallet.tsx index 6cd149a5..ccc57fba 100644 --- a/client/src/hooks/useWallet.tsx +++ b/client/src/hooks/useWallet.tsx @@ -27,7 +27,7 @@ const useWallet = () => { const walletApi = await getWalletApi(); if (!walletKey) { - dispatch(connectWalletRedux(walletApi)); + dispatch(connectWalletRedux(undefined)); dispatch(setIsWrongNetwork(false)); localStorage.removeItem("wallet-provider"); return; diff --git a/client/src/pages/Cardano/Claim/index.tsx b/client/src/pages/Cardano/Claim/index.tsx index f8b03987..3cc113fc 100644 --- a/client/src/pages/Cardano/Claim/index.tsx +++ b/client/src/pages/Cardano/Claim/index.tsx @@ -1,356 +1,25 @@ -import { faStar } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { KeyboardEvent, useCallback, useEffect, useState } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { useNavigate } from "react-router-dom"; - -import Spinner from "src/components/Spinner"; -import { - InfoModalTypes, - ModalTypes, - PageRoute, -} from "src/entities/common.entities"; -import { ClaimableToken } from "src/entities/vm.entities"; -import { showModal } from "src/reducers/globalSlice"; -import { getCustomRewards, getRewards } from "src/services/claim"; -import { RootState } from "src/store"; - -import ClaimableTokenBox from "src/components/Claim/ClaimableTokenBox"; +import CheckRewardInput from "src/components/Claim/CheckRewardInput"; +import RewardsView from "src/components/Claim/RewardsView"; +import useClaimReward from "src/hooks/cardano/claim/useClaimReward"; import { useQueue } from "src/hooks/cardano/claim/useQueue"; -import useErrorHandler from "src/hooks/useErrorHandler"; -import { getStakeKey } from "src/services/common"; function Claim() { - const dispatch = useDispatch(); - const navigate = useNavigate(); - const connectedWallet = useSelector( - (state: RootState) => state.wallet.walletApi - ); - const { handleError } = useErrorHandler(); - - const isWrongNetwork = useSelector( - (state: RootState) => state.wallet.isWrongNetwork - ); - const [hideCheck, setHideCheck] = useState(false); - const [hideStakingInfo, setHideStakingInfo] = useState(true); - - const [claimableTokens, setClaimableTokens] = useState([]); - const [poolInfo, setPoolInfo] = useState(null); - const [numberOfSelectedTokens, setNumberOfSelectedTokens] = useState(0); - - const [searchAddress, setSearchAddress] = useState(""); - const [rewardsLoader, setRewardsLoader] = useState(false); - const [stakeAddress, setStakeAddress] = useState(""); - const [claimMyRewardLoading, setClaimMyRewardLoading] = - useState(false); + const { + searchAddress, + setSearchAddress, + checkRewards, + isCheckRewardLoading, + isClaimRewardLoading, + selectAll, + cancelClaim, + claimableTokens, + handleTokenSelect, + numberOfSelectedTokens, + claimRewards, + poolInfo, + } = useClaimReward(); const queue = useQueue(); - useEffect(() => { - if (claimableTokens.length) { - setHideStakingInfo(false); - } else { - setHideStakingInfo(true); - } - }, [claimableTokens]); - - useEffect(() => { - async function init() { - if (connectedWallet?.wallet?.api && !isWrongNetwork) { - setSearchAddress(await connectedWallet.getAddress()); - setHideCheck(false); - setHideStakingInfo(true); - } - } - - init(); - }, [connectedWallet?.wallet?.api, connectedWallet, isWrongNetwork]); - - const getNumberOfSelectedTokens = useCallback(() => { - return claimableTokens.reduce((prev, token) => { - if (token.selected) { - prev += 1; - } - return prev; - }, 0); - }, [claimableTokens]); - - /** - * select/unselect all tokens - */ - const selectAll = () => { - const updatedClaimableTokens = [...claimableTokens]; - if (numberOfSelectedTokens < claimableTokens.length) { - updatedClaimableTokens.forEach((token) => (token.selected = true)); - } else { - updatedClaimableTokens.forEach((token) => (token.selected = false)); - } - setClaimableTokens(updatedClaimableTokens); - setNumberOfSelectedTokens(getNumberOfSelectedTokens()); - }; - - /** - * handle token select - */ - const handleTokenSelect = (position: number) => { - const updatedClaimableTokens = [...claimableTokens]; - updatedClaimableTokens[position].selected = - !updatedClaimableTokens[position].selected; - setClaimableTokens(updatedClaimableTokens); - setNumberOfSelectedTokens(getNumberOfSelectedTokens()); - }; - - const checkRewards = async () => { - if (searchAddress) { - setRewardsLoader(true); - try { - /** - * check if the inserted address is cardano address - * we want the stake address - * if it is cardano address, get the staking address - */ - let address = await getStakeKey(searchAddress); - - address = address.staking_address; - - setStakeAddress(address); - const getRewardsDto = await getRewards(address); - if (getRewardsDto == null) throw new Error(); - if (getRewardsDto.claimable_tokens.length !== 0) { - setClaimableTokens( - getRewardsDto.claimable_tokens - .map((token) => { - token.selected = false; - return token; - }) - .sort((a, b) => { - if (a.premium === b.premium) { - if (a.ticker < b.ticker) { - return -1; - } else { - return 1; - } - } else { - return a.premium ? -1 : 1; - } - }) - ); - setPoolInfo(getRewardsDto.pool_info); - setRewardsLoader(false); - } else { - dispatch( - showModal({ - modalType: ModalTypes.info, - details: { - text: "No rewards found for the account, yet.", - type: InfoModalTypes.info, - }, - }) - ); - } - } catch (e: any) { - handleError(e); - } finally { - setRewardsLoader(false); - } - } - }; - - const claimMyRewards = async () => { - if (numberOfSelectedTokens === 0) return; - - setClaimMyRewardLoading(true); - let selectedPremiumToken = false; - - const selectedTokenId: string[] = []; - claimableTokens.forEach((token) => { - if (token.selected) { - if (token.premium) { - selectedPremiumToken = true; - } - selectedTokenId.push(token.assetId); - } - }); - - try { - const res = await getCustomRewards( - stakeAddress, - stakeAddress.slice(0, 40), - selectedTokenId.join(","), - selectedPremiumToken - ); - if (res == null) throw new Error(); - - let depositInfoUrl = `${PageRoute.depositCardano}?stakeAddress=${stakeAddress}&withdrawAddress=${res.withdrawal_address}&requestId=${res.request_id}&selectedTokens=${numberOfSelectedTokens}&unlock=${selectedPremiumToken}&isWhitelisted=${res.is_whitelisted}`; - navigate(depositInfoUrl, { replace: true }); - } catch (e) { - handleError(e); - } finally { - setClaimMyRewardLoading(false); - } - }; - - const cancelClaim = async () => { - setClaimableTokens([]); - }; - - const renderStakeInfo = () => { - if (poolInfo != null) { - return ( - <> - {poolInfo.delegated_pool_logo ? ( - - ) : ( - "" - )} -
-
- Currently staking  - {poolInfo.total_balance} ADA -  with  - - {poolInfo.delegated_pool_name} -   [{poolInfo.delegated_pool_ticker}] - -
-
- - ); - } else { - return <>Unregistered; - } - }; - - function renderCheckRewardsStep() { - if (!hideCheck) { - return ( -
-

Enter your wallet/stake address or $handle to view your rewards

- ) => - setSearchAddress((e.target as HTMLInputElement).value) - } - onKeyDown={(e) => { - if (e.key === "Enter") { - checkRewards(); - } - }} - disabled={ - !hideStakingInfo || - (typeof connectedWallet?.wallet?.api !== "undefined" && - !isWrongNetwork) - } - > -
- - -
-
- ); - } else { - return null; - } - } - - function renderStakingInfoStep() { - if (!hideStakingInfo) { - return ( -
-
- {renderStakeInfo()} -
-
-
- -
- These tokens incur a TosiFee when claiming -
-
- {claimableTokens.map((token, index) => { - return ( - - ); - })} -
- -
-
Selected {numberOfSelectedTokens} token
-
- - -
-
-
- ); - } else { - return null; - } - } - return ( <>
@@ -360,8 +29,23 @@ function Claim() {
- {renderCheckRewardsStep()} - {renderStakingInfoStep()} + +
); diff --git a/client/src/reducers/walletSlice.ts b/client/src/reducers/walletSlice.ts index 8510c0cd..ef1796a9 100644 --- a/client/src/reducers/walletSlice.ts +++ b/client/src/reducers/walletSlice.ts @@ -27,12 +27,15 @@ export const walletSlice = createSlice({ name: "wallet", initialState, reducers: { - connectWallet: (state, action: PayloadAction) => { - if (!action.payload) return; + connectWallet: (state, action: PayloadAction) => { state.walletApi = action.payload; - if (!action.payload.wallet) return; - state.name = action.payload.wallet.name; - state.api = action.payload.wallet.api; + if (action.payload?.wallet !== undefined) { + state.name = action.payload.wallet.name; + state.api = action.payload.wallet.api; + } else { + state.name = ""; + state.api = undefined; + } }, setNetworkId: (state, action: PayloadAction) => { state.networkId = action.payload; diff --git a/client/src/services/common.ts b/client/src/services/common.ts index 258eefe8..41f5ae3d 100644 --- a/client/src/services/common.ts +++ b/client/src/services/common.ts @@ -1,6 +1,6 @@ import axios from "axios"; import { NetworkId, PopUpInfo } from "src/entities/common.entities"; -import { GetPoolsDto, GetQueueDto } from "src/entities/dto"; +import { GetPoolsDto, GetQueueDto, StakeTxDto } from "src/entities/dto"; import { EpochParams, Tip } from "src/entities/koios.entities"; import { ProjectData } from "src/entities/project.entities"; import { GetTokens } from "src/entities/vm.entities"; @@ -76,3 +76,22 @@ export async function getTokens(): Promise { const response = await axios.get(`/api/gettokens`); return response.data; } + +export async function createStakeTx( + params: StakeTxDto.GetTxRequest +): Promise { + const response = await axios.get( + `/api/tx/stake?poolId=${params.poolId}&address=${params.address}` + ); + return response.data; +} + +export async function submitStakeTx( + params: StakeTxDto.PostSignedTxRequest +): Promise { + const response = await axios.post( + `/api/tx/stake`, + params + ); + return response.data; +} diff --git a/client/src/services/connectors/wallet.connector.ts b/client/src/services/connectors/wallet.connector.ts index 07d5dea0..2b58f22c 100644 --- a/client/src/services/connectors/wallet.connector.ts +++ b/client/src/services/connectors/wallet.connector.ts @@ -105,6 +105,15 @@ class WalletApi { return address; } + async getBech32Address(): Promise { + if (!this.isEnabled() || !this.wallet) throw new Error(ERROR.NOT_CONNECTED); + + const addresses = await this.wallet.api.getUsedAddresses(); + const address = addresses[0] as any; + + return wasm.Address.from_hex(address).to_bech32(); + } + async getNetworkId() { if (!this.isEnabled() || !this.wallet) throw ERROR.NOT_CONNECTED; @@ -285,6 +294,10 @@ class WalletApi { return UTXOS; } + async signTx(txInHex: string) { + return this.wallet?.api.signTx(txInHex); + } + private utxoToAssets(utxo: wasm.TransactionUnspentOutput) { let value = utxo.output().amount(); const assets = []; diff --git a/server/index.ts b/server/index.ts index 376931ac..0e9ed545 100644 --- a/server/index.ts +++ b/server/index.ts @@ -14,6 +14,10 @@ import { } from "../client/src/entities/dto"; import { Tip, TransactionStatus } from "../client/src/entities/koios.entities"; import { PoolInfo } from "../client/src/entities/vm.entities"; +import errorHandlerMiddleware, { + errorHandlerWrapper, +} from "./middlewares/error-handler"; +import TxRouter from "./routes/tx"; import { CardanoNetwork, getAccountsInfo, @@ -32,18 +36,21 @@ import { translateAdaHandle, } from "./utils"; import { ICustomRewards } from "./utils/entities"; -import { logError } from "./utils/error"; - +import { createErrorWithCode, HttpStatusCode } from "./utils/error"; require("dotenv").config(); -const openapi = require("@wesleytodd/openapi"); +const openapi = require("@reqlez/express-openapi"); const fs = require("fs"); -const CARDANO_NETWORK = process.env.CARDANO_NETWORK || CardanoNetwork.preview; + +/** environment variables */ +export const VM_KOIOS_URL = + process.env.KOIOS_URL_TESTNET || process.env.KOIOS_URL; +export const CARDANO_NETWORK = + process.env.CARDANO_NETWORK || CardanoNetwork.preview; const CLOUDFLARE_PSK = process.env.CLOUDFLARE_PSK; const LOG_TYPE = process.env.LOG_TYPE || "dev"; const PORT = process.env.PORT || 3000; const TOSIFEE = process.env.TOSIFEE || 500000; const TOSIFEE_WHITELIST = process.env.TOSIFEE_WHITELIST; -const VM_KOIOS_URL = process.env.KOIOS_URL_TESTNET || process.env.KOIOS_URL; const CLAIM_ENABLED = process.env.CLAIM_ENABLED === "true"; const ERGO_ENABLED = process.env.ERGO_ENABLED === "true"; @@ -61,22 +68,8 @@ app.use(express.json()); app.use(require("morgan")(LOG_TYPE)); app.use(oapi); app.use("/swaggerui", oapi.swaggerui); - -/** - * Serve static files for our React app - */ app.use(express.static("../client/build")); -const server = app.listen(PORT, () => { - console.log(`Server listening on ${PORT}`); -}); - -process.on("SIGTERM", () => { - server.close(() => { - console.log("Server shutting down"); - }); -}); - const resp200Ok = { responses: { 200: { @@ -119,26 +112,30 @@ const resp200Ok500Bad = { }, }; -app.get("/api/getprices", oapi.path(resp200Ok), async (req, res) => { - const prices = await getPrices(); - return res.status(200).send(prices); -}); +app.use("/api/tx", TxRouter); + +app.get( + "/api/getprices", + oapi.path(resp200Ok), + errorHandlerWrapper(async (_req: Request, res: Response) => { + const prices = await getPrices(); + return res.status(200).send(prices); + }) +); app.get( "/api/getpools", oapi.path(resp200Ok), - async (req, res: Response) => { + errorHandlerWrapper(async (_req: Request, res: Response) => { const pools = await getPools(); - - /** did this because value in env use 'pool...' as ID whereas VM retuns pool ID */ - const whitelistedPoolTickers = ["BBHMM", "OTG", "PSB", "SEAL", "APEX"]; + const whitelist = TOSIFEE_WHITELIST ? TOSIFEE_WHITELIST.split(",") : []; const whitelistedPools: PoolInfo[] = []; const regularPools: PoolInfo[] = []; Object.values(pools).forEach((pool) => { if (pool.visible === "f" || pool.id.includes("project_")) { return; } - if (whitelistedPoolTickers.includes(pool.ticker)) { + if (whitelist.includes(pool.id)) { whitelistedPools.push(pool); } else { regularPools.push(pool); @@ -148,70 +145,83 @@ app.get( whitelistedPools: _.shuffle(whitelistedPools), regularPools: _.shuffle(regularPools), }); - } + }) ); -app.get("/api/gettokens", oapi.path(resp200Ok), async (req, res) => { - const tokens = await getTokens(); - return res.status(200).send(tokens); -}); +app.get( + "/api/gettokens", + oapi.path(resp200Ok), + errorHandlerWrapper(async (_req: Request, res: Response) => { + const tokens = await getTokens(); + return res.status(200).send(tokens); + }) +); -app.get("/api/getsettings", oapi.path(resp200Ok), async (req, res) => { - const settings: IVMSettings = await getFromVM("get_settings"); - return res.status(200).send(settings); -}); +app.get( + "/api/getsettings", + oapi.path(resp200Ok), + errorHandlerWrapper(async (_req: Request, res: Response) => { + const settings: IVMSettings = await getFromVM("get_settings"); + return res.status(200).send(settings); + }) +); -app.get("/api/systeminfo", oapi.path(resp200Ok), async (req, res) => { - const systeminfo = await getFromVM("system_info"); - return res.status(200).send(systeminfo); -}); +app.get( + "/api/systeminfo", + oapi.path(resp200Ok), + errorHandlerWrapper(async (_req: Request, res: Response) => { + const systeminfo = await getFromVM("system_info"); + return res.status(200).send(systeminfo); + }) +); -app.get("/health", (req: any, res: any) => { - res.status(200).json({ - status: "UP", - }); -}); +app.get( + "/health", + errorHandlerWrapper((_req: Request, res: Response) => { + res.status(200).json({ + status: "UP", + }); + }) +); -app.get("/healthz", async (req: any, res: any) => { - try { - const getTipResponse = await getFromKoios(`tip`); - } catch (error: any) { - return res.status(502).send({ error: "Failed to get tip from Koios" }); - } - if (CLOUDFLARE_PSK) { - if (req.headers["x-cloudflare-psk"]) { - const myPsk = req.headers["x-cloudflare-psk"]; - if (myPsk == CLOUDFLARE_PSK) { - const authResponse = await getFromVM("is_authenticated"); - res.send(authResponse); +app.get( + "/healthz", + errorHandlerWrapper(async (req: Request, res: Response) => { + await getFromKoios(`tip`); + if (CLOUDFLARE_PSK) { + if (req.headers["x-cloudflare-psk"]) { + const myPsk = req.headers["x-cloudflare-psk"]; + if (myPsk == CLOUDFLARE_PSK) { + const authResponse = await getFromVM("is_authenticated"); + return res.send(authResponse); + } else { + throw createErrorWithCode(HttpStatusCode.BAD_REQUEST, "PSK invalid"); + } } else { - res.status(403).json({ - error: "PSK invalid", - }); + throw createErrorWithCode(HttpStatusCode.BAD_REQUEST, "PSK is missing"); } } else { - res.status(401).json({ - error: "PSK missing", + return res.status(200).json({ + status: "UP", }); } - } else { - res.status(200).json({ - status: "UP", - }); - } -}); - -app.get("/features", (req: any, res: any) => { - const features: ITosiFeatures = { - tosi_fee: Number(TOSIFEE), - tosi_fee_whitelist: TOSIFEE_WHITELIST, - claim_enabled: CLAIM_ENABLED, - network: CARDANO_NETWORK, - ergo_enabled: ERGO_ENABLED, - }; + }) +); - return res.status(200).send(features); -}); +app.get( + "/features", + errorHandlerWrapper((_req: Request, res: Response) => { + const features: ITosiFeatures = { + tosi_fee: Number(TOSIFEE), + tosi_fee_whitelist: TOSIFEE_WHITELIST, + claim_enabled: CLAIM_ENABLED, + network: CARDANO_NETWORK, + ergo_enabled: ERGO_ENABLED, + }; + + return res.status(200).send(features); + }) +); app.get( "/api/getstakekey", @@ -264,87 +274,89 @@ app.get( }, }, }), - async (req: any, res: any) => { - try { - const queryObject = url.parse(req.url, true).query; - let address = queryObject.address as string; - let translatedAddress; - - if (!address) - return res.status(400).send({ error: "Address seems invalid" }); - if (!VM_KOIOS_URL) - return res.status(500).send({ error: "KOIOS URL is not defined" }); - - const prefix = address.slice(0, 5); - - switch (true) { - /** - * for ADA Handle, translate the handle - * to a functional address - */ - case prefix[0] === "$": - translatedAddress = await translateAdaHandle( - address, - CARDANO_NETWORK, - VM_KOIOS_URL - ); - address = translatedAddress; - break; - case prefix === "addr_": - if (CARDANO_NETWORK === CardanoNetwork.mainnet) - return res - .status(400) - .send({ error: "Inserted address is for a testnet" }); - break; - case prefix === "addr1": - if (CARDANO_NETWORK === CardanoNetwork.preview) - return res - .status(400) - .send({ error: "Inserted address is for mainnet" }); - break; - case prefix === "stake": - // We were given a stake address, pass it through - return res.send({ staking_address: address }); - break; - default: - return res.status(400).send({ error: "Address seems invalid" }); - } - - let rewardAddressBytes = new Uint8Array(29); - switch (CARDANO_NETWORK) { - case CardanoNetwork.mainnet: - rewardAddressBytes.set([0xe1], 0); - break; - case CardanoNetwork.preview: - default: - rewardAddressBytes.set([0xe0], 0); - break; - } - - const addressObject = Address.from_bech32(address); - const baseAddress = BaseAddress.from_address(addressObject); - if (baseAddress == null) return null; - rewardAddressBytes.set( - baseAddress.stake_cred().to_bytes().slice(4, 32), - 1 + errorHandlerWrapper(async (req: Request, res: Response) => { + if (!VM_KOIOS_URL) { + throw createErrorWithCode( + HttpStatusCode.INTERNAL_SERVER_ERROR, + "KOIOS URL is not defined" ); + } + + const queryObject = url.parse(req.url, true).query; + let address = queryObject.address as string; + let translatedAddress; - let rewardAddress = RewardAddress.from_address( - Address.from_bytes(rewardAddressBytes) + if (!address) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Address seems invalid" ); + } - if (rewardAddress == null) return null; + const prefix = address.slice(0, 5); + + switch (true) { + /** for ADA Handle, translate the handle to a regular address */ + case prefix[0] === "$": + translatedAddress = await translateAdaHandle( + address, + CARDANO_NETWORK, + VM_KOIOS_URL + ); + address = translatedAddress; + break; + case prefix === "addr_": + if (CARDANO_NETWORK === CardanoNetwork.mainnet) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Inserted address is for a testnet" + ); + } + break; + case prefix === "addr1": + if (CARDANO_NETWORK === CardanoNetwork.preview) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Inserted address is for a mainnet" + ); + } + break; + case prefix === "stake": + // We were given a stake address, pass it through + return res.send({ staking_address: address }); + default: + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Address seems invalid" + ); + } - return res.send({ - staking_address: rewardAddress.to_address().to_bech32(), - }); - } catch (error: any) { - return res.status(500).send({ - error: - "Fails to get the stake key. Are you sure the inserted address is correct?", - }); + let rewardAddressBytes = new Uint8Array(29); + switch (CARDANO_NETWORK) { + case CardanoNetwork.mainnet: + rewardAddressBytes.set([0xe1], 0); + break; + case CardanoNetwork.preview: + default: + rewardAddressBytes.set([0xe0], 0); + break; } - } + + const addressObject = Address.from_bech32(address); + const baseAddress = BaseAddress.from_address(addressObject); + if (baseAddress == null) return null; + rewardAddressBytes.set(baseAddress.stake_cred().to_bytes().slice(4, 32), 1); + + let rewardAddress = RewardAddress.from_address( + Address.from_bytes(rewardAddressBytes) + ); + + if (rewardAddress == null) return null; + + return res.send({ + staking_address: rewardAddress.to_address().to_bech32(), + }); + }) ); /** @@ -403,31 +415,33 @@ app.get( }, }, }), - async (req: any, res: any) => { - try { - const queryObject = url.parse(req.url, true).query; - const stakeAddress = queryObject.address as string; - if (!stakeAddress) - return res - .status(400) - .send({ error: "No address provided to /api/getrewards" }); - - let claimableTokens = await getRewards(stakeAddress); - const accountsInfo = await getAccountsInfo(stakeAddress); - const poolInfo = await getPoolMetadata(accountsInfo[0]); - - const consolidatedGetRewards = { - pool_info: poolInfo, - claimable_tokens: claimableTokens, - }; - - return res.send(consolidatedGetRewards); - } catch (error: any) { - return res - .status(500) - .send({ error: "An error occurred in /api/getrewards" }); + errorHandlerWrapper(async (req: Request, res: Response) => { + const queryObject = url.parse(req.url, true).query; + const stakeAddress = queryObject.address as string; + if (!stakeAddress) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Address is required" + ); } - } + + let claimableTokens = await getRewards(stakeAddress); + const accountsInfo = await getAccountsInfo(stakeAddress); + const poolInfo = await getPoolMetadata(accountsInfo[0]); + poolInfo.isWhitelisted = false; + + const whitelist = TOSIFEE_WHITELIST ? TOSIFEE_WHITELIST.split(",") : []; + if (whitelist.includes(poolInfo.delegated_pool_id_bech32)) { + poolInfo.isWhitelisted = true; + } + + const consolidatedGetRewards = { + pool_info: poolInfo, + claimable_tokens: claimableTokens, + }; + + return res.send(consolidatedGetRewards); + }) ); app.get( @@ -499,67 +513,119 @@ app.get( }, }, }), - async (req: any, res: any) => { - try { - const queryObject = url.parse(req.url, true).query; - const { staking_address, session_id, selected, unlock } = queryObject; - let vmArgs = `custom_request&staking_address=${staking_address}&session_id=${session_id}&selected=${selected}&xwallet=true`; - let isWhitelisted = false; - - if (!staking_address) - return res.status(400).send({ error: "staking_address required" }); - if (unlock === "true") { - if (TOSIFEE_WHITELIST) { - const whitelist = TOSIFEE_WHITELIST.split(","); - const accountsInfo = await getAccountsInfo(`${staking_address}`); - const accountInfo = accountsInfo[0]; - if (whitelist.includes(accountInfo.delegated_pool)) { - vmArgs += "&unlocks_special=true"; - isWhitelisted = true; - } else { - vmArgs += `&overhead_fee=${TOSIFEE}&unlocks_special=true`; - } + errorHandlerWrapper(async (req: Request, res: Response) => { + const queryObject = url.parse(req.url, true).query; + const { + staking_address: stakeAddress, + session_id, + selected, + unlock, + } = queryObject; + let vmArgs = `custom_request&staking_address=${stakeAddress}&session_id=${session_id}&selected=${selected}&xwallet=true`; + let isWhitelisted = false; + + if (!stakeAddress) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Address is required" + ); + } + + if (unlock === "true") { + if (TOSIFEE_WHITELIST) { + const whitelist = TOSIFEE_WHITELIST.split(","); + const accountsInfo = await getAccountsInfo(`${stakeAddress}`); + const accountInfo = accountsInfo[0]; + if (whitelist.includes(accountInfo.delegated_pool)) { + vmArgs += "&unlocks_special=true"; + isWhitelisted = true; } else { vmArgs += `&overhead_fee=${TOSIFEE}&unlocks_special=true`; } } else { - vmArgs += "&unlocks_special=false"; + vmArgs += `&overhead_fee=${TOSIFEE}&unlocks_special=true`; } + } else { + vmArgs += "&unlocks_special=false"; + } - const submitCustomReward: any = await getFromVM(vmArgs); - - if (submitCustomReward == null) { - throw new Error(); - } + const submitCustomReward: any = await getFromVM(vmArgs); - const customReward: ICustomRewards = { - request_id: submitCustomReward.request_id, - deposit: submitCustomReward.deposit, - overhead_fee: submitCustomReward.overhead_fee, - withdrawal_address: submitCustomReward.withdrawal_address, - is_whitelisted: isWhitelisted, - }; - - return res.send(customReward); - } catch (e: any) { - logError(e); - return res - .status(500) - .send({ error: "An error occurred in /api/getcustomrewards" }); + if (submitCustomReward == null) { + throw new Error(); } - } + + const customReward: ICustomRewards = { + request_id: submitCustomReward.request_id, + deposit: submitCustomReward.deposit, + overhead_fee: submitCustomReward.overhead_fee, + withdrawal_address: submitCustomReward.withdrawal_address, + is_whitelisted: isWhitelisted, + }; + + return res.send(customReward); + }) ); app.get( "/api/getdeliveredrewards", - async (req: any, res: Response) => { - try { + oapi.path({ + description: "Return delivered rewards from a given stake address.", + parameters: [ + { + name: "staking_address", + in: "query", + required: true, + }, + ], + responses: { + 200: { + content: { + "application/json": { + schema: { + type: "object", + }, + }, + }, + }, + 400: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + error: { type: "string" }, + }, + }, + }, + }, + }, + 500: { + content: { + "application/json": { + schema: { + type: "object", + properties: { + error: { type: "string" }, + }, + }, + }, + }, + }, + }, + }), + errorHandlerWrapper( + async ( + req: Request, + res: Response + ) => { const queryObject = url.parse(req.url, true).query; const { staking_address: stakingAddress } = queryObject; if (!stakingAddress) { - return res - .status(400) - .send({ error: "No address provided to /api/getdeliveredrewards" }); + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Address is required" + ); } const deliveredRewards = await getDeliveredRewards( @@ -569,13 +635,8 @@ app.get( return res.status(200).send({ deliveredRewards, }); - } catch (e: any) { - logError(e); - return res - .status(500) - .send({ error: "An error occurred in /api/getdeliveredrewards" }); } - } + ) ); app.get( @@ -631,26 +692,29 @@ app.get( }, }, }), - async (req, res) => { - try { - const queryObject = url.parse(req.url, true).query; - const { request_id, session_id } = queryObject; - - if (!request_id || !session_id) - return res - .status(400) - .send({ error: "Missing request or session ID in /api/txstatus" }); + errorHandlerWrapper(async (req: Request, res: Response) => { + const queryObject = url.parse(req.url, true).query; + const { request_id, session_id } = queryObject; + + if (!request_id) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Request ID is required" + ); + } - const txStatus = await getFromVM( - `check_status_custom_request&request_id=${request_id}&session_id=${session_id}` + if (!session_id) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Session ID is required" ); - return res.send(txStatus); - } catch (e: any) { - return res - .status(500) - .send({ error: "An error occurred in /api/txstatus" }); } - } + + const txStatus = await getFromVM( + `check_status_custom_request&request_id=${request_id}&session_id=${session_id}` + ); + return res.send(txStatus); + }) ); app.get( @@ -700,129 +764,119 @@ app.get( }, }, }), - async (req: any, res: any) => { - try { - const queryObject = url.parse(req.url, true).query; - if (queryObject.txHash) { - const getTransactionStatusResponse = await postFromKoios< - TransactionStatus[] - >(`tx_status`, { _tx_hashes: [queryObject.txHash] }); - res.send(getTransactionStatusResponse); - } else { - res.status(400).send({ error: "Tx hash seems invalid" }); - } - } catch (error: any) { - return res - .status(500) - .send({ error: "An error occurred in /api/gettransactionstatus" }); + errorHandlerWrapper(async (req: Request, res: Response) => { + const queryObject = url.parse(req.url, true).query; + if (!queryObject.txHash) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Tx hash is invalid" + ); } - } + const getTransactionStatusResponse = await postFromKoios< + TransactionStatus[] + >(`tx_status`, { _tx_hashes: [queryObject.txHash] }); + return res.send(getTransactionStatusResponse); + }) ); app.get( "/api/getabsslot", oapi.path(resp200Ok500Bad), - async (req: any, res: any) => { - try { - const getTipResponse = await getFromKoios(`tip`); - res.send({ - abs_slot: - getTipResponse && getTipResponse.length - ? getTipResponse[0].abs_slot - : 0, - }); - } catch (error: any) { - return res - .status(500) - .send({ error: "An error occurred in /api/getabsslot" }); - } - } + errorHandlerWrapper(async (_req: Request, res: Response) => { + const getTipResponse = await getFromKoios(`tip`); + return res.send({ + abs_slot: + getTipResponse && getTipResponse.length + ? getTipResponse[0].abs_slot + : 0, + }); + }) ); app.get( "/api/getblock", oapi.path(resp200Ok500Bad), - async (req: any, res: any) => { - try { - const getTipResponse = await getFromKoios(`tip`); - res.send({ - block_no: - getTipResponse && getTipResponse.length - ? getTipResponse[0].block_no - : 0, - }); - } catch (error: any) { - return res - .status(500) - .send({ error: "An error occurred in /api/getblock" }); - } - } + errorHandlerWrapper(async (_req: Request, res: Response) => { + const getTipResponse = await getFromKoios(`tip`); + return res.send({ + block_no: + getTipResponse && getTipResponse.length + ? getTipResponse[0].block_no + : 0, + }); + }) ); app.get( "/api/gettip", oapi.path(resp200Ok500Bad), - async (req: any, res: any) => { - try { - const getTipResponse = await getFromKoios(`tip`); - res.send(getTipResponse[0]); - } catch (error: any) { - return res - .status(500) - .send({ error: "An error occurred in /api/gettip" }); - } - } + errorHandlerWrapper(async (_req: Request, res: Response) => { + const getTipResponse = await getFromKoios(`tip`); + res.send(getTipResponse[0]); + }) ); app.get( "/api/getepochparams", oapi.path(resp200Ok500Bad), - async (req: any, res: any) => { - try { - const getTipResponse = await getFromKoios(`tip`); - const getEpochParamsResponse = await getEpochParams( - getTipResponse && getTipResponse.length ? getTipResponse[0].epoch_no : 0 - ); - res.send(getEpochParamsResponse); - } catch (error: any) { - return res - .status(500) - .send({ error: "An error occurred in /api/getepochparams" }); - } - } + errorHandlerWrapper(async (_req: Request, res: Response) => { + const getTipResponse = await getFromKoios(`tip`); + const getEpochParamsResponse = await getEpochParams( + getTipResponse && getTipResponse.length ? getTipResponse[0].epoch_no : 0 + ); + return res.send(getEpochParamsResponse); + }) ); app.get( "/api/getprojects", oapi.path(resp200Ok), - async (req: any, res: any) => { + errorHandlerWrapper(async (_req: Request, res: Response) => { const projects = JSON.parse( fs.readFileSync(__dirname + "/public/json/projects.json", "utf8") ); return res.status(200).send(projects); - } + }) ); app.get( "/api/getpopupinfo", oapi.path(resp200Ok), - async (req: any, res: any) => { + errorHandlerWrapper(async (_req: Request, res: Response) => { const popupInfo = JSON.parse( fs.readFileSync(__dirname + "/public/json/popup.json", "utf8") ); return res.status(200).send(popupInfo); - } + }) ); -app.get("/api/getqueue", async (req: Request, res: Response) => { - const queue: GetQueueDto = await getFromVM("get_pending_tx_count"); - return res.status(200).send(queue); -}); +app.get( + "/api/getqueue", + errorHandlerWrapper(async (_req: Request, res: Response) => { + const queue: GetQueueDto = await getFromVM("get_pending_tx_count"); + return res.status(200).send(queue); + }) +); // host static files such as images app.use("/api/img", express.static(__dirname + "/public/img")); // Fallback to React app -app.get("*", (req, res) => { - res.sendFile("client/build/index.html", { root: "../" }); +app.get( + "*", + errorHandlerWrapper((_req: Request, res: Response) => { + return res.sendFile("client/build/index.html", { root: "../" }); + }) +); + +const server = app.listen(PORT, () => { + console.log(`Server listening on ${PORT}`); +}); + +process.on("SIGTERM", () => { + server.close(() => { + console.log("Server shutting down"); + }); }); + +app.use(errorHandlerMiddleware); diff --git a/server/middlewares/error-handler.ts b/server/middlewares/error-handler.ts new file mode 100644 index 00000000..02bdabdc --- /dev/null +++ b/server/middlewares/error-handler.ts @@ -0,0 +1,38 @@ +import { NextFunction, Request, Response } from "express"; +import { + createErrorResponse, + ErrorWithCode, + HttpStatusCode, +} from "../utils/error"; + +export default async function errorHandlerMiddleware( + error: unknown, + req: Request, + res: Response, + _next: NextFunction +) { + let statusCode: HttpStatusCode = HttpStatusCode.INTERNAL_SERVER_ERROR; + let errorMessage: string; + if (error instanceof ErrorWithCode) { + errorMessage = error.message; + console.log(`Error at ${req.url}: ${errorMessage}\n${error.stack}`); + statusCode = error.code; + } else if (error instanceof Error) { + errorMessage = error.message; + console.log(`Error at ${req.url}: ${errorMessage}\n${error.stack}`); + } else { + errorMessage = JSON.stringify(error); + console.log(`Error at ${req.url}: ${errorMessage}`); + } + return res.status(statusCode).send(createErrorResponse(errorMessage)); +} + +export const errorHandlerWrapper = + (func: Function) => + async (req: Request, res: Response, next: NextFunction) => { + try { + await func(req, res); + } catch (error) { + next(error); + } + }; diff --git a/server/package-lock.json b/server/package-lock.json index a1eb3142..0c28fb7c 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -8,27 +8,26 @@ "name": "tosidrop-server", "version": "1.0.0", "dependencies": { - "@emurgo/cardano-serialization-lib-nodejs": "^11.1.0", - "@wesleytodd/openapi": "^0.1.0", + "@emurgo/cardano-serialization-lib-nodejs": "^11.3.0", + "@reqlez/express-openapi": "^2.1.2", "axios": "^0.26.0", - "cors": "^2.8.5", + "bech32-converting": "^1.0.9", "dotenv": "^16.0.0", "express": "^4.17.3", "lodash": "^4.17.21", "lru-cache": "^7.14.1", "morgan": "^1.10.0", "ts-node": "^10.7.0", - "typescript": "^4.6.2" + "typescript": "^4.9.5" }, "devDependencies": { - "@types/cors": "^2.8.12", - "@types/express": "^4.17.13", + "@types/express": "^4.17.17", "@types/lodash": "^4.14.191", "nodemon": "^2.0.16" }, "engines": { - "node": ">=16", - "npm": ">=8" + "node": ">=18", + "npm": ">=9" } }, "node_modules/@babel/code-frame": { @@ -302,9 +301,9 @@ "peer": true }, "node_modules/@emurgo/cardano-serialization-lib-nodejs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-11.1.0.tgz", - "integrity": "sha512-lcKuKmeMGLLu45DqT2HYugHujsu1/WYKfrPzycAMpRk4FhZ0wWY2IFkD6We8+CQwNpXyQquy0psmRD5tChIxMA==" + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-11.3.0.tgz", + "integrity": "sha512-F1WXfvTtOZkJf3mSA9yToJaLCpPNOqyK5IljigS8fHxrLjSDEqVGVmQNM2R0NQTNsQLKxcSPBf0I3gukgoHnbQ==" }, "node_modules/@exodus/schemasafe": { "version": "1.0.0-rc.9", @@ -431,6 +430,136 @@ "node": ">=10" } }, + "node_modules/@reqlez/express-openapi": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@reqlez/express-openapi/-/express-openapi-2.1.2.tgz", + "integrity": "sha512-VtSAz0SzfpfCfUPnonnq7NXKK85oA2juMKbGq1mXMF+Y8viJRQJ6lP0O7IxNT0agHaBN60rybeLcOewadlFsmg==", + "dependencies": { + "ajv": "^6.10.2", + "http-errors": "^2.0.0", + "merge-deep": "^3.0.2", + "path-to-regexp": "^6.2.1", + "redoc": "^2.0.0-alpha.41", + "router": "^1.3.3", + "serve-static": "^1.13.2", + "swagger-parser": "^7.0.1", + "swagger-ui-dist": "^4.16.0" + } + }, + "node_modules/@reqlez/express-openapi/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@reqlez/express-openapi/node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@reqlez/express-openapi/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@reqlez/express-openapi/node_modules/json-schema-ref-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-7.1.4.tgz", + "integrity": "sha512-AD7bvav0vak1/63w3jH8F7eHId/4E4EPdMAEZhGxtjktteUv9dnNB/cJy6nVnMyoTPBJnLwFK6tiQPSTeleCtQ==", + "deprecated": "Please switch to @apidevtools/json-schema-ref-parser", + "dependencies": { + "call-me-maybe": "^1.0.1", + "js-yaml": "^3.13.1", + "ono": "^6.0.0" + } + }, + "node_modules/@reqlez/express-openapi/node_modules/json-schema-ref-parser/node_modules/ono": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ono/-/ono-6.0.1.tgz", + "integrity": "sha512-5rdYW/106kHqLeG22GE2MHKq+FlsxMERZev9DCzQX1zwkxnFwBivSn5i17a5O/rDmOJOdf4Wyt80UZljzx9+DA==" + }, + "node_modules/@reqlez/express-openapi/node_modules/ono": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ono/-/ono-5.1.0.tgz", + "integrity": "sha512-GgqRIUWErLX4l9Up0khRtbrlH8Fyj59A0nKv8V6pWEto38aUgnOGOOF7UmgFFLzFnDSc8REzaTXOc0hqEe7yIw==" + }, + "node_modules/@reqlez/express-openapi/node_modules/path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + }, + "node_modules/@reqlez/express-openapi/node_modules/swagger-methods": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-2.0.2.tgz", + "integrity": "sha512-/RNqvBZkH8+3S/FqBPejHxJxZenaYq3MrpeXnzi06aDIS39Mqf5YCUNb/ZBjsvFFt8h9FxfKs8EXPtcYdfLiRg==", + "deprecated": "This package is no longer being maintained." + }, + "node_modules/@reqlez/express-openapi/node_modules/swagger-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-7.0.1.tgz", + "integrity": "sha512-73FAlW1xqtkGLsxp41C4ASXPyEeJ9h38SGJRSDH0gSImjG5XzlbFb2EWsnhakLZfKOG/VsjzKQjO5aenmDSw/g==", + "dependencies": { + "call-me-maybe": "^1.0.1", + "json-schema-ref-parser": "^7.1.0", + "ono": "^5.0.1", + "openapi-schema-validation": "^0.4.2", + "openapi-types": "^1.3.5", + "swagger-methods": "^2.0.0", + "swagger-schema-official": "2.0.0-bab6bed", + "z-schema": "^4.1.0" + } + }, + "node_modules/@reqlez/express-openapi/node_modules/swagger-ui-dist": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.16.0.tgz", + "integrity": "sha512-PpoejNHzaw9lvI/RgQHesUDrZ3s+dbV2XpnuaxHU8TekEQYIOZ7WLCsCvMpMmgjXUZEg5ElTy67Ts1dp4A6eGQ==" + }, + "node_modules/@reqlez/express-openapi/node_modules/validator": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.9.0.tgz", + "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/@reqlez/express-openapi/node_modules/z-schema": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.4.tgz", + "integrity": "sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w==", + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.6.0" + }, + "bin": { + "z-schema": "bin/z-schema" + }, + "engines": { + "node": ">=6.0.0" + }, + "optionalDependencies": { + "commander": "^2.7.1" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -470,12 +599,6 @@ "@types/node": "*" } }, - "node_modules/@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, "node_modules/@types/eslint": { "version": "8.4.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", @@ -503,21 +626,21 @@ "peer": true }, "node_modules/@types/express": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", - "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", "dev": true, "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.31", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", - "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", "dev": true, "dependencies": { "@types/node": "*", @@ -715,22 +838,6 @@ "@xtuc/long": "4.2.2" } }, - "node_modules/@wesleytodd/openapi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@wesleytodd/openapi/-/openapi-0.1.0.tgz", - "integrity": "sha512-Lkv561gn4bnRVn7L2ArIpdbr1QFIrE1GMnVxIKcR/MN7wBttlzQcPaqAEzavLv59eC6JkPX4vXc+TiMncH1zNA==", - "dependencies": { - "ajv": "^6.10.2", - "http-errors": "^1.7.3", - "merge-deep": "^3.0.2", - "path-to-regexp": "^2.4.0", - "redoc": "^2.0.0-alpha.41", - "router": "^1.3.3", - "serve-static": "^1.13.2", - "swagger-parser": "^6.0.5", - "swagger-ui-dist": "^3.20.2" - } - }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -904,6 +1011,33 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -920,6 +1054,28 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "node_modules/bech32-converting": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bech32-converting/-/bech32-converting-1.0.9.tgz", + "integrity": "sha512-dKpGLNlOEO67pomo+f6Dowwd5bqvnOBIanBvFhCJ/3h0KF7PbpU/1Ujv+fbYNZBQVaTVQOdU57oiggMgtXfbUg==", + "dependencies": { + "bech32": "^2.0.0", + "crypto-addr-codec": "^0.1.7" + } + }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -929,6 +1085,11 @@ "node": ">=8" } }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -1017,6 +1178,37 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1238,23 +1430,25 @@ "url": "https://opencollective.com/core-js" } }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, + "node_modules/crypto-addr-codec": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.7.tgz", + "integrity": "sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==", + "dependencies": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, "node_modules/css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", @@ -1621,11 +1815,6 @@ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" }, - "node_modules/format-util": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", - "integrity": "sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==" - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1760,37 +1949,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "peer": true }, - "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-errors/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/http2-client": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", @@ -1807,6 +1965,25 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -1996,36 +2173,6 @@ "foreach": "^2.0.4" } }, - "node_modules/json-schema-ref-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz", - "integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==", - "dependencies": { - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.12.1", - "ono": "^4.0.11" - } - }, - "node_modules/json-schema-ref-parser/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/json-schema-ref-parser/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2545,14 +2692,6 @@ "node": ">= 0.8" } }, - "node_modules/ono": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz", - "integrity": "sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==", - "dependencies": { - "format-util": "^1.0.3" - } - }, "node_modules/openapi-sampler": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.3.0.tgz", @@ -2572,6 +2711,11 @@ "swagger-schema-official": "2.0.0-bab6bed" } }, + "node_modules/openapi-types": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-1.3.5.tgz", + "integrity": "sha512-11oi4zYorsgvg5yBarZplAqbpev5HkuVNPlZaPTknPDzAynq+lnJdXAmruGWP0s+dNYZS7bjM+xrTpJw7184Fg==" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2585,11 +2729,6 @@ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" }, - "node_modules/path-to-regexp": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.4.0.tgz", - "integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==" - }, "node_modules/perfect-scrollbar": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz", @@ -2872,6 +3011,14 @@ "node": ">=0.10.0" } }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "engines": { + "node": ">=8" + } + }, "node_modules/router": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/router/-/router-1.3.7.tgz", @@ -3031,6 +3178,14 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dependencies": { + "buffer": "6.0.3" + } + }, "node_modules/shallow-clone": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", @@ -3278,35 +3433,11 @@ "node": ">=4" } }, - "node_modules/swagger-methods": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-1.0.8.tgz", - "integrity": "sha512-G6baCwuHA+C5jf4FNOrosE4XlmGsdjbOjdBK4yuiDDj/ro9uR4Srj3OR84oQMT8F3qKp00tYNv0YN730oTHPZA==" - }, - "node_modules/swagger-parser": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-6.0.5.tgz", - "integrity": "sha512-UL47eu4+GRm5y+N7J+W6QQiqAJn2lojyqgMwS0EZgA55dXd5xmpQCsjUmH/Rf0eKDiG1kULc9VS515PxAyTDVw==", - "dependencies": { - "call-me-maybe": "^1.0.1", - "json-schema-ref-parser": "^6.0.3", - "ono": "^4.0.11", - "openapi-schema-validation": "^0.4.2", - "swagger-methods": "^1.0.8", - "swagger-schema-official": "2.0.0-bab6bed", - "z-schema": "^3.24.2" - } - }, "node_modules/swagger-schema-official": { "version": "2.0.0-bab6bed", "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", "integrity": "sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==" }, - "node_modules/swagger-ui-dist": { - "version": "3.52.5", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.52.5.tgz", - "integrity": "sha512-8z18eX8G/jbTXYzyNIaobrnD7PSN7yU/YkSasMmajrXtw0FGS64XjrKn5v37d36qmU3o1xLeuYnktshRr7uIFw==" - }, "node_modules/swagger2openapi": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", @@ -3495,9 +3626,9 @@ } }, "node_modules/typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3572,14 +3703,6 @@ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, - "node_modules/validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -3770,30 +3893,6 @@ "engines": { "node": ">=6" } - }, - "node_modules/z-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-3.25.1.tgz", - "integrity": "sha512-7tDlwhrBG+oYFdXNOjILSurpfQyuVgkRe3hB2q8TEssamDHB7BbLWYkYO98nTn0FibfdFroFKDjndbgufAgS/Q==", - "dependencies": { - "core-js": "^2.5.7", - "lodash.get": "^4.0.0", - "lodash.isequal": "^4.0.0", - "validator": "^10.0.0" - }, - "bin": { - "z-schema": "bin/z-schema" - }, - "optionalDependencies": { - "commander": "^2.7.1" - } - }, - "node_modules/z-schema/node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true } }, "dependencies": { @@ -4010,9 +4109,9 @@ "peer": true }, "@emurgo/cardano-serialization-lib-nodejs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-11.1.0.tgz", - "integrity": "sha512-lcKuKmeMGLLu45DqT2HYugHujsu1/WYKfrPzycAMpRk4FhZ0wWY2IFkD6We8+CQwNpXyQquy0psmRD5tChIxMA==" + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-11.3.0.tgz", + "integrity": "sha512-F1WXfvTtOZkJf3mSA9yToJaLCpPNOqyK5IljigS8fHxrLjSDEqVGVmQNM2R0NQTNsQLKxcSPBf0I3gukgoHnbQ==" }, "@exodus/schemasafe": { "version": "1.0.0-rc.9", @@ -4124,6 +4223,121 @@ } } }, + "@reqlez/express-openapi": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@reqlez/express-openapi/-/express-openapi-2.1.2.tgz", + "integrity": "sha512-VtSAz0SzfpfCfUPnonnq7NXKK85oA2juMKbGq1mXMF+Y8viJRQJ6lP0O7IxNT0agHaBN60rybeLcOewadlFsmg==", + "requires": { + "ajv": "^6.10.2", + "http-errors": "^2.0.0", + "merge-deep": "^3.0.2", + "path-to-regexp": "^6.2.1", + "redoc": "^2.0.0-alpha.41", + "router": "^1.3.3", + "serve-static": "^1.13.2", + "swagger-parser": "^7.0.1", + "swagger-ui-dist": "^4.16.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-ref-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-7.1.4.tgz", + "integrity": "sha512-AD7bvav0vak1/63w3jH8F7eHId/4E4EPdMAEZhGxtjktteUv9dnNB/cJy6nVnMyoTPBJnLwFK6tiQPSTeleCtQ==", + "requires": { + "call-me-maybe": "^1.0.1", + "js-yaml": "^3.13.1", + "ono": "^6.0.0" + }, + "dependencies": { + "ono": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ono/-/ono-6.0.1.tgz", + "integrity": "sha512-5rdYW/106kHqLeG22GE2MHKq+FlsxMERZev9DCzQX1zwkxnFwBivSn5i17a5O/rDmOJOdf4Wyt80UZljzx9+DA==" + } + } + }, + "ono": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ono/-/ono-5.1.0.tgz", + "integrity": "sha512-GgqRIUWErLX4l9Up0khRtbrlH8Fyj59A0nKv8V6pWEto38aUgnOGOOF7UmgFFLzFnDSc8REzaTXOc0hqEe7yIw==" + }, + "path-to-regexp": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", + "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + }, + "swagger-methods": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-2.0.2.tgz", + "integrity": "sha512-/RNqvBZkH8+3S/FqBPejHxJxZenaYq3MrpeXnzi06aDIS39Mqf5YCUNb/ZBjsvFFt8h9FxfKs8EXPtcYdfLiRg==" + }, + "swagger-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-7.0.1.tgz", + "integrity": "sha512-73FAlW1xqtkGLsxp41C4ASXPyEeJ9h38SGJRSDH0gSImjG5XzlbFb2EWsnhakLZfKOG/VsjzKQjO5aenmDSw/g==", + "requires": { + "call-me-maybe": "^1.0.1", + "json-schema-ref-parser": "^7.1.0", + "ono": "^5.0.1", + "openapi-schema-validation": "^0.4.2", + "openapi-types": "^1.3.5", + "swagger-methods": "^2.0.0", + "swagger-schema-official": "2.0.0-bab6bed", + "z-schema": "^4.1.0" + } + }, + "swagger-ui-dist": { + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.16.0.tgz", + "integrity": "sha512-PpoejNHzaw9lvI/RgQHesUDrZ3s+dbV2XpnuaxHU8TekEQYIOZ7WLCsCvMpMmgjXUZEg5ElTy67Ts1dp4A6eGQ==" + }, + "validator": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.9.0.tgz", + "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==" + }, + "z-schema": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.4.tgz", + "integrity": "sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w==", + "requires": { + "commander": "^2.7.1", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "validator": "^13.6.0" + } + } + } + }, "@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -4163,12 +4377,6 @@ "@types/node": "*" } }, - "@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, "@types/eslint": { "version": "8.4.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", @@ -4196,21 +4404,21 @@ "peer": true }, "@types/express": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", - "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", "dev": true, "requires": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "@types/express-serve-static-core": { - "version": "4.17.31", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", - "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", "dev": true, "requires": { "@types/node": "*", @@ -4408,22 +4616,6 @@ "@xtuc/long": "4.2.2" } }, - "@wesleytodd/openapi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@wesleytodd/openapi/-/openapi-0.1.0.tgz", - "integrity": "sha512-Lkv561gn4bnRVn7L2ArIpdbr1QFIrE1GMnVxIKcR/MN7wBttlzQcPaqAEzavLv59eC6JkPX4vXc+TiMncH1zNA==", - "requires": { - "ajv": "^6.10.2", - "http-errors": "^1.7.3", - "merge-deep": "^3.0.2", - "path-to-regexp": "^2.4.0", - "redoc": "^2.0.0-alpha.41", - "router": "^1.3.3", - "serve-static": "^1.13.2", - "swagger-parser": "^6.0.5", - "swagger-ui-dist": "^3.20.2" - } - }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -4562,6 +4754,19 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -4577,12 +4782,36 @@ } } }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "bech32-converting": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bech32-converting/-/bech32-converting-1.0.9.tgz", + "integrity": "sha512-dKpGLNlOEO67pomo+f6Dowwd5bqvnOBIanBvFhCJ/3h0KF7PbpU/1Ujv+fbYNZBQVaTVQOdU57oiggMgtXfbUg==", + "requires": { + "bech32": "^2.0.0", + "crypto-addr-codec": "^0.1.7" + } + }, + "big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, "body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -4647,6 +4876,23 @@ "update-browserslist-db": "^1.0.9" } }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "requires": { + "base-x": "^3.0.2" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4809,20 +5055,25 @@ "integrity": "sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA==", "peer": true }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, + "crypto-addr-codec": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.7.tgz", + "integrity": "sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==", + "requires": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, "css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", @@ -5108,11 +5359,6 @@ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", "integrity": "sha512-k6GAGDyqLe9JaebCsFCoudPPWfihKu8pylYXRlqP1J7ms39iPoTtk2fviNglIeQEwdh0bQeKJ01ZPyuyQvKzwg==" }, - "format-util": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/format-util/-/format-util-1.0.5.tgz", - "integrity": "sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg==" - }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -5212,30 +5458,6 @@ } } }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" - } - } - }, "http2-client": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.5.tgz", @@ -5249,6 +5471,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", @@ -5389,35 +5616,6 @@ "foreach": "^2.0.4" } }, - "json-schema-ref-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-6.1.0.tgz", - "integrity": "sha512-pXe9H1m6IgIpXmE5JSb8epilNTGsmTb2iPohAXpOdhqGFbQjNeHHsZxU+C8w6T81GZxSPFLeUoqDJmzxx5IGuw==", - "requires": { - "call-me-maybe": "^1.0.1", - "js-yaml": "^3.12.1", - "ono": "^4.0.11" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - } - } - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5785,14 +5983,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" }, - "ono": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/ono/-/ono-4.0.11.tgz", - "integrity": "sha512-jQ31cORBFE6td25deYeD80wxKBMj+zBmHTrVxnc6CKhx8gho6ipmWM5zj/oeoqioZ99yqBls9Z/9Nss7J26G2g==", - "requires": { - "format-util": "^1.0.3" - } - }, "openapi-sampler": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/openapi-sampler/-/openapi-sampler-1.3.0.tgz", @@ -5812,6 +6002,11 @@ "swagger-schema-official": "2.0.0-bab6bed" } }, + "openapi-types": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-1.3.5.tgz", + "integrity": "sha512-11oi4zYorsgvg5yBarZplAqbpev5HkuVNPlZaPTknPDzAynq+lnJdXAmruGWP0s+dNYZS7bjM+xrTpJw7184Fg==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -5822,11 +6017,6 @@ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" }, - "path-to-regexp": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.4.0.tgz", - "integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==" - }, "perfect-scrollbar": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz", @@ -6045,6 +6235,11 @@ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, + "ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==" + }, "router": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/router/-/router-1.3.7.tgz", @@ -6172,6 +6367,14 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "requires": { + "buffer": "6.0.3" + } + }, "shallow-clone": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", @@ -6365,35 +6568,11 @@ "has-flag": "^3.0.0" } }, - "swagger-methods": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-1.0.8.tgz", - "integrity": "sha512-G6baCwuHA+C5jf4FNOrosE4XlmGsdjbOjdBK4yuiDDj/ro9uR4Srj3OR84oQMT8F3qKp00tYNv0YN730oTHPZA==" - }, - "swagger-parser": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-6.0.5.tgz", - "integrity": "sha512-UL47eu4+GRm5y+N7J+W6QQiqAJn2lojyqgMwS0EZgA55dXd5xmpQCsjUmH/Rf0eKDiG1kULc9VS515PxAyTDVw==", - "requires": { - "call-me-maybe": "^1.0.1", - "json-schema-ref-parser": "^6.0.3", - "ono": "^4.0.11", - "openapi-schema-validation": "^0.4.2", - "swagger-methods": "^1.0.8", - "swagger-schema-official": "2.0.0-bab6bed", - "z-schema": "^3.24.2" - } - }, "swagger-schema-official": { "version": "2.0.0-bab6bed", "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", "integrity": "sha512-rCC0NWGKr/IJhtRuPq/t37qvZHI/mH4I4sxflVM+qgVe5Z2uOCivzWaVbuioJaB61kvm5UvB7b49E+oBY0M8jA==" }, - "swagger-ui-dist": { - "version": "3.52.5", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.52.5.tgz", - "integrity": "sha512-8z18eX8G/jbTXYzyNIaobrnD7PSN7yU/YkSasMmajrXtw0FGS64XjrKn5v37d36qmU3o1xLeuYnktshRr7uIFw==" - }, "swagger2openapi": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.8.tgz", @@ -6507,9 +6686,9 @@ } }, "typescript": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz", - "integrity": "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==" + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" }, "undefsafe": { "version": "2.0.5", @@ -6555,11 +6734,6 @@ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, - "validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" - }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -6698,25 +6872,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" - }, - "z-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-3.25.1.tgz", - "integrity": "sha512-7tDlwhrBG+oYFdXNOjILSurpfQyuVgkRe3hB2q8TEssamDHB7BbLWYkYO98nTn0FibfdFroFKDjndbgufAgS/Q==", - "requires": { - "commander": "^2.7.1", - "core-js": "^2.5.7", - "lodash.get": "^4.0.0", - "lodash.isequal": "^4.0.0", - "validator": "^10.0.0" - }, - "dependencies": { - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" - } - } } } } diff --git a/server/package.json b/server/package.json index 7125c057..0c3066b0 100644 --- a/server/package.json +++ b/server/package.json @@ -7,8 +7,8 @@ "url": "git://github.com/TosiDrop/vm-frontend.git" }, "engines": { - "node": ">=16", - "npm": ">=8" + "node": ">=18", + "npm": ">=9" }, "main": "index.ts", "scripts": { @@ -21,21 +21,20 @@ "proxy": "http://localhost:3000", "keywords": [], "dependencies": { - "@emurgo/cardano-serialization-lib-nodejs": "^11.1.0", - "@wesleytodd/openapi": "^0.1.0", + "@emurgo/cardano-serialization-lib-nodejs": "^11.3.0", + "@reqlez/express-openapi": "^2.1.2", "axios": "^0.26.0", - "cors": "^2.8.5", + "bech32-converting": "^1.0.9", "dotenv": "^16.0.0", "express": "^4.17.3", "lodash": "^4.17.21", "lru-cache": "^7.14.1", "morgan": "^1.10.0", "ts-node": "^10.7.0", - "typescript": "^4.6.2" + "typescript": "^4.9.5" }, "devDependencies": { - "@types/cors": "^2.8.12", - "@types/express": "^4.17.13", + "@types/express": "^4.17.17", "@types/lodash": "^4.14.191", "nodemon": "^2.0.16" } diff --git a/server/routes/tx.ts b/server/routes/tx.ts new file mode 100644 index 00000000..739d8cbc --- /dev/null +++ b/server/routes/tx.ts @@ -0,0 +1,48 @@ +import express, { Request, Response } from "express"; +import { StakeTxDto } from "../../client/src/entities/dto"; +import { errorHandlerWrapper } from "../middlewares/error-handler"; +import { TxService } from "../service/tx"; +import { createErrorWithCode, HttpStatusCode } from "../utils/error"; +const router = express.Router(); + +/** get unsigned transaction */ +router.get( + "/stake", + errorHandlerWrapper(async function ( + req: Request, + res: Response + ) { + const { poolId, address } = req.query; + if (!poolId) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Pool ID must be specified" + ); + } + if (!address) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "User address must be specified" + ); + } + const delegationTx = await TxService.createDelegationTx(poolId, address); + return res.status(200).send(delegationTx); + }) +); + +/** post signed transaction */ +router.post( + "/stake", + errorHandlerWrapper(async function ( + req: Request, + res: Response + ) { + const { signedWitness, txBody } = req.body; + const tx = await TxService.createTxToSubmit(signedWitness, txBody); + return res.status(201).send({ + tx, + }); + }) +); + +export default router; diff --git a/server/service/cardano.ts b/server/service/cardano.ts new file mode 100644 index 00000000..30809ed5 --- /dev/null +++ b/server/service/cardano.ts @@ -0,0 +1,63 @@ +import { + Address, + BaseAddress, + RewardAddress, +} from "@emurgo/cardano-serialization-lib-nodejs"; +import { CARDANO_NETWORK } from ".."; +import { createErrorWithCode, HttpStatusCode } from "../utils/error"; +import { CardanoNetwork } from "../utils/interfaces"; + +export namespace CardanoService { + export function getStakeAddress(address: string): string { + let rewardAddressBytes = new Uint8Array(29); + switch (CARDANO_NETWORK) { + case CardanoNetwork.mainnet: + rewardAddressBytes.set([0xe1], 0); + break; + case CardanoNetwork.preview: + default: + rewardAddressBytes.set([0xe0], 0); + break; + } + + const addressObject = Address.from_bech32(address); + const baseAddress = BaseAddress.from_address(addressObject); + if (baseAddress == null) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Address id invalid. Failed to derive stake address" + ); + } + rewardAddressBytes.set(baseAddress.stake_cred().to_bytes().slice(4, 32), 1); + + let rewardAddress = RewardAddress.from_address( + Address.from_bytes(rewardAddressBytes) + ); + + if (rewardAddress == null) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Address id invalid. Failed to derive stake address" + ); + } + + return rewardAddress.to_address().to_bech32(); + } + + export function getStakeCredHash(addressInBech32: string) { + const address = Address.from_bech32(addressInBech32); + const baseAddress = BaseAddress.from_address(address); + + if (baseAddress?.stake_cred().kind() !== 0) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Address is invalid" + ); + } + + const buffer = Buffer.from( + baseAddress.stake_cred().to_keyhash()!.to_bytes() + ); + return buffer.toString("hex"); + } +} diff --git a/server/service/koios.ts b/server/service/koios.ts new file mode 100644 index 00000000..aba0ef46 --- /dev/null +++ b/server/service/koios.ts @@ -0,0 +1,87 @@ +import axios from "axios"; +import { VM_KOIOS_URL } from ".."; +import { KoiosTypes } from "../types/koios"; +import { createErrorWithCode, HttpStatusCode } from "../utils/error"; + +export namespace KoiosService { + export async function getAccountInformation( + stakeAddress: string + ): Promise { + const action = "account_info"; + const params = { + _stake_addresses: [stakeAddress], + }; + const response = await postFromKoios( + action, + params + ); + if (response.length === 0) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Fail to get account information" + ); + } + return response[0]; + } + + export async function getProtocolParameters(): Promise { + const tip = await getBlockchainTip(); + const currentEpoch = tip.epoch_no; + const parameters = await getFromKoios( + "epoch_params", + `_epoch_no=${currentEpoch}` + ); + return parameters[0]; + } + + export async function getBlockchainTip(): Promise { + const tips = await getFromKoios("tip"); + if (tips.length === 0) { + throw createErrorWithCode(HttpStatusCode.BAD_REQUEST, "Fail to get tip"); + } + return tips[0]; + } + + export async function getAddressesFromStakeAddress( + stakeAddress: string + ): Promise { + const response = await postFromKoios< + { stake_address: string; addresses: string[] }[] + >("account_addresses", { _stake_addresses: [stakeAddress] }); + if (response.length === 0) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Fail to get addresses" + ); + } + return response[0].addresses; + } + + export async function getAddressesInformation( + addresses: string[] + ): Promise { + const response = await postFromKoios( + "address_info", + { _addresses: [addresses] } + ); + if (response.length === 0) { + throw createErrorWithCode( + HttpStatusCode.BAD_REQUEST, + "Fail to get address information" + ); + } + return response; + } + + async function getFromKoios(action: string, params?: any): Promise { + return ( + await axios.get( + `${VM_KOIOS_URL}/${action}${params ? "?" + params : ""}` + ) + ).data; + } + + async function postFromKoios(action: string, params?: any): Promise { + return (await axios.post(`${VM_KOIOS_URL}/${action}`, params)).data; + } +} diff --git a/server/service/tx.ts b/server/service/tx.ts new file mode 100644 index 00000000..993346b0 --- /dev/null +++ b/server/service/tx.ts @@ -0,0 +1,147 @@ +import { + Address, + BigNum, + Certificate, + Certificates, + Ed25519KeyHash, + LinearFee, + StakeCredential, + StakeDelegation, + StakeRegistration, + Transaction, + TransactionBody, + TransactionBuilder, + TransactionBuilderConfigBuilder, + TransactionHash, + TransactionInput, + TransactionOutput, + TransactionUnspentOutput, + TransactionUnspentOutputs, + TransactionWitnessSet, + Value, +} from "@emurgo/cardano-serialization-lib-nodejs"; +import { CardanoService } from "./cardano"; +import { KoiosService } from "./koios"; + +enum StakeCredentialKind { + StakeKeyHash = 0, + StakeScriptHash = 1, +} + +enum PaymentCredential { + PaymentKeyHash = 0, + PaymentScriptHash = 1, +} + +export namespace TxService { + export async function createDelegationTx( + poolId: string, + delegatorAddress: string + ) { + const [tip, stakeAddress, epochParameters] = await Promise.all([ + KoiosService.getBlockchainTip(), + CardanoService.getStakeAddress(delegatorAddress), + KoiosService.getProtocolParameters(), + ]); + + const stakeCredHash = CardanoService.getStakeCredHash(delegatorAddress); + + const accountInformation = await KoiosService.getAccountInformation( + stakeAddress + ); + + const { + coins_per_utxo_size, + min_fee_a, + min_fee_b, + key_deposit, + pool_deposit, + max_tx_size, + max_val_size, + } = epochParameters; + + const feeAlgo = LinearFee.new( + BigNum.from_str(min_fee_a.toString()), + BigNum.from_str(min_fee_b.toString()) + ); + + const txBuilderConfig = TransactionBuilderConfigBuilder.new() + .coins_per_utxo_byte(BigNum.from_str(coins_per_utxo_size)) + .fee_algo(feeAlgo) + .key_deposit(BigNum.from_str(key_deposit)) + .pool_deposit(BigNum.from_str(pool_deposit)) + .max_tx_size(Number(max_tx_size)) + .max_value_size(Number(max_val_size)) + .prefer_pure_change(true) + .build(); + + const txBuilder = TransactionBuilder.new(txBuilderConfig); + txBuilder.set_ttl_bignum(BigNum.from_str((tip.abs_slot + 3600).toString())); + + const certs = Certificates.new(); + + if (accountInformation.status !== "registered") { + certs.add( + Certificate.new_stake_registration( + StakeRegistration.new( + StakeCredential.from_keyhash(Ed25519KeyHash.from_hex(stakeCredHash)) + ) + ) + ); + } + + certs.add( + Certificate.new_stake_delegation( + StakeDelegation.new( + StakeCredential.from_keyhash(Ed25519KeyHash.from_hex(stakeCredHash)), + Ed25519KeyHash.from_bech32(poolId) + ) + ) + ); + + txBuilder.set_certs(certs); + + const addressesRelatedToStakeAddress = + await KoiosService.getAddressesFromStakeAddress(stakeAddress); + const getAddressesInformation = await KoiosService.getAddressesInformation( + addressesRelatedToStakeAddress + ); + + const utxosOutput = TransactionUnspentOutputs.new(); + getAddressesInformation.forEach((info) => { + const utxos = info.utxo_set; + utxos.forEach((utxo) => { + const input = TransactionInput.new( + TransactionHash.from_hex(utxo.tx_hash), + Number(utxo.tx_index) + ); + const output = TransactionOutput.new( + Address.from_bech32(info.address), + Value.new(BigNum.from_str(utxo.value)) + ); + utxosOutput.add(TransactionUnspentOutput.new(input, output)); + }); + }); + + txBuilder.add_inputs_from(utxosOutput, 0); + + txBuilder.add_change_if_needed(Address.from_bech32(delegatorAddress)); + + const txBody = txBuilder.build(); + + const transaction = Transaction.new(txBody, TransactionWitnessSet.new()); + + return { + witness: transaction.to_hex(), + txBody: txBody.to_hex(), + }; + } + + export async function createTxToSubmit(witness: string, txBody: string) { + const tx = Transaction.new( + TransactionBody.from_hex(txBody), + TransactionWitnessSet.from_hex(witness) + ); + return tx.to_hex(); + } +} diff --git a/server/types/koios.ts b/server/types/koios.ts new file mode 100644 index 00000000..91bb6ff4 --- /dev/null +++ b/server/types/koios.ts @@ -0,0 +1,89 @@ +export namespace KoiosTypes { + export type AccountStatus = "registered" | "not registered"; + + export interface AccountInfo { + stake_address: string; + status: AccountStatus; + delegated_pool: string; + total_balance: string; + utxo: string; + rewards: string; + withdrawals: string; + rewards_available: string; + reserves: string; + treasury: string; + } + + export interface EpochProtocolParameters { + epoch_no: number; + min_fee_a: number; + min_fee_b: number; + max_block_size: number; + max_tx_size: number; + max_bh_size: number; + key_deposit: string; + pool_deposit: string; + max_epoch: number; + optimal_pool_count: number; + influence: number; + monetary_expand_rate: number; + treasury_growth_rate: number; + decentralisation: number; + extra_entropy: string; + protocol_major: number; + protocol_minor: number; + min_utxo_value: string; + min_pool_cost: string; + nonce: string; + block_hash: string; + cost_models: string; + price_mem: number; + price_step: number; + max_tx_ex_mem: number; + max_tx_ex_steps: number; + max_block_ex_mem: number; + max_block_ex_steps: number; + max_val_size: number; + collateral_percent: number; + max_collateral_inputs: number; + coins_per_utxo_size: string; + } + + export interface EpochInformation { + epoch_no: number; + out_sum: string; + fees: string; + tx_count: number; + blk_count: number; + start_time: number; + end_time: number; + first_block_time: number; + last_block_time: number; + active_stake: string; + total_rewards: string; + avg_blk_reward: string; + } + + export interface BlockchainTip { + hash: string; + epoch_no: number; + abs_slot: number; + epoch_slot: number; + block_no: number; + block_time: number; + } + + export interface AddressInformation { + address: string; + balance: string; + stake_address: string | null; + script_address: boolean; + utxo_set: UTxO[]; + } + + export interface UTxO { + value: string; + tx_hash: string; + tx_index: string; + } +} diff --git a/server/utils/error.ts b/server/utils/error.ts index b1f9b1eb..efdd0cdf 100644 --- a/server/utils/error.ts +++ b/server/utils/error.ts @@ -1,7 +1,394 @@ -export function logError(e: unknown) { - if (e instanceof Error) { - console.log(e.message, e.stack); - } else { - console.log(JSON.stringify(e)); +import { ServerErrorDto } from "../../client/src/entities/dto"; + +export class ErrorWithCode extends Error { + code: HttpStatusCode; + constructor(code: HttpStatusCode, message: string) { + super(message); + this.code = code; } } + +export function createErrorWithCode(code: HttpStatusCode, message: string) { + return new ErrorWithCode(code, message); +} + +export function createErrorResponse(error: string): ServerErrorDto { + return { + error, + }; +} + +export enum HttpStatusCode { + /** + * The server has received the request headers and the client should proceed to send the request body + * (in the case of a request for which a body needs to be sent; for example, a POST request). + * Sending a large request body to a server after a request has been rejected for inappropriate headers would be inefficient. + * To have a server check the request's headers, a client must send Expect: 100-continue as a header in its initial request + * and receive a 100 Continue status code in response before sending the body. The response 417 Expectation Failed indicates the request should not be continued. + */ + CONTINUE = 100, + + /** + * The requester has asked the server to switch protocols and the server has agreed to do so. + */ + SWITCHING_PROTOCOLS = 101, + + /** + * A WebDAV request may contain many sub-requests involving file operations, requiring a long time to complete the request. + * This code indicates that the server has received and is processing the request, but no response is available yet. + * This prevents the client from timing out and assuming the request was lost. + */ + PROCESSING = 102, + + /** + * Standard response for successful HTTP requests. + * The actual response will depend on the request method used. + * In a GET request, the response will contain an entity corresponding to the requested resource. + * In a POST request, the response will contain an entity describing or containing the result of the action. + */ + OK = 200, + + /** + * The request has been fulfilled, resulting in the creation of a new resource. + */ + CREATED = 201, + + /** + * The request has been accepted for processing, but the processing has not been completed. + * The request might or might not be eventually acted upon, and may be disallowed when processing occurs. + */ + ACCEPTED = 202, + + /** + * SINCE HTTP/1.1 + * The server is a transforming proxy that received a 200 OK from its origin, + * but is returning a modified version of the origin's response. + */ + NON_AUTHORITATIVE_INFORMATION = 203, + + /** + * The server successfully processed the request and is not returning any content. + */ + NO_CONTENT = 204, + + /** + * The server successfully processed the request, but is not returning any content. + * Unlike a 204 response, this response requires that the requester reset the document view. + */ + RESET_CONTENT = 205, + + /** + * The server is delivering only part of the resource (byte serving) due to a range header sent by the client. + * The range header is used by HTTP clients to enable resuming of interrupted downloads, + * or split a download into multiple simultaneous streams. + */ + PARTIAL_CONTENT = 206, + + /** + * The message body that follows is an XML message and can contain a number of separate response codes, + * depending on how many sub-requests were made. + */ + MULTI_STATUS = 207, + + /** + * The members of a DAV binding have already been enumerated in a preceding part of the (multistatus) response, + * and are not being included again. + */ + ALREADY_REPORTED = 208, + + /** + * The server has fulfilled a request for the resource, + * and the response is a representation of the result of one or more instance-manipulations applied to the current instance. + */ + IM_USED = 226, + + /** + * Indicates multiple options for the resource from which the client may choose (via agent-driven content negotiation). + * For example, this code could be used to present multiple video format options, + * to list files with different filename extensions, or to suggest word-sense disambiguation. + */ + MULTIPLE_CHOICES = 300, + + /** + * This and all future requests should be directed to the given URI. + */ + MOVED_PERMANENTLY = 301, + + /** + * This is an example of industry practice contradicting the standard. + * The HTTP/1.0 specification (RFC 1945) required the client to perform a temporary redirect + * (the original describing phrase was "Moved Temporarily"), but popular browsers implemented 302 + * with the functionality of a 303 See Other. Therefore, HTTP/1.1 added status codes 303 and 307 + * to distinguish between the two behaviours. However, some Web applications and frameworks + * use the 302 status code as if it were the 303. + */ + FOUND = 302, + + /** + * SINCE HTTP/1.1 + * The response to the request can be found under another URI using a GET method. + * When received in response to a POST (or PUT/DELETE), the client should presume that + * the server has received the data and should issue a redirect with a separate GET message. + */ + SEE_OTHER = 303, + + /** + * Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-None-Match. + * In such case, there is no need to retransmit the resource since the client still has a previously-downloaded copy. + */ + NOT_MODIFIED = 304, + + /** + * SINCE HTTP/1.1 + * The requested resource is available only through a proxy, the address for which is provided in the response. + * Many HTTP clients (such as Mozilla and Internet Explorer) do not correctly handle responses with this status code, primarily for security reasons. + */ + USE_PROXY = 305, + + /** + * No longer used. Originally meant "Subsequent requests should use the specified proxy." + */ + SWITCH_PROXY = 306, + + /** + * SINCE HTTP/1.1 + * In this case, the request should be repeated with another URI; however, future requests should still use the original URI. + * In contrast to how 302 was historically implemented, the request method is not allowed to be changed when reissuing the original request. + * For example, a POST request should be repeated using another POST request. + */ + TEMPORARY_REDIRECT = 307, + + /** + * The request and all future requests should be repeated using another URI. + * 307 and 308 parallel the behaviors of 302 and 301, but do not allow the HTTP method to change. + * So, for example, submitting a form to a permanently redirected resource may continue smoothly. + */ + PERMANENT_REDIRECT = 308, + + /** + * The server cannot or will not process the request due to an apparent client error + * (e.g., malformed request syntax, too large size, invalid request message framing, or deceptive request routing). + */ + BAD_REQUEST = 400, + + /** + * Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet + * been provided. The response must include a WWW-Authenticate header field containing a challenge applicable to the + * requested resource. See Basic access authentication and Digest access authentication. 401 semantically means + * "unauthenticated",i.e. the user does not have the necessary credentials. + */ + UNAUTHORIZED = 401, + + /** + * Reserved for future use. The original intention was that this code might be used as part of some form of digital + * cash or micro payment scheme, but that has not happened, and this code is not usually used. + * Google Developers API uses this status if a particular developer has exceeded the daily limit on requests. + */ + PAYMENT_REQUIRED = 402, + + /** + * The request was valid, but the server is refusing action. + * The user might not have the necessary permissions for a resource. + */ + FORBIDDEN = 403, + + /** + * The requested resource could not be found but may be available in the future. + * Subsequent requests by the client are permissible. + */ + NOT_FOUND = 404, + + /** + * A request method is not supported for the requested resource; + * for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource. + */ + METHOD_NOT_ALLOWED = 405, + + /** + * The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request. + */ + NOT_ACCEPTABLE = 406, + + /** + * The client must first authenticate itself with the proxy. + */ + PROXY_AUTHENTICATION_REQUIRED = 407, + + /** + * The server timed out waiting for the request. + * According to HTTP specifications: + * "The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time." + */ + REQUEST_TIMEOUT = 408, + + /** + * Indicates that the request could not be processed because of conflict in the request, + * such as an edit conflict between multiple simultaneous updates. + */ + CONFLICT = 409, + + /** + * Indicates that the resource requested is no longer available and will not be available again. + * This should be used when a resource has been intentionally removed and the resource should be purged. + * Upon receiving a 410 status code, the client should not request the resource in the future. + * Clients such as search engines should remove the resource from their indices. + * Most use cases do not require clients and search engines to purge the resource, and a "404 Not Found" may be used instead. + */ + GONE = 410, + + /** + * The request did not specify the length of its content, which is required by the requested resource. + */ + LENGTH_REQUIRED = 411, + + /** + * The server does not meet one of the preconditions that the requester put on the request. + */ + PRECONDITION_FAILED = 412, + + /** + * The request is larger than the server is willing or able to process. Previously called "Request Entity Too Large". + */ + PAYLOAD_TOO_LARGE = 413, + + /** + * The URI provided was too long for the server to process. Often the result of too much data being encoded as a query-string of a GET request, + * in which case it should be converted to a POST request. + * Called "Request-URI Too Long" previously. + */ + URI_TOO_LONG = 414, + + /** + * The request entity has a media type which the server or resource does not support. + * For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format. + */ + UNSUPPORTED_MEDIA_TYPE = 415, + + /** + * The client has asked for a portion of the file (byte serving), but the server cannot supply that portion. + * For example, if the client asked for a part of the file that lies beyond the end of the file. + * Called "Requested Range Not Satisfiable" previously. + */ + RANGE_NOT_SATISFIABLE = 416, + + /** + * The server cannot meet the requirements of the Expect request-header field. + */ + EXPECTATION_FAILED = 417, + + /** + * This code was defined in 1998 as one of the traditional IETF April Fools' jokes, in RFC 2324, Hyper Text Coffee Pot Control Protocol, + * and is not expected to be implemented by actual HTTP servers. The RFC specifies this code should be returned by + * teapots requested to brew coffee. This HTTP status is used as an Easter egg in some websites, including Google.com. + */ + I_AM_A_TEAPOT = 418, + + /** + * The request was directed at a server that is not able to produce a response (for example because a connection reuse). + */ + MISDIRECTED_REQUEST = 421, + + /** + * The request was well-formed but was unable to be followed due to semantic errors. + */ + UNPROCESSABLE_ENTITY = 422, + + /** + * The resource that is being accessed is locked. + */ + LOCKED = 423, + + /** + * The request failed due to failure of a previous request (e.g., a PROPPATCH). + */ + FAILED_DEPENDENCY = 424, + + /** + * The client should switch to a different protocol such as TLS/1.0, given in the Upgrade header field. + */ + UPGRADE_REQUIRED = 426, + + /** + * The origin server requires the request to be conditional. + * Intended to prevent "the 'lost update' problem, where a client + * GETs a resource's state, modifies it, and PUTs it back to the server, + * when meanwhile a third party has modified the state on the server, leading to a conflict." + */ + PRECONDITION_REQUIRED = 428, + + /** + * The user has sent too many requests in a given amount of time. Intended for use with rate-limiting schemes. + */ + TOO_MANY_REQUESTS = 429, + + /** + * The server is unwilling to process the request because either an individual header field, + * or all the header fields collectively, are too large. + */ + REQUEST_HEADER_FIELDS_TOO_LARGE = 431, + + /** + * A server operator has received a legal demand to deny access to a resource or to a set of resources + * that includes the requested resource. The code 451 was chosen as a reference to the novel Fahrenheit 451. + */ + UNAVAILABLE_FOR_LEGAL_REASONS = 451, + + /** + * A generic error message, given when an unexpected condition was encountered and no more specific message is suitable. + */ + INTERNAL_SERVER_ERROR = 500, + + /** + * The server either does not recognize the request method, or it lacks the ability to fulfill the request. + * Usually this implies future availability (e.g., a new feature of a web-service API). + */ + NOT_IMPLEMENTED = 501, + + /** + * The server was acting as a gateway or proxy and received an invalid response from the upstream server. + */ + BAD_GATEWAY = 502, + + /** + * The server is currently unavailable (because it is overloaded or down for maintenance). + * Generally, this is a temporary state. + */ + SERVICE_UNAVAILABLE = 503, + + /** + * The server was acting as a gateway or proxy and did not receive a timely response from the upstream server. + */ + GATEWAY_TIMEOUT = 504, + + /** + * The server does not support the HTTP protocol version used in the request + */ + HTTP_VERSION_NOT_SUPPORTED = 505, + + /** + * Transparent content negotiation for the request results in a circular reference. + */ + VARIANT_ALSO_NEGOTIATES = 506, + + /** + * The server is unable to store the representation needed to complete the request. + */ + INSUFFICIENT_STORAGE = 507, + + /** + * The server detected an infinite loop while processing the request. + */ + LOOP_DETECTED = 508, + + /** + * Further extensions to the request are required for the server to fulfill it. + */ + NOT_EXTENDED = 510, + + /** + * The client needs to authenticate to gain network access. + * Intended for use by intercepting proxies used to control access to the network (e.g., "captive portals" used + * to require agreement to Terms of Service before granting full Internet access via a Wi-Fi hotspot). + */ + NETWORK_AUTHENTICATION_REQUIRED = 511, +} diff --git a/server/utils/helpers.ts b/server/utils/helpers.ts index acd4d6eb..a509a4ae 100644 --- a/server/utils/helpers.ts +++ b/server/utils/helpers.ts @@ -1,4 +1,5 @@ import axios from "axios"; +import converter from "bech32-converting"; import { CardanoNetwork } from "."; import { DeliveredReward, @@ -122,6 +123,9 @@ export async function getPools() { let pools: GetPools | undefined = longTermCache.get("pools"); if (pools == null) { pools = await getFromVM("get_pools"); + Object.values(pools).forEach((pool) => { + pool.id = convertPoolIdToBech32(pool.id); + }); longTermCache.set("pools", pools); } return pools; @@ -373,3 +377,7 @@ export function parseVmDeliveredRewards( return Object.values(rewardMap); } + +export function convertPoolIdToBech32(poolIdInHex: string) { + return converter("pool").toBech32(poolIdInHex); +}