diff --git a/api/package-lock.json b/api/package-lock.json index f7645d8..d980e01 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -10,8 +10,8 @@ "license": "UNLICENSED", "dependencies": { "@apollo/server": "^4.10.4", - "@aptos-labs/ts-sdk": "^1.18.1", - "@aws-sdk/client-s3": "^3.592.0", + "@aptos-labs/ts-sdk": "^1.19.0", + "@aws-sdk/client-s3": "^3.596.0", "@clickhouse/client": "^1.1.0", "@nestjs/apollo": "^12.1.0", "@nestjs/bullmq": "^10.1.1", @@ -30,12 +30,12 @@ "axios": "^1.7.2", "bluebird": "^3.7.2", "bn.js": "^5.2.1", - "bullmq": "^5.7.15", + "bullmq": "^5.8.1", "csv-stringify": "^6.5.0", "d3-array": "^3.2.4", "decimal.js": "^10.4.3", "firebase-admin": "^12.1.1", - "graphql": "^16.8.1", + "graphql": "^16.8.2", "graphql-ws": "^5.16.0", "lodash": "^4.17.21", "maxmind": "^4.3.20", @@ -53,13 +53,13 @@ "@types/jest": "^29.5.12", "@types/node": "^20.14.2", "@types/supertest": "^6.0.2", - "@typescript-eslint/eslint-plugin": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "jest": "^29.7.0", - "prettier": "^3.3.1", + "prettier": "^3.3.2", "prisma": "^5.15.0", "source-map-support": "^0.5.21", "supertest": "^7.0.0", @@ -546,9 +546,9 @@ } }, "node_modules/@aptos-labs/ts-sdk": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/@aptos-labs/ts-sdk/-/ts-sdk-1.18.1.tgz", - "integrity": "sha512-+tsm+UAT8BEMJsT30RpIT8rv6yDwFcs7W/YvyHPG2wnOvTjnGQe1CT8sB/qqUt4OiVhyPdddPQDB4+4oJBVyAQ==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@aptos-labs/ts-sdk/-/ts-sdk-1.19.0.tgz", + "integrity": "sha512-ReTQNh1heap8VpK9Js4FVUVflRs/zSol+jtMDFwHk6IY7eNkdtVck9rqp17/vghBGkQw7b0YZERFOz0UdcE5zA==", "dependencies": { "@aptos-labs/aptos-cli": "^0.1.2", "@aptos-labs/aptos-client": "^0.1.0", @@ -715,17 +715,17 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@aws-sdk/client-s3": { - "version": "3.592.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.592.0.tgz", - "integrity": "sha512-abn1XYk9HW2nXIvyD6ldwrNcF5/7a2p06OSWEr7zVTo954kArg8N0yTsy83ezznEHZfaZpdZn/DLDl2GxrE1Xw==", + "version": "3.596.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.596.0.tgz", + "integrity": "sha512-W5C85cEUTYbmCpvvhLye+KirtLcBMX4t0l4Zj3EsGc5tTwkp7lxZDmJEoDfRy0+FE2H/O6OZQJdWMXCwt/Inqw==", "dependencies": { "@aws-crypto/sha1-browser": "3.0.0", "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.592.0", - "@aws-sdk/client-sts": "3.592.0", + "@aws-sdk/client-sso-oidc": "3.596.0", + "@aws-sdk/client-sts": "3.596.0", "@aws-sdk/core": "3.592.0", - "@aws-sdk/credential-provider-node": "3.592.0", + "@aws-sdk/credential-provider-node": "3.596.0", "@aws-sdk/middleware-bucket-endpoint": "3.587.0", "@aws-sdk/middleware-expect-continue": "3.577.0", "@aws-sdk/middleware-flexible-checksums": "3.587.0", @@ -831,15 +831,15 @@ } }, "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.592.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.592.0.tgz", - "integrity": "sha512-11Zvm8nm0s/UF3XCjzFRpQU+8FFVW5rcr3BHfnH6xAe5JEoN6bJN/n+wOfnElnjek+90hh+Qc7s141AMrCjiiw==", + "version": "3.596.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.596.0.tgz", + "integrity": "sha512-KnTWtKzO0N+rMdIrVwbewFp4FAvVWBV/ekCAh5w7EN+uAvBHxMoFElE2RwlcRF/gH1/F715OspPMvOxPom6bMA==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.592.0", + "@aws-sdk/client-sts": "3.596.0", "@aws-sdk/core": "3.592.0", - "@aws-sdk/credential-provider-node": "3.592.0", + "@aws-sdk/credential-provider-node": "3.596.0", "@aws-sdk/middleware-host-header": "3.577.0", "@aws-sdk/middleware-logger": "3.577.0", "@aws-sdk/middleware-recursion-detection": "3.577.0", @@ -881,15 +881,15 @@ } }, "node_modules/@aws-sdk/client-sts": { - "version": "3.592.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.592.0.tgz", - "integrity": "sha512-KUrOdszZfcrlpKr4dpdkGibZ/qq3Lnfu1rjv1U+V1QJQ9OuMo9J3sDWpWV9tigNqY0aGllarWH5cJbz9868W/w==", + "version": "3.596.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.596.0.tgz", + "integrity": "sha512-37+WQDjgmqS/YXj3vPzIVIrbXaFcZ1WXk715AMGIPBZn9Y2/wr2bmSTpX7bsMyn0G8+LxmoIxFcG7n1Gu0nvLg==", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.592.0", + "@aws-sdk/client-sso-oidc": "3.596.0", "@aws-sdk/core": "3.592.0", - "@aws-sdk/credential-provider-node": "3.592.0", + "@aws-sdk/credential-provider-node": "3.596.0", "@aws-sdk/middleware-host-header": "3.577.0", "@aws-sdk/middleware-logger": "3.577.0", "@aws-sdk/middleware-recursion-detection": "3.577.0", @@ -962,9 +962,9 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.587.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.587.0.tgz", - "integrity": "sha512-Su1SRWVRCuR1e32oxX3C1V4c5hpPN20WYcRfdcr2wXwHqSvys5DrnmuCC+JoEnS/zt3adUJhPliTqpfKgSdMrA==", + "version": "3.596.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.596.0.tgz", + "integrity": "sha512-nnmvEsz1KJgRmfSZJPWuzbxPRXu8Y+/78Ifa1jY3fQKSKdEJfXMDsjPljJvMDBl4dZ8pf5Hwx+S/ONnMEDwYEA==", "dependencies": { "@aws-sdk/types": "3.577.0", "@smithy/fetch-http-handler": "^3.0.1", @@ -981,12 +981,12 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.592.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.592.0.tgz", - "integrity": "sha512-3kG6ngCIOPbLJZZ3RV+NsU7HVK6vX1+1DrPJKj9fVlPYn7IXsk8NAaUT5885yC7+jKizjv0cWLrLKvAJV5gfUA==", + "version": "3.596.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.596.0.tgz", + "integrity": "sha512-c7PLtd7GbnOVAc5sk3sVlHxLvEsM8RF96rsBGlRo4AVpil/lXLKyNv9VarS4w/ZZZoRbJRyZ+m92PjNcLvpTDQ==", "dependencies": { "@aws-sdk/credential-provider-env": "3.587.0", - "@aws-sdk/credential-provider-http": "3.587.0", + "@aws-sdk/credential-provider-http": "3.596.0", "@aws-sdk/credential-provider-process": "3.587.0", "@aws-sdk/credential-provider-sso": "3.592.0", "@aws-sdk/credential-provider-web-identity": "3.587.0", @@ -1001,17 +1001,17 @@ "node": ">=16.0.0" }, "peerDependencies": { - "@aws-sdk/client-sts": "^3.592.0" + "@aws-sdk/client-sts": "^3.596.0" } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.592.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.592.0.tgz", - "integrity": "sha512-BguihBGTrEjVBQ07hm+ZsO29eNJaxwBwUZMftgGAm2XcMIEClNPfm5hydxu2BmA4ouIJQJ6nG8pNYghEumM+Aw==", + "version": "3.596.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.596.0.tgz", + "integrity": "sha512-F4MLyXpQyie1AnJS9n7TIRL0aF7YH8tKMIJXDsM5OXpSZi2en+yR6SzsxvHf5dwS2Ga8LUdEJyiyS2NoebaJGA==", "dependencies": { "@aws-sdk/credential-provider-env": "3.587.0", - "@aws-sdk/credential-provider-http": "3.587.0", - "@aws-sdk/credential-provider-ini": "3.592.0", + "@aws-sdk/credential-provider-http": "3.596.0", + "@aws-sdk/credential-provider-ini": "3.596.0", "@aws-sdk/credential-provider-process": "3.587.0", "@aws-sdk/credential-provider-sso": "3.592.0", "@aws-sdk/credential-provider-web-identity": "3.587.0", @@ -3899,11 +3899,11 @@ } }, "node_modules/@smithy/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.0.1.tgz", + "integrity": "sha512-Jb7jg4E+C+uvrUQi+h9kbILY6ts6fglKZzseMCHlH9ayq+1f5QdpYf8MV/xppuiN6DAMJAmwGz53GwP3213dmA==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -3928,14 +3928,14 @@ } }, "node_modules/@smithy/config-resolver": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.1.tgz", - "integrity": "sha512-hbkYJc20SBDz2qqLzttjI/EqXemtmWk0ooRznLsiXp3066KQRTvuKHa7U4jCZCJq6Dozqvy0R1/vNESC9inPJg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.2.tgz", + "integrity": "sha512-wUyG6ezpp2sWAvfqmSYTROwFUmJqKV78GLf55WODrosBcT0BAMd9bOLO4HRhynWBgAobPml2cF9ZOdgCe00r+g==", "dependencies": { - "@smithy/node-config-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@smithy/node-config-provider": "^3.1.1", + "@smithy/types": "^3.1.0", "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", + "@smithy/util-middleware": "^3.0.1", "tslib": "^2.6.2" }, "engines": { @@ -3943,17 +3943,17 @@ } }, "node_modules/@smithy/core": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.0.tgz", - "integrity": "sha512-ygLZSSKgt9bR8HAxR9mK+U5obvAJBr6zlQuhN5soYWx/amjDoQN4dTkydTypgKe6rIbUjTILyLU+W5XFwXr4kg==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.0.1", - "@smithy/middleware-retry": "^3.0.3", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.2.1.tgz", + "integrity": "sha512-R8Pzrr2v2oGUoj4CTZtKPr87lVtBsz7IUBGhSwS1kc6Cj0yPwNdYbkzhFsxhoDE9+BPl09VN/6rFsW9GJzWnBA==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.0.2", + "@smithy/middleware-retry": "^3.0.4", + "@smithy/middleware-serde": "^3.0.1", + "@smithy/protocol-http": "^4.0.1", + "@smithy/smithy-client": "^3.1.2", + "@smithy/types": "^3.1.0", + "@smithy/util-middleware": "^3.0.1", "tslib": "^2.6.2" }, "engines": { @@ -3961,14 +3961,14 @@ } }, "node_modules/@smithy/credential-provider-imds": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.0.tgz", - "integrity": "sha512-q4A4d38v8pYYmseu/jTS3Z5I3zXlEOe5Obi+EJreVKgSVyWUHOd7/yaVCinC60QG4MRyCs98tcxBH1IMC0bu7Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.1.1.tgz", + "integrity": "sha512-htndP0LwHdE3R3Nam9ZyVWhwPYOmD4xCL79kqvNxy8u/bv0huuy574CSiRY4cvEICgimv8jlVfLeZ7zZqbnB2g==", "dependencies": { - "@smithy/node-config-provider": "^3.1.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", + "@smithy/node-config-provider": "^3.1.1", + "@smithy/property-provider": "^3.1.1", + "@smithy/types": "^3.1.0", + "@smithy/url-parser": "^3.0.1", "tslib": "^2.6.2" }, "engines": { @@ -4038,13 +4038,13 @@ } }, "node_modules/@smithy/fetch-http-handler": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.0.1.tgz", - "integrity": "sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.0.2.tgz", + "integrity": "sha512-0nW6tLK0b7EqSsfKvnOmZCgJqnodBAnvqcrlC5dotKfklLedPTRGsQamSVbVDWyuU/QGg+YbZDJUQ0CUufJXZQ==", "dependencies": { - "@smithy/protocol-http": "^4.0.0", - "@smithy/querystring-builder": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/protocol-http": "^4.0.1", + "@smithy/querystring-builder": "^3.0.1", + "@smithy/types": "^3.1.0", "@smithy/util-base64": "^3.0.0", "tslib": "^2.6.2" } @@ -4061,11 +4061,11 @@ } }, "node_modules/@smithy/hash-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.0.tgz", - "integrity": "sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.1.tgz", + "integrity": "sha512-w2ncjgk2EYO2+WhAsSQA8owzoOSY7IL1qVytlwpnL1pFGWTjIoIh5nROkEKXY51unB63bMGZqDiVoXaFbyKDlg==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-utf8": "^3.0.0", "tslib": "^2.6.2" @@ -4088,11 +4088,11 @@ } }, "node_modules/@smithy/invalid-dependency": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.0.tgz", - "integrity": "sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.1.tgz", + "integrity": "sha512-RSNF/32BKygXKKMyS7koyuAq1rcdW5p5c4EFa77QenBFze9As+JiRnV9OWBh2cB/ejGZalEZjvIrMLHwJl7aGA==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" } }, @@ -4118,12 +4118,12 @@ } }, "node_modules/@smithy/middleware-content-length": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.0.tgz", - "integrity": "sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.1.tgz", + "integrity": "sha512-6QdK/VbrCfXD5/QolE2W/ok6VqxD+SM28Ds8iSlEHXZwv4buLsvWyvoEEy0322K/g5uFgPzBmZjGqesTmPL+yQ==", "dependencies": { - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", + "@smithy/protocol-http": "^4.0.1", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4131,16 +4131,16 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.1.tgz", - "integrity": "sha512-lQ/UOdGD4KM5kLZiAl0q8Qy3dPbynvAXKAdXnYlrA1OpaUwr+neSsVokDZpY6ZVb5Yx8jnus29uv6XWpM9P4SQ==", - "dependencies": { - "@smithy/middleware-serde": "^3.0.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.2.tgz", + "integrity": "sha512-gWEaGYB3Bei17Oiy/F2IlUPpBazNXImytoOdJ1xbrUOaJKAOiUhx8/4FOnYLLJHdAwa9PlvJ2ULda2f/Dnwi9w==", + "dependencies": { + "@smithy/middleware-serde": "^3.0.1", + "@smithy/node-config-provider": "^3.1.1", + "@smithy/shared-ini-file-loader": "^3.1.1", + "@smithy/types": "^3.1.0", + "@smithy/url-parser": "^3.0.1", + "@smithy/util-middleware": "^3.0.1", "tslib": "^2.6.2" }, "engines": { @@ -4148,17 +4148,17 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.3.tgz", - "integrity": "sha512-Wve1qzJb83VEU/6q+/I0cQdAkDnuzELC6IvIBwDzUEiGpKqXgX1v10FUuZGbRS6Ov/P+HHthcAoHOJZQvZNAkA==", - "dependencies": { - "@smithy/node-config-provider": "^3.1.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/service-error-classification": "^3.0.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.4.tgz", + "integrity": "sha512-Tu+FggbLNF5G9L6Wi8o32Mg4bhlBInWlhhaFKyytGRnkfxGopxFVXJQn7sjZdFYJyTz6RZZa06tnlvavUgtoVg==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.1", + "@smithy/protocol-http": "^4.0.1", + "@smithy/service-error-classification": "^3.0.1", + "@smithy/smithy-client": "^3.1.2", + "@smithy/types": "^3.1.0", + "@smithy/util-middleware": "^3.0.1", + "@smithy/util-retry": "^3.0.1", "tslib": "^2.6.2", "uuid": "^9.0.1" }, @@ -4167,11 +4167,11 @@ } }, "node_modules/@smithy/middleware-serde": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.0.tgz", - "integrity": "sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.1.tgz", + "integrity": "sha512-ak6H/ZRN05r5+SR0/IUc5zOSyh2qp3HReg1KkrnaSLXmncy9lwOjNqybX4L4x55/e5mtVDn1uf/gQ6bw5neJPw==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4179,11 +4179,11 @@ } }, "node_modules/@smithy/middleware-stack": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.0.tgz", - "integrity": "sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.1.tgz", + "integrity": "sha512-fS5uT//y1SlBdkzIvgmWQ9FufwMXrHSSbuR25ygMy1CRDIZkcBMoF4oTMYNfR9kBlVBcVzlv7joFdNrFuQirPA==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4191,13 +4191,13 @@ } }, "node_modules/@smithy/node-config-provider": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.0.tgz", - "integrity": "sha512-ngfB8QItUfTFTfHMvKuc2g1W60V1urIgZHqD1JNFZC2tTWXahqf2XvKXqcBS7yZqR7GqkQQZy11y/lNOUWzq7Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.1.tgz", + "integrity": "sha512-z5G7+ysL4yUtMghUd2zrLkecu0mTfnYlt5dR76g/HsFqf7evFazwiZP1ag2EJenGxNBDwDM5g8nm11NPogiUVA==", "dependencies": { - "@smithy/property-provider": "^3.1.0", - "@smithy/shared-ini-file-loader": "^3.1.0", - "@smithy/types": "^3.0.0", + "@smithy/property-provider": "^3.1.1", + "@smithy/shared-ini-file-loader": "^3.1.1", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4205,14 +4205,14 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.0.0.tgz", - "integrity": "sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.0.1.tgz", + "integrity": "sha512-hlBI6MuREA4o1wBMEt+QNhUzoDtFFvwR6ecufimlx9D79jPybE/r8kNorphXOi91PgSO9S2fxRjcKCLk7Jw8zA==", "dependencies": { - "@smithy/abort-controller": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/querystring-builder": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/abort-controller": "^3.0.1", + "@smithy/protocol-http": "^4.0.1", + "@smithy/querystring-builder": "^3.0.1", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4220,11 +4220,11 @@ } }, "node_modules/@smithy/property-provider": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.0.tgz", - "integrity": "sha512-Tj3+oVhqdZgemjCiWjFlADfhvLF4C/uKDuKo7/tlEsRQ9+3emCreR2xndj970QSRSsiCEU8hZW3/8JQu+n5w4Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.1.tgz", + "integrity": "sha512-YknOMZcQkB5on+MU0DvbToCmT2YPtTETMXW0D3+/Iln7ezT+Zm1GMHhCW1dOH/X/+LkkQD9aXEoCX/B10s4Xdw==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4232,11 +4232,11 @@ } }, "node_modules/@smithy/protocol-http": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.0.tgz", - "integrity": "sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.1.tgz", + "integrity": "sha512-eBhm9zwcFPEazc654c0BEWtxYAzrw+OhoSf5pkwKzfftWKXRoqEhwOE2Pvn30v0iAdo7Mfsfb6pi1NnZlGCMpg==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4244,11 +4244,11 @@ } }, "node_modules/@smithy/querystring-builder": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.0.tgz", - "integrity": "sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.1.tgz", + "integrity": "sha512-vKitpnG/2KOMVlx3x1S3FkBH075EROG3wcrcDaNerQNh8yuqnSL23btCD2UyX4i4lpPzNW6VFdxbn2Z25b/g5Q==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" }, @@ -4257,11 +4257,11 @@ } }, "node_modules/@smithy/querystring-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.0.tgz", - "integrity": "sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.1.tgz", + "integrity": "sha512-Qt8DMC05lVS8NcQx94lfVbZSX+2Ym7032b/JR8AlboAa/D669kPzqb35dkjkvAG6+NWmUchef3ENtrD6F+5n8Q==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4269,22 +4269,22 @@ } }, "node_modules/@smithy/service-error-classification": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.0.tgz", - "integrity": "sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.1.tgz", + "integrity": "sha512-ubFUvIePjDCyIzZ+pLETqNC6KXJ/fc6g+/baqel7Zf6kJI/kZKgjwkCI7zbUhoUuOZ/4eA/87YasVu40b/B4bA==", "dependencies": { - "@smithy/types": "^3.0.0" + "@smithy/types": "^3.1.0" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.0.tgz", - "integrity": "sha512-dAM7wSX0NR3qTNyGVN/nwwpEDzfV9T/3AN2eABExWmda5VqZKSsjlINqomO5hjQWGv+IIkoXfs3u2vGSNz8+Rg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.1.tgz", + "integrity": "sha512-nD6tXIX2126/P9e3wqRY1bm9dTtPZwRDyjVOd18G28o+1UOG+kOVgUwujE795HslSuPlEgqzsH5sgNP1hDjj9g==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4309,15 +4309,15 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.1.tgz", - "integrity": "sha512-tj4Ku7MpzZR8cmVuPcSbrLFVxmptWktmJMwST/uIEq4sarabEdF8CbmQdYB7uJ/X51Qq2EYwnRsoS7hdR4B7rA==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.0.1", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-stream": "^3.0.1", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.2.tgz", + "integrity": "sha512-f3eQpczBOFUtdT/ptw2WpUKu1qH1K7xrssrSiHYtd9TuLXkvFqb88l9mz9FHeUVNSUxSnkW1anJnw6rLwUKzQQ==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.0.2", + "@smithy/middleware-stack": "^3.0.1", + "@smithy/protocol-http": "^4.0.1", + "@smithy/types": "^3.1.0", + "@smithy/util-stream": "^3.0.2", "tslib": "^2.6.2" }, "engines": { @@ -4325,9 +4325,9 @@ } }, "node_modules/@smithy/types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.0.0.tgz", - "integrity": "sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.1.0.tgz", + "integrity": "sha512-qi4SeCVOUPjhSSZrxxB/mB8DrmuSFUcJnD9KXjuP+7C3LV/KFV4kpuUSH3OHDZgQB9TEH/1sO/Fq/5HyaK9MPw==", "dependencies": { "tslib": "^2.6.2" }, @@ -4336,12 +4336,12 @@ } }, "node_modules/@smithy/url-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.0.tgz", - "integrity": "sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.1.tgz", + "integrity": "sha512-G140IlNFlzYWVCedC4E2d6NycM1dCUbe5CnsGW1hmGt4hYKiGOw0v7lVru9WAn5T2w09QEjl4fOESWjGmCvVmg==", "dependencies": { - "@smithy/querystring-parser": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/querystring-parser": "^3.0.1", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" } }, @@ -4401,13 +4401,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.3.tgz", - "integrity": "sha512-3DFON2bvXJAukJe+qFgPV/rorG7ZD3m4gjCXHD1V5z/tgKQp5MCTCLntrd686tX6tj8Uli3lefWXJudNg5WmCA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.4.tgz", + "integrity": "sha512-sXtin3Mue3A3xo4+XkozpgPptgmRwvNPOqTvb3ANGTCzzoQgAPBNjpE+aXCINaeSMXwHmv7E2oEn2vWdID+SAQ==", "dependencies": { - "@smithy/property-provider": "^3.1.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", + "@smithy/property-provider": "^3.1.1", + "@smithy/smithy-client": "^3.1.2", + "@smithy/types": "^3.1.0", "bowser": "^2.11.0", "tslib": "^2.6.2" }, @@ -4416,16 +4416,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.3.tgz", - "integrity": "sha512-D0b8GJXecT00baoSQ3Iieu3k3mZ7GY8w1zmg8pdogYrGvWJeLcIclqk2gbkG4K0DaBGWrO6v6r20iwIFfDYrmA==", - "dependencies": { - "@smithy/config-resolver": "^3.0.1", - "@smithy/credential-provider-imds": "^3.1.0", - "@smithy/node-config-provider": "^3.1.0", - "@smithy/property-provider": "^3.1.0", - "@smithy/smithy-client": "^3.1.1", - "@smithy/types": "^3.0.0", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.4.tgz", + "integrity": "sha512-CUF6TyxLh3CgBRVYgZNOPDfzHQjeQr0vyALR6/DkQkOm7rNfGEzW1BRFi88C73pndmfvoiIT7ochuT76OPz9Dw==", + "dependencies": { + "@smithy/config-resolver": "^3.0.2", + "@smithy/credential-provider-imds": "^3.1.1", + "@smithy/node-config-provider": "^3.1.1", + "@smithy/property-provider": "^3.1.1", + "@smithy/smithy-client": "^3.1.2", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4433,12 +4433,12 @@ } }, "node_modules/@smithy/util-endpoints": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.1.tgz", - "integrity": "sha512-ZRT0VCOnKlVohfoABMc8lWeQo/JEFuPWctfNRXgTHbyOVssMOLYFUNWukxxiHRGVAhV+n3c0kPW+zUqckjVPEA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.2.tgz", + "integrity": "sha512-4zFOcBFQvifd2LSD4a1dKvfIWWwh4sWNtS3oZ7mpob/qPPmJseqKB148iT+hWCDsG//TmI+8vjYPgZdvnkYlTg==", "dependencies": { - "@smithy/node-config-provider": "^3.1.0", - "@smithy/types": "^3.0.0", + "@smithy/node-config-provider": "^3.1.1", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4457,11 +4457,11 @@ } }, "node_modules/@smithy/util-middleware": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.0.tgz", - "integrity": "sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.1.tgz", + "integrity": "sha512-WRODCQtUsO7vIvfrdxS8RFPeLKcewYtaCglZsBsedIKSUGIIvMlZT5oh+pCe72I+1L+OjnZuqRNpN2LKhWA4KQ==", "dependencies": { - "@smithy/types": "^3.0.0", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4469,12 +4469,12 @@ } }, "node_modules/@smithy/util-retry": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.0.tgz", - "integrity": "sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.1.tgz", + "integrity": "sha512-5lRtYm+8fNFEUTdqZXg5M4ppVp40rMIJfR1TpbHAhKQgPIDpWT+iYMaqgnwEbtpi9U1smyUOPv5Sg+M1neOBgw==", "dependencies": { - "@smithy/service-error-classification": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/service-error-classification": "^3.0.1", + "@smithy/types": "^3.1.0", "tslib": "^2.6.2" }, "engines": { @@ -4482,13 +4482,13 @@ } }, "node_modules/@smithy/util-stream": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.1.tgz", - "integrity": "sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.2.tgz", + "integrity": "sha512-n5Obp5AnlI6qHo8sbupwrcpBe6vFp4qkl0SRNuExKPNrH3ABAMG2ZszRTIUIv2b4AsFrCO+qiy4uH1Q3z1dxTA==", "dependencies": { - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/types": "^3.0.0", + "@smithy/fetch-http-handler": "^3.0.2", + "@smithy/node-http-handler": "^3.0.1", + "@smithy/types": "^3.1.0", "@smithy/util-base64": "^3.0.0", "@smithy/util-buffer-from": "^3.0.0", "@smithy/util-hex-encoding": "^3.0.0", @@ -4952,16 +4952,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", - "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", + "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/type-utils": "7.12.0", - "@typescript-eslint/utils": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/type-utils": "7.13.0", + "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -4984,16 +4984,17 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", - "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", + "node_modules/@typescript-eslint/parser": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", + "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/utils": "7.12.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", + "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5011,16 +5012,14 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", - "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0" + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5028,22 +5027,18 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", - "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", + "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", - "debug": "^4.3.4" + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/utils": "7.13.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5061,27 +5056,10 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", - "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", - "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -5092,13 +5070,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", - "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5119,13 +5097,35 @@ } } }, + "node_modules/@typescript-eslint/utils": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", + "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", - "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/types": "7.13.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -5947,9 +5947,9 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/bullmq": { - "version": "5.7.15", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.7.15.tgz", - "integrity": "sha512-XR5sTA8BPUY67sS37sMKGCDvSLaVpMq7aaQG8FGSKOUnPoJMRf17n1TibVWP3+yK0xKLdK5Y7PY9D874Fpeqpg==", + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.8.1.tgz", + "integrity": "sha512-t6BTH3J6T7exR+1C1NtQYekCgzkzEnxzBKU8Qit2YVgoJyTsu/xlHk7z/6g088uv1qD6XtHtV5Aiur/sUewTQA==", "dependencies": { "cron-parser": "^4.6.0", "ioredis": "^5.4.1", @@ -8138,9 +8138,9 @@ "dev": true }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "version": "16.8.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.2.tgz", + "integrity": "sha512-cvVIBILwuoSyD54U4cF/UXDh5yAobhNV/tPygI4lZhgOIJQE/WLWC4waBRb4I6bDVYb3OVx3lfHbaQOEoUD5sg==", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -10712,9 +10712,9 @@ } }, "node_modules/prettier": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.1.tgz", - "integrity": "sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" diff --git a/api/package.json b/api/package.json index 6354675..f6034bb 100644 --- a/api/package.json +++ b/api/package.json @@ -25,8 +25,8 @@ }, "dependencies": { "@apollo/server": "^4.10.4", - "@aptos-labs/ts-sdk": "^1.18.1", - "@aws-sdk/client-s3": "^3.592.0", + "@aptos-labs/ts-sdk": "^1.19.0", + "@aws-sdk/client-s3": "^3.596.0", "@clickhouse/client": "^1.1.0", "@nestjs/apollo": "^12.1.0", "@nestjs/bullmq": "^10.1.1", @@ -45,12 +45,12 @@ "axios": "^1.7.2", "bluebird": "^3.7.2", "bn.js": "^5.2.1", - "bullmq": "^5.7.15", + "bullmq": "^5.8.1", "csv-stringify": "^6.5.0", "d3-array": "^3.2.4", "decimal.js": "^10.4.3", "firebase-admin": "^12.1.1", - "graphql": "^16.8.1", + "graphql": "^16.8.2", "graphql-ws": "^5.16.0", "lodash": "^4.17.21", "maxmind": "^4.3.20", @@ -68,13 +68,13 @@ "@types/jest": "^29.5.12", "@types/node": "^20.14.2", "@types/supertest": "^6.0.2", - "@typescript-eslint/eslint-plugin": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "jest": "^29.7.0", - "prettier": "^3.3.1", + "prettier": "^3.3.2", "prisma": "^5.15.0", "source-map-support": "^0.5.21", "supertest": "^7.0.0", diff --git a/api/src/ol/account.resolver.ts b/api/src/ol/account.resolver.ts index 9268bfe..3127d49 100644 --- a/api/src/ol/account.resolver.ts +++ b/api/src/ol/account.resolver.ts @@ -6,111 +6,48 @@ import { Resolver, Int, } from "@nestjs/graphql"; -import { ApiError } from "aptos"; import { Decimal } from "decimal.js"; import { OlService } from "./ol.service.js"; -import { GqlAccount } from "./models/account.model.js"; -import { GqlSlowWallet } from "./models/slow-wallet.model.js"; +import { Account } from "./models/account.model.js"; +import { SlowWallet } from "./models/slow-wallet.model.js"; import { OrderDirection } from "./models/Paginated.js"; import { PaginatedMovements } from "./models/PaginatedMovements.js"; import { MovementsService } from "./movements/movements.service.js"; -export interface CoinStoreResource { - coin: { - value: string; - }; - deposit_events: { - counter: string; - guid: { - id: { - addr: string; - creation_num: string; - }; - }; - }; - withdraw_events: { - counter: string; - guid: { - id: { - addr: string; - creation_num: string; - }; - }; - }; -} - -export interface SlowWalletResource { - transferred: string; - unlocked: string; -} - -@Resolver(GqlAccount) +@Resolver(Account) export class AccountResolver { public constructor( private readonly olService: OlService, private readonly movementsService: MovementsService, ) {} - @Query(() => GqlAccount, { nullable: true }) + @Query(() => Account, { nullable: true }) public async account( @Args({ name: "address", type: () => Buffer }) address: Buffer, - ): Promise { + ): Promise { const accountExists = await this.olService.accountExists(address); if (accountExists) { - return new GqlAccount(address); + return new Account(address); } return null; } @ResolveField(() => Decimal, { nullable: true }) - public async balance(@Parent() account: GqlAccount): Promise { - try { - const res = await this.olService.aptosClient.getAccountResource( - `0x${account.address.toString("hex")}`, - "0x1::coin::CoinStore<0x1::libra_coin::LibraCoin>", - ); - const balance = new Decimal( - (res.data as CoinStoreResource).coin.value, - ).div(1e6); - return balance; - } catch (error) { - if (error instanceof ApiError) { - if (error.errorCode === "resource_not_found") { - return null; - } - } - throw error; - } + public async balance(@Parent() account: Account): Promise { + return this.olService.getAccountBalance(account.address); } - @ResolveField(() => GqlSlowWallet, { nullable: true }) + @ResolveField(() => SlowWallet, { nullable: true }) public async slowWallet( - @Parent() account: GqlAccount, - ): Promise { - try { - const res = await this.olService.aptosClient.getAccountResource( - `0x${account.address.toString("hex")}`, - "0x1::slow_wallet::SlowWallet", - ); - const slowWallet = res.data as SlowWalletResource; - return new GqlSlowWallet({ - unlocked: new Decimal(slowWallet.unlocked).div(1e6), - transferred: new Decimal(slowWallet.transferred).div(1e6), - }); - } catch (error) { - if (error instanceof ApiError) { - if (error.errorCode === "resource_not_found") { - return null; - } - } - throw error; - } + @Parent() account: Account, + ): Promise { + return this.olService.getSlowWallet(account.address); } @ResolveField(() => PaginatedMovements) public async movements( - @Parent() account: GqlAccount, + @Parent() account: Account, @Args({ name: "first", diff --git a/api/src/ol/accounts/accounts.model.ts b/api/src/ol/accounts/accounts.model.ts new file mode 100644 index 0000000..b14e26f --- /dev/null +++ b/api/src/ol/accounts/accounts.model.ts @@ -0,0 +1,54 @@ +import { Field, ObjectType, Int, Float } from "@nestjs/graphql"; + +export interface CumulativeShareInput { + amount: number; + percentage: number; +} + +@ObjectType() +export class CumulativeShare { + @Field(() => Float) + public amount: number; + + @Field(() => Float) + public percentage: number; + + public constructor(input: CumulativeShareInput) { + this.amount = input.amount; + this.percentage = input.percentage; + } +} + +export interface TopAccountInput { + rank: number; + address: string; + publicName: string; + balance: number; + cumulativeShare: CumulativeShare; +} + +@ObjectType() +export class TopAccount { + @Field(() => Int) + public rank: number; + + @Field() + public address: string; + + @Field() + public publicName: string; + + @Field(() => Float) + public balance: number; + + @Field(() => CumulativeShare) + public cumulativeShare: CumulativeShare; + + public constructor(input: TopAccountInput) { + this.rank = input.rank; + this.address = input.address; + this.publicName = input.publicName; + this.balance = input.balance; + this.cumulativeShare = input.cumulativeShare; + } +} diff --git a/api/src/ol/accounts/accounts.processor.ts b/api/src/ol/accounts/accounts.processor.ts new file mode 100644 index 0000000..b217676 --- /dev/null +++ b/api/src/ol/accounts/accounts.processor.ts @@ -0,0 +1,49 @@ +import { InjectQueue, Processor, WorkerHost } from "@nestjs/bullmq"; +import { OnModuleInit } from "@nestjs/common"; +import { Job, Queue } from "bullmq"; + +import { AccountsService } from "./accounts.service.js"; +import { redisClient } from "../../redis/redis.service.js"; +import { TOP_BALANCE_ACCOUNTS_CACHE_KEY } from "../constants.js"; + +@Processor("accounts") +export class AccountsProcessor extends WorkerHost implements OnModuleInit { + public constructor( + @InjectQueue("accounts") + private readonly accountsQueue: Queue, + + private readonly accountsService: AccountsService, + ) { + super(); + } + + public async onModuleInit() { + await this.accountsQueue.add("updateAccountsCache", undefined, { + repeat: { + every: 60 * 60 * 1_000, // 1 hour + }, + }); + + // Execute the job immediately on startup + await this.updateAccountsCache(); + } + + public async process(job: Job) { + switch (job.name) { + case "updateAccountsCache": + await this.updateAccountsCache(); + break; + + default: + throw new Error(`invalid job name ${job.name}`); + } + } + + private async updateAccountsCache() { + const accounts = await this.accountsService.getTopBalanceAccounts(100); + await redisClient.set( + TOP_BALANCE_ACCOUNTS_CACHE_KEY, + JSON.stringify(accounts), + ); + } +} diff --git a/api/src/ol/accounts/accounts.resolver.ts b/api/src/ol/accounts/accounts.resolver.ts new file mode 100644 index 0000000..91dbbd9 --- /dev/null +++ b/api/src/ol/accounts/accounts.resolver.ts @@ -0,0 +1,61 @@ +import { Query, Resolver, Args } from "@nestjs/graphql"; +import { Inject } from "@nestjs/common"; +import { ServiceUnavailableException } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; + +import { CumulativeShare, TopAccount } from "./accounts.model.js"; +import { AccountsService } from "./accounts.service.js"; +import { redisClient } from "../../redis/redis.service.js"; +import { TOP_BALANCE_ACCOUNTS_CACHE_KEY } from "../constants.js"; + +@Resolver(() => TopAccount) +export class AccountsResolver { + private readonly cacheEnabled: boolean; + + public constructor( + @Inject(AccountsService) + private readonly accountsService: AccountsService, + config: ConfigService, + ) { + this.cacheEnabled = config.get("cacheEnabled")!; + } + + @Query(() => [TopAccount]) + async getTopAccounts( + @Args("limit", { type: () => Number, defaultValue: 100 }) limit: number, + ): Promise { + // Check if caching is enabled and the query is not present + if (this.cacheEnabled) { + const cachedAccounts = await redisClient.get( + TOP_BALANCE_ACCOUNTS_CACHE_KEY, + ); + if (cachedAccounts) { + const accounts = JSON.parse(cachedAccounts); + return accounts.slice(0, limit).map( + (account: any) => + new TopAccount({ + rank: account.rank, + address: account.address, + publicName: account.publicName, + balance: account.balance, + cumulativeShare: new CumulativeShare(account.cumulativeShare), + }), + ); + } + throw new ServiceUnavailableException("Cache not ready"); + } + + // If cache is not enabled, get data from the service + const accounts = await this.accountsService.getTopBalanceAccounts(limit); + return accounts.map( + (account) => + new TopAccount({ + rank: account.rank, + address: account.address, + publicName: account.publicName, + balance: account.balance, + cumulativeShare: new CumulativeShare(account.cumulativeShare), + }), + ); + } +} diff --git a/api/src/ol/accounts/accounts.service.ts b/api/src/ol/accounts/accounts.service.ts new file mode 100644 index 0000000..af67543 --- /dev/null +++ b/api/src/ol/accounts/accounts.service.ts @@ -0,0 +1,69 @@ +import { Injectable } from "@nestjs/common"; +import { ClickhouseService } from "../../clickhouse/clickhouse.service.js"; +import { OlService } from "../ol.service.js"; +import { communityWallets } from "../community-wallets/community-wallets.js"; +import { CumulativeShare, TopAccount } from "./accounts.model.js"; + +@Injectable() +export class AccountsService { + constructor( + private readonly clickhouseService: ClickhouseService, + private readonly olService: OlService, + ) {} + + public async getTopBalanceAccounts(limit: number): Promise { + try { + const supplyStats = await this.olService.getSupplyStats(); + const totalSupply = supplyStats.totalSupply; + + const query = ` + SELECT + ROW_NUMBER() OVER (ORDER BY balance DESC) AS rank, + address, + balance + FROM ( + SELECT + hex(address) AS address, + max(balance) / 1e6 AS balance + FROM coin_balance + WHERE coin_module = 'libra_coin' + GROUP BY address + ) + ORDER BY balance DESC + LIMIT ${limit} + `; + + const resultSet = await this.clickhouseService.client.query({ + query: query, + format: "JSONEachRow", + }); + + const rows: Array<{ + rank: number; + address: string; + balance: number; + publicName: string; + }> = await resultSet.json(); + + let cumulativeBalanceAmount = 0; + const accountsWithCumulative = rows.map((account) => { + const name = communityWallets.get(account.address)?.name; + account.publicName = name ?? ""; + cumulativeBalanceAmount += account.balance; + const cumulativeShare = new CumulativeShare({ + amount: cumulativeBalanceAmount, + percentage: (cumulativeBalanceAmount / totalSupply) * 100, + }); + return new TopAccount({ + ...account, + cumulativeShare, + }); + }); + + return accountsWithCumulative; + } catch (error) { + console.error("Error in getTopBalanceAccounts:", error); + throw error; + } + } +} diff --git a/api/src/ol/community-wallets/community-wallet.model.ts b/api/src/ol/community-wallets/community-wallet.model.ts index 62a9b2c..bfbc245 100644 --- a/api/src/ol/community-wallets/community-wallet.model.ts +++ b/api/src/ol/community-wallets/community-wallet.model.ts @@ -1,25 +1,23 @@ -import { Field, ObjectType } from '@nestjs/graphql'; +import { Field, ObjectType } from "@nestjs/graphql"; -interface GqlCommunityWalletInput { - name?: string; - description?: string; - address: Buffer; -} - -@ObjectType('CommunityWallet') +@ObjectType() export class GqlCommunityWallet { - public constructor(input: GqlCommunityWalletInput) { - this.name = input.name; - this.description = input.description; - this.address = input.address; - } + @Field() + rank: number; - @Field(() => String, { nullable: true }) - public name?: string; + @Field() + address: string; - @Field(() => String, { nullable: true }) - public description?: string; + @Field({ nullable: true }) + name?: string; - @Field(() => Buffer) - public address: Buffer; -} \ No newline at end of file + @Field({ nullable: true }) + description?: string; + + @Field({ nullable: true }) + balance?: number; + + constructor(partial: Partial) { + Object.assign(this, partial); + } +} diff --git a/api/src/ol/community-wallets/community-wallets.processor.ts b/api/src/ol/community-wallets/community-wallets.processor.ts new file mode 100644 index 0000000..daee592 --- /dev/null +++ b/api/src/ol/community-wallets/community-wallets.processor.ts @@ -0,0 +1,56 @@ +import _ from "lodash"; +import { InjectQueue, Processor, WorkerHost } from "@nestjs/bullmq"; +import { Inject, OnModuleInit } from "@nestjs/common"; +import { Job, Queue } from "bullmq"; +import { ICommunityWalletsService } from "./interfaces.js"; +import { redisClient } from "../../redis/redis.service.js"; +import { Types } from "../../types.js"; + +import { COMMUNITY_WALLETS_CACHE_KEY } from "../constants.js"; + +@Processor("community-wallets") +export class CommunityWalletsProcessor + extends WorkerHost + implements OnModuleInit +{ + public constructor( + @InjectQueue("community-wallets") + private readonly communityWalletsQueue: Queue, + + @Inject(Types.ICommunityWalletsService) + private readonly communityWalletsService: ICommunityWalletsService, + ) { + super(); + } + + public async onModuleInit() { + await this.communityWalletsQueue.add( + "updateCommunityWalletsCache", + undefined, + { + repeat: { + every: 60 * 60 * 1_000, // 1 hour + }, + }, + ); + + // Execute the job immediately on startup + await this.updateCommunityWalletsCache(); + } + + public async process(job: Job) { + switch (job.name) { + case "updateCommunityWalletsCache": + await this.updateCommunityWalletsCache(); + break; + + default: + throw new Error(`invalid job name ${job.name}`); + } + } + + private async updateCommunityWalletsCache() { + const wallets = await this.communityWalletsService.getCommunityWallets(); + await redisClient.set(COMMUNITY_WALLETS_CACHE_KEY, JSON.stringify(wallets)); + } +} diff --git a/api/src/ol/community-wallets/community-wallets.resolver.ts b/api/src/ol/community-wallets/community-wallets.resolver.ts index 91cd4d3..7ff45b0 100644 --- a/api/src/ol/community-wallets/community-wallets.resolver.ts +++ b/api/src/ol/community-wallets/community-wallets.resolver.ts @@ -1,20 +1,36 @@ import { Query, Resolver } from "@nestjs/graphql"; import _ from "lodash"; import { Inject } from "@nestjs/common"; - +import { redisClient } from "../../redis/redis.service.js"; import { GqlCommunityWallet } from "./community-wallet.model.js"; import { ICommunityWalletsService } from "./interfaces.js"; import { Types } from "../../types.js"; +import { ServiceUnavailableException } from "@nestjs/common"; +import { COMMUNITY_WALLETS_CACHE_KEY } from "../constants.js"; @Resolver() export class CommunityWalletsResolver { + private readonly cacheEnabled: boolean; + public constructor( @Inject(Types.ICommunityWalletsService) private readonly communityWalletsService: ICommunityWalletsService, - ) {} + ) { + this.cacheEnabled = process.env.CACHE_ENABLED === "true"; // Check if cache is enabled + } @Query(() => [GqlCommunityWallet]) - async communityWallets(): Promise { + async getCommunityWallets(): Promise { + // Check if cache is enabled + if (this.cacheEnabled) { + const cachedWallets = await redisClient.get(COMMUNITY_WALLETS_CACHE_KEY); + if (cachedWallets) { + return JSON.parse(cachedWallets); + } + throw new ServiceUnavailableException("Cache not ready"); + } + + // If cache is not enabled, fetch data from service return this.communityWalletsService.getCommunityWallets(); } } diff --git a/api/src/ol/community-wallets/community-wallets.service.ts b/api/src/ol/community-wallets/community-wallets.service.ts index b4e004b..5291c97 100644 --- a/api/src/ol/community-wallets/community-wallets.service.ts +++ b/api/src/ol/community-wallets/community-wallets.service.ts @@ -28,40 +28,32 @@ export class CommunityWalletsService implements ICommunityWalletsService { parseAddress(address).toString("hex").toUpperCase(), ); - const res = addresses.map((address) => { - const addrBuff = parseAddress(address); - const addr = addrBuff.toString("hex").toUpperCase(); - const info = communityWallets.get(addr); - - return new GqlCommunityWallet({ - address: addrBuff, - name: info?.name, - description: info?.description, - }); - }); - - const groups = _.groupBy(res, (wallet) => { - if (wallet.name && wallet.description) { - return "nameAndDescription"; - } - if (wallet.name) { - return "nameOnly"; - } - if (wallet.description) { - return "descriptionOnly"; - } - return "rest"; - }); + const res = await Promise.all( + addresses.map(async (address) => { + const addrBuff = parseAddress(address); + const addr = addrBuff.toString("hex").toUpperCase(); + const info = communityWallets.get(addr); + const balance = await this.olService.getAccountBalance(addrBuff); + + return { + address: addr, + name: info?.name, + description: info?.description, + balance: balance ? balance.toNumber() : 0, + }; + }), + ); - const { nameAndDescription, nameOnly, descriptionOnly, rest } = groups; - const sorter = (wallet: GqlCommunityWallet) => - wallet.address.toString("hex"); + // Sort by balance descending + const sortedRes = _.sortBy(res, [(wallet) => -wallet.balance]); - return [ - ..._.sortBy(nameAndDescription, sorter), - ..._.sortBy(nameOnly, sorter), - ..._.sortBy(descriptionOnly, sorter), - ..._.sortBy(rest, sorter), - ]; + // Add rank + return sortedRes.map( + (wallet, index) => + new GqlCommunityWallet({ + rank: index + 1, + ...wallet, + }), + ); } } diff --git a/api/src/ol/constants.ts b/api/src/ol/constants.ts index 65ad221..d4eb4a6 100644 --- a/api/src/ol/constants.ts +++ b/api/src/ol/constants.ts @@ -1 +1,4 @@ export const V0_TIMESTAMP = 1712696400; +export const TOP_BALANCE_ACCOUNTS_CACHE_KEY = "__0L_TOP_BALANCE_ACCOUNTS__"; +export const COMMUNITY_WALLETS_CACHE_KEY = "__0L_COMMUNITY_WALLETS__"; +export const VALIDATORS_CACHE_KEY = "__0L_VALIDATORS__"; diff --git a/api/src/ol/models/account.model.ts b/api/src/ol/models/account.model.ts index 0195bf7..b185102 100644 --- a/api/src/ol/models/account.model.ts +++ b/api/src/ol/models/account.model.ts @@ -1,7 +1,7 @@ import { Field, ObjectType } from '@nestjs/graphql'; -@ObjectType('Account') -export class GqlAccount { +@ObjectType() +export class Account { public constructor(address: Buffer) { this.address = address; } diff --git a/api/src/ol/models/slow-wallet.model.ts b/api/src/ol/models/slow-wallet.model.ts index d01a73e..3478c41 100644 --- a/api/src/ol/models/slow-wallet.model.ts +++ b/api/src/ol/models/slow-wallet.model.ts @@ -1,14 +1,14 @@ -import { Field, ObjectType } from '@nestjs/graphql'; -import { Decimal } from 'decimal.js'; +import { Field, ObjectType } from "@nestjs/graphql"; +import { Decimal } from "decimal.js"; -interface GqlSlowWalletInput { +interface SlowWalletInput { transferred: Decimal; unlocked: Decimal; } -@ObjectType('SlowWallet') -export class GqlSlowWallet { - public constructor(input: GqlSlowWalletInput) { +@ObjectType() +export class SlowWallet { + public constructor(input: SlowWalletInput) { this.transferred = input.transferred; this.unlocked = input.unlocked; } @@ -18,4 +18,4 @@ export class GqlSlowWallet { @Field(() => Decimal) public unlocked: Decimal; -} \ No newline at end of file +} diff --git a/api/src/ol/models/validator.model.ts b/api/src/ol/models/validator.model.ts index 07e128e..e9ccaea 100644 --- a/api/src/ol/models/validator.model.ts +++ b/api/src/ol/models/validator.model.ts @@ -1,6 +1,25 @@ import { Field, ObjectType } from "@nestjs/graphql"; import BN from "bn.js"; +@ObjectType("ValidatorCurrentBid") +export class GqlValidatorCurrentBid { + public constructor(input: GqlValidatorCurrentBidInput) { + this.currentBid = input.currentBid; + this.expirationEpoch = input.expirationEpoch; + } + + @Field(() => Number) + public currentBid: number; + + @Field(() => Number) + public expirationEpoch: number; +} + +interface GqlValidatorCurrentBidInput { + currentBid: number; + expirationEpoch: number; +} + interface GqlValidatorGradeInput { compliant: boolean; proposedBlocks: number; @@ -25,30 +44,36 @@ export class GqlValidatorGrade { public failedBlocks: number; } -interface GqlValidatorInput { - address: Buffer; - votingPower: BN; - grade: GqlValidatorGradeInput; +interface ValidatorInput { inSet: boolean; index: BN; - networkAddresses?: string; - fullnodeAddresses?: string; - city?: string; - country?: string; + address: string; + balance?: number; + unlocked?: number; + votingPower: BN; + grade?: GqlValidatorGrade | null; + vouches: GqlVouch[]; + currentBid: GqlValidatorCurrentBid; + city?: string | null; + country?: string | null; + auditQualification?: [string] | null; } -@ObjectType("Validator") -export class GqlValidator { - public constructor(input: GqlValidatorInput) { +@ObjectType() +export class Validator { + public constructor(input: ValidatorInput) { + this.inSet = input.inSet; + this.index = input.index; this.address = input.address; + this.balance = input.balance; + this.unlocked = input.unlocked; this.votingPower = input.votingPower; this.grade = input.grade; - this.inSet = input.inSet; - this.index = input.index; - this.networkAddresses = input.networkAddresses; - this.fullnodeAddresses = input.fullnodeAddresses; + this.vouches = input.vouches; + this.currentBid = input.currentBid; this.city = input.city; this.country = input.country; + this.auditQualification = input.auditQualification; } @Field(() => Boolean) @@ -57,38 +82,40 @@ export class GqlValidator { @Field(() => BN) public index: BN; - @Field(() => Buffer) - public address: Buffer; - - @Field(() => String, { nullable: true }) - public networkAddresses?: string; + @Field(() => String) + public address: string; @Field(() => String, { nullable: true }) - public fullnodeAddresses?: string; + public city?: string | null; @Field(() => String, { nullable: true }) - public city?: string; - - @Field(() => String, { nullable: true }) - public country?: string; + public country?: string | null; @Field(() => BN) public votingPower: BN; - @Field(() => BN) - public failedProposals: BN; + @Field(() => GqlValidatorGrade, { nullable: true }) + public grade?: GqlValidatorGrade | null; - @Field(() => BN) - public successfulProposals: BN; + @Field(() => [GqlVouch], { nullable: true }) + public vouches?: GqlVouch[]; - @Field(() => GqlValidatorGrade, { nullable: true }) - public grade?: GqlValidatorGrade; + @Field(() => GqlValidatorCurrentBid, { nullable: true }) + public currentBid?: GqlValidatorCurrentBid; + + @Field(() => Number, { nullable: true }) + public balance?: number; + + @Field(() => Number, { nullable: true }) + public unlocked?: number; + + @Field(() => [String], { nullable: true }) + public auditQualification?: [string] | null; } interface GqlVouchInput { - epoch: BN; - address: Buffer; - inSet: boolean; + epoch: number; + address: string; } @ObjectType("Vouch") @@ -96,34 +123,11 @@ export class GqlVouch { public constructor(input: GqlVouchInput) { this.epoch = input.epoch; this.address = input.address; - this.inSet = input.inSet; - } - - @Field(() => BN) - public epoch: BN; - - @Field(() => Buffer) - public address: Buffer; - - @Field(() => Boolean) - public inSet: boolean; -} - -interface GqlValidatorCurrentBidInput { - currentBid: number; - expirationEpoch: number; -} - -@ObjectType("ValidatorCurrentBid") -export class GqlValidatorCurrentBid { - public constructor(input: GqlValidatorCurrentBidInput) { - this.currentBid = input.currentBid; - this.expirationEpoch = input.expirationEpoch; } @Field(() => Number) - public currentBid: number; + public epoch: number; - @Field(() => Number) - public expirationEpoch: number; + @Field(() => String) + public address: string; } diff --git a/api/src/ol/ol.module.ts b/api/src/ol/ol.module.ts index c9155ce..85417f2 100644 --- a/api/src/ol/ol.module.ts +++ b/api/src/ol/ol.module.ts @@ -23,9 +23,13 @@ import { OlClickhouseIngestorProcessor } from "./ol-clickhouse-ingestor.processo import { OlController } from "./ol.controller.js"; import { ValidatorsResolver } from "./validators/validators.resolver.js"; -import { ValidatorResolver } from "./validators/validator.resvoler.js"; +import { ValidatorsProcessor } from "./validators/validators.processor.js"; +import { ValidatorsService } from "./validators/validators.service.js"; import { AccountResolver } from "./account.resolver.js"; +import { AccountsResolver } from "./accounts/accounts.resolver.js"; +import { AccountsService } from "./accounts/accounts.service.js"; +import { AccountsProcessor } from "./accounts/accounts.processor.js"; import { TransformerService } from "./transformer.service.js"; @@ -36,6 +40,7 @@ import { MovementsService } from "./movements/movements.service.js"; import { CommunityWalletsResolver } from "./community-wallets/community-wallets.resolver.js"; import { CommunityWalletsService } from "./community-wallets/community-wallets.service.js"; +import { CommunityWalletsProcessor } from "./community-wallets/community-wallets.processor.js"; import { TransactionsResolver } from "./transactions/TransactionsResolver.js"; import { TransactionResolver } from "./transactions/TransactionResolver.js"; @@ -54,6 +59,7 @@ const workersMap = new Map>([ ["version-processor", OlVersionProcessor], ["clickhouse-ingestor-processor", OlClickhouseIngestorProcessor], ["expired-transactions-processor", ExpiredTransactionsProcessor], + ["accounts-processor", AccountsProcessor], ]); const workers: Type[] = []; @@ -98,6 +104,21 @@ for (const role of roles) { name: "expired-transactions", connection: redisClient, }), + + BullModule.registerQueue({ + name: "accounts", + connection: redisClient, + }), + + BullModule.registerQueue({ + name: "community-wallets", + connection: redisClient, + }), + + BullModule.registerQueue({ + name: "validators", + connection: redisClient, + }), ], providers: [ UserTransactionsResolver, @@ -105,11 +126,17 @@ for (const role of roles) { MovementsResolver, AccountResolver, + AccountsResolver, + AccountsService, + AccountsProcessor, - ValidatorResolver, ValidatorsResolver, + ValidatorsService, + ValidatorsProcessor, CommunityWalletsResolver, + CommunityWalletsService, + CommunityWalletsProcessor, { provide: Types.ICommunityWalletsService, useClass: CommunityWalletsService, diff --git a/api/src/ol/ol.service.ts b/api/src/ol/ol.service.ts index b8fcba7..6ad4ca4 100644 --- a/api/src/ol/ol.service.ts +++ b/api/src/ol/ol.service.ts @@ -1,13 +1,16 @@ -import { AptosClient } from "aptos"; +import { ApiError, AptosClient } from "aptos"; import { Injectable } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import BN from "bn.js"; +import { Decimal } from "decimal.js"; import { OlConfig } from "../config/config.interface.js"; import { + CoinStoreResource, ConsensusReward, RawDonorVoiceRegistry, RawValidatorSet, + SlowWalletResource, ValidatorConfig, ValidatorGrade, ValidatorSet, @@ -15,6 +18,7 @@ import { import { NetworkAddresses } from "./network-addresses.js"; import { parseAddress } from "../utils.js"; import { SupplyStats } from "./types.js"; +import { SlowWallet } from "./models/slow-wallet.model.js"; @Injectable() export class OlService { @@ -214,4 +218,45 @@ export class OlService { const data = res.data as RawDonorVoiceRegistry; return data.list.map((it) => it.substring(2)); } + + public async getAccountBalance(address: Uint8Array): Promise { + try { + const res = await this.aptosClient.getAccountResource( + `0x${Buffer.from(address).toString("hex")}`, + "0x1::coin::CoinStore<0x1::libra_coin::LibraCoin>", + ); + const balance = new Decimal( + (res.data as CoinStoreResource).coin.value, + ).div(1e6); + return balance; + } catch (error) { + if (error instanceof ApiError) { + if (error.errorCode === "resource_not_found") { + return null; + } + } + throw error; + } + } + + public async getSlowWallet(address: Uint8Array): Promise { + try { + const res = await this.aptosClient.getAccountResource( + `0x${Buffer.from(address).toString("hex")}`, + "0x1::slow_wallet::SlowWallet", + ); + const slowWallet = res.data as SlowWalletResource; + return new SlowWallet({ + unlocked: new Decimal(slowWallet.unlocked).div(1e6), + transferred: new Decimal(slowWallet.transferred).div(1e6), + }); + } catch (error) { + if (error instanceof ApiError) { + if (error.errorCode === "resource_not_found") { + return null; + } + } + throw error; + } + } } diff --git a/api/src/ol/types.ts b/api/src/ol/types.ts index b2c9084..3f09708 100644 --- a/api/src/ol/types.ts +++ b/api/src/ol/types.ts @@ -71,3 +71,32 @@ export interface RawDonorVoiceRegistry { liquidation_queue: unknown[]; list: string[]; } + +export interface CoinStoreResource { + coin: { + value: string; + }; + deposit_events: { + counter: string; + guid: { + id: { + addr: string; + creation_num: string; + }; + }; + }; + withdraw_events: { + counter: string; + guid: { + id: { + addr: string; + creation_num: string; + }; + }; + }; +} + +export interface SlowWalletResource { + transferred: string; + unlocked: string; +} diff --git a/api/src/ol/user-transactions.resolver.ts b/api/src/ol/user-transactions.resolver.ts index 12b171e..5c85ced 100644 --- a/api/src/ol/user-transactions.resolver.ts +++ b/api/src/ol/user-transactions.resolver.ts @@ -10,6 +10,25 @@ import { ClickhouseService } from "../clickhouse/clickhouse.service.js"; export class UserTransactionsResolver { public constructor(private readonly clickhouseService: ClickhouseService) {} + @Query(() => Int) + async userTransactionsCount(): Promise { + const result = await this.clickhouseService.client + .query({ + query: 'SELECT COUNT(*) as "total" FROM user_transaction', + format: "JSONEachRow", + }) + .then((res) => res.json<{ total: string }[]>()); + + // Verifica se o resultado está definido e se contém o campo 'total' + if (result && result.length > 0) { + const total = Number(result[0]["total"]); + return total; + } + + // Caso não haja resultado, retorna 0 ou lança um erro apropriado + throw new Error("Failed to fetch user transactions count"); + } + @Query(() => GqlUserTransactionCollection) async userTransactions( @Args({ name: "limit", type: () => Int }) diff --git a/api/src/ol/validators/validator.resvoler.ts b/api/src/ol/validators/validator.resvoler.ts deleted file mode 100644 index 3a8548c..0000000 --- a/api/src/ol/validators/validator.resvoler.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Parent, ResolveField, Resolver } from "@nestjs/graphql"; -import BN from "bn.js"; - -import { OlService } from "../ol.service.js"; -import { - GqlValidator, - GqlValidatorCurrentBid, - GqlValidatorGrade, - GqlVouch, -} from "../models/validator.model.js"; -import { GqlAccount } from "../models/account.model.js"; -import { parseAddress } from "../../utils.js"; - -@Resolver(GqlValidator) -export class ValidatorResolver { - public constructor(private readonly olService: OlService) {} - - @ResolveField(() => GqlAccount) - public account(@Parent() validator: GqlValidator): GqlAccount { - return new GqlAccount(validator.address); - } - - @ResolveField(() => [GqlVouch]) - public async vouches(@Parent() validator: GqlValidator): Promise { - const vouchesRes = await this.olService.aptosClient.getAccountResource( - `0x${validator.address.toString("hex")}`, - "0x1::vouch::MyVouches", - ); - const vouches = vouchesRes.data as { - epoch_vouched: string[]; - my_buddies: string[]; - }; - return vouches.my_buddies.map((address, index) => { - return new GqlVouch({ - address: parseAddress(address), - epoch: new BN(vouches.epoch_vouched[index]), - inSet: true, - }); - }); - } - - @ResolveField(() => GqlValidatorGrade) - public async grade( - @Parent() validator: GqlValidator, - ): Promise { - const grade = await this.olService.getValidatorGrade(validator.address); - return new GqlValidatorGrade({ - compliant: grade.compliant, - proposedBlocks: grade.proposedBlocks, - failedBlocks: grade.failedBlocks, - }); - } - - @ResolveField(() => GqlValidatorCurrentBid) - public async currentBid( - @Parent() validator: GqlValidator, - ): Promise { - const currentBid = await this.olService.getCurrentBid(validator.address); - return new GqlValidatorCurrentBid({ - currentBid: currentBid.currentBid, - expirationEpoch: currentBid.expirationEpoch, - }); - } -} diff --git a/api/src/ol/validators/validators.processor.ts b/api/src/ol/validators/validators.processor.ts new file mode 100644 index 0000000..2cb9738 --- /dev/null +++ b/api/src/ol/validators/validators.processor.ts @@ -0,0 +1,45 @@ +// src/validators/validators.processor.ts +import { Processor, WorkerHost } from "@nestjs/bullmq"; +import { InjectQueue } from "@nestjs/bullmq"; +import { Queue, Job } from "bullmq"; +import { redisClient } from "../../redis/redis.service.js"; +import { ValidatorsService } from "./validators.service.js"; +import { VALIDATORS_CACHE_KEY } from "../constants.js"; + +@Processor("validators") +export class ValidatorsProcessor extends WorkerHost { + public constructor( + @InjectQueue("validators") + private readonly validatorsQueue: Queue, + private readonly validatorsService: ValidatorsService, + ) { + super(); + } + + public async onModuleInit() { + await this.validatorsQueue.add("updateValidatorsCache", undefined, { + repeat: { + every: 30 * 1000, // 30 seconds + }, + }); + + // Execute the job immediately on startup + await this.updateValidatorsCache(); + } + + public async process(job: Job) { + switch (job.name) { + case "updateValidatorsCache": + await this.updateValidatorsCache(); + break; + + default: + throw new Error(`Invalid job name ${job.name}`); + } + } + + private async updateValidatorsCache() { + const validators = await this.validatorsService.getValidators(); + await redisClient.set(VALIDATORS_CACHE_KEY, JSON.stringify(validators)); + } +} diff --git a/api/src/ol/validators/validators.resolver.ts b/api/src/ol/validators/validators.resolver.ts index 757c759..cce5f21 100644 --- a/api/src/ol/validators/validators.resolver.ts +++ b/api/src/ol/validators/validators.resolver.ts @@ -1,84 +1,28 @@ +// src/validators/validators.resolver.ts import { Query, Resolver } from "@nestjs/graphql"; -import _ from "lodash"; -import Bluebird from "bluebird"; -import BN from "bn.js"; +import { ServiceUnavailableException } from "@nestjs/common"; +import { ValidatorsService } from "./validators.service.js"; +import { Validator } from "../models/validator.model.js"; +import { redisClient } from "../../redis/redis.service.js"; +import { VALIDATORS_CACHE_KEY } from "../constants.js"; -import { OlService } from "../ol.service.js"; -import { PrismaService } from "../../prisma/prisma.service.js"; -import { GqlValidator } from "../models/validator.model.js"; - -@Resolver() +@Resolver(() => Validator) export class ValidatorsResolver { - public constructor( - private readonly olService: OlService, - private readonly prisma: PrismaService, - ) {} - - @Query(() => [GqlValidator]) - async validators(): Promise { - const validatorSet = await this.olService.getValidatorSet(); - const nodes = await this.prisma.node.findMany({ - select: { - ip: true, - city: true, - country: true, - }, - }); - - const currentValidators = await Bluebird.map( - validatorSet.activeValidators, - async (validator) => { - const grade = await this.olService.getValidatorGrade(validator.addr); - const valIp = - validator.config.networkAddresses && - validator.config.networkAddresses.split("/")[2]; - const node = nodes.find((node) => node["ip"] == valIp); - const city = node && node["city"] ? node["city"] : undefined; - const country = node && node["country"] ? node["country"] : undefined; - - return new GqlValidator({ - address: validator.addr, - votingPower: validator.votingPower, - grade, - inSet: true, - index: validator.config.validatorIndex, - networkAddresses: validator.config.networkAddresses, - fullnodeAddresses: validator.config.fullnodeAddresses, - city, - country, - }); - }, - ); - - let eligible = await this.olService.getEligibleValidators(); - eligible = eligible.filter( - (address) => !currentValidators.find((it) => it.address.equals(address)), - ); - - const eligibleValidators = await Bluebird.map(eligible, async (address) => { - const grade = await this.olService.getValidatorGrade(address); - - // Ready to fetch city and country for inactive validators - /* - const config = await this.olService.getValidatorConfig(address); - const valIp = - config.network_addresses && config.network_addresses.split("/")[2]; - const node = nodes.find((node) => node["ip"] == valIp); - const city = node && node["city"] ? node["city"] : ""; - const country = node && node["country"] ? node["country"] : ""; - */ - - return new GqlValidator({ - address, - votingPower: new BN(0), - grade: grade, - inSet: false, - index: new BN(-1), - // city: city, - // country: country - }); - }); - - return [...currentValidators, ...eligibleValidators]; + private cacheEnabled = true; // Set to true if cache is enabled + + public constructor(private readonly validatorsService: ValidatorsService) {} + + @Query(() => [Validator]) + async getValidators(): Promise { + if (this.cacheEnabled) { + const cachedValidators = await redisClient.get(VALIDATORS_CACHE_KEY); + if (cachedValidators) { + return JSON.parse(cachedValidators); + } + // throw new ServiceUnavailableException("Cache not ready"); + } + + const validators = await this.validatorsService.getValidators(); + return validators; } } diff --git a/api/src/ol/validators/validators.service.ts b/api/src/ol/validators/validators.service.ts new file mode 100644 index 0000000..6d7511d --- /dev/null +++ b/api/src/ol/validators/validators.service.ts @@ -0,0 +1,156 @@ +import { Injectable } from "@nestjs/common"; +import Bluebird from "bluebird"; +import BN from "bn.js"; + +import { OlService } from "../ol.service.js"; +import { PrismaService } from "../../prisma/prisma.service.js"; +import { Validator, GqlVouch } from "../models/validator.model.js"; +import { parseAddress } from "../../utils.js"; + +@Injectable() +export class ValidatorsService { + public constructor( + private readonly olService: OlService, + private readonly prisma: PrismaService, + ) {} + + public async getValidators(): Promise { + const validatorSet = await this.olService.getValidatorSet(); + const nodes = await this.prisma.node.findMany({ + select: { + ip: true, + city: true, + country: true, + }, + }); + + const currentValidators = await Bluebird.map( + validatorSet.activeValidators, + async (validator) => { + const valIp = + validator.config.networkAddresses && + validator.config.networkAddresses.split("/")[2]; + const node = nodes.find((node) => node["ip"] == valIp); + const city = node && node["city"] ? node["city"] : null; + const country = node && node["country"] ? node["country"] : null; + const grade = await this.olService.getValidatorGrade(validator.addr); + + return { + address: validator.addr, + votingPower: validator.votingPower, + inSet: true, + index: validator.config.validatorIndex, + networkAddresses: validator.config.networkAddresses, + fullnodeAddresses: validator.config.fullnodeAddresses, + city, + country, + grade, + auditQualification: null, + }; + }, + ); + + const eligible = await this.olService.getEligibleValidators(); + const eligibleCurrent = eligible.filter( + (address) => + !currentValidators.find((it) => !it.address.compare(address)), + ); + + const eligibleValidators = await Promise.all( + eligibleCurrent.map(async (address) => { + return { + address, + votingPower: new BN(0), + inSet: false, + index: new BN(-1), + auditQualification: await this.getAuditQualification(address), + grade: null, + city: null, + country: null, + }; + }), + ); + + let allValidators = [...currentValidators, ...eligibleValidators]; + return await Promise.all( + allValidators.map(async (validator) => { + const balance = await this.olService.getAccountBalance( + validator.address, + ); + const slowWallet = await this.olService.getSlowWallet( + validator.address, + ); + const unlocked = Number(slowWallet?.unlocked); + + const vouches = await this.getVouches(validator.address); + const currentBid = await this.olService.getCurrentBid( + validator.address, + ); + return new Validator({ + inSet: validator.inSet, + index: validator.index, + address: validator.address.toString("hex").toLocaleUpperCase(), + votingPower: validator.votingPower, + balance: Number(balance), + unlocked: unlocked, + grade: validator.grade, + vouches: vouches, + currentBid: currentBid, + city: validator.city, + country: validator.country, + auditQualification: validator.auditQualification, + }); + }), + ); + } + public async getAuditQualification(address: Buffer): Promise<[string]> { + const auditQualification = await this.olService.aptosClient.view({ + function: "0x1::proof_of_fee::audit_qualification", + type_arguments: [], + arguments: [`0x${address.toString("hex")}`], + }); + return auditQualification[0] as [string]; + } + + public async getVouches(address: Buffer): Promise { + const allVouchesRes = await this.olService.aptosClient.getAccountResource( + `0x${address.toString("hex")}`, + "0x1::vouch::MyVouches", + ); + + const validVouchesRes = await this.olService.aptosClient.view({ + function: "0x1::vouch::true_friends", + type_arguments: [], + arguments: [`0x${address.toString("hex")}`], + }); + + const allVouches = allVouchesRes.data as { + epoch_vouched: string[]; + my_buddies: string[]; + }; + + const all = allVouches.my_buddies.map((address, index) => { + return { + address: parseAddress(address).toString("hex").toLocaleUpperCase(), + epoch: Number(allVouches.epoch_vouched[index]), + }; + }); + + let validVouches = validVouchesRes[0] as string[]; + validVouches = validVouches.map((address) => + parseAddress(address).toString("hex").toLocaleUpperCase(), + ); + const activeVouches = all.filter((vouch) => + validVouches.includes(vouch.address), + ); + + return activeVouches.map((vouch) => { + return new GqlVouch({ + address: parseAddress(vouch.address) + .toString("hex") + .toLocaleUpperCase(), + epoch: Number(vouch.epoch), + }); + }); + } +} diff --git a/api/src/schema.gql b/api/src/schema.gql index 2727cbb..03f5568 100644 --- a/api/src/schema.gql +++ b/api/src/schema.gql @@ -12,6 +12,11 @@ type Module { functions: [String!]! } +type SlowWallet { + transferred: Decimal! + unlocked: Decimal! +} + type GqlUserTransactionDeprecated { hash: String! version: Float! @@ -35,6 +40,11 @@ type UserTransactionCollection { items: [GqlUserTransactionDeprecated!]! } +type ValidatorCurrentBid { + currentBid: Float! + expirationEpoch: Float! +} + type ValidatorGrade { compliant: Boolean! proposedBlocks: Float! @@ -44,29 +54,21 @@ type ValidatorGrade { type Validator { inSet: Boolean! index: BigInt! - address: Bytes! - networkAddresses: String - fullnodeAddresses: String + address: String! city: String country: String votingPower: BigInt! - failedProposals: BigInt! - successfulProposals: BigInt! grade: ValidatorGrade - account: Account! - vouches: [Vouch!]! - currentBid: ValidatorCurrentBid! + vouches: [Vouch!] + currentBid: ValidatorCurrentBid + balance: Float + unlocked: Float + auditQualification: [String!] } type Vouch { - epoch: BigInt! - address: Bytes! - inSet: Boolean! -} - -type ValidatorCurrentBid { - currentBid: Float! - expirationEpoch: Float! + epoch: Float! + address: String! } type Account { @@ -81,11 +83,6 @@ enum OrderDirection { DESC } -type SlowWallet { - transferred: Decimal! - unlocked: Decimal! -} - type PageInfo { prevCursor: String hasNextPage: Boolean! @@ -112,10 +109,25 @@ type PaginatedMovements { pageInfo: PageInfo! } -type CommunityWallet { +type CumulativeShare { + amount: Float! + percentage: Float! +} + +type TopAccount { + rank: Int! + address: String! + publicName: String! + balance: Float! + cumulativeShare: CumulativeShare! +} + +type GqlCommunityWallet { + rank: Float! + address: String! name: String description: String - address: Bytes! + balance: Float } type Transaction { @@ -175,11 +187,13 @@ scalar BigInt scalar Decimal type Query { + userTransactionsCount: Int! userTransactions(limit: Int!, offset: Int!, order: String!): UserTransactionCollection! modules: [Module!]! account(address: Bytes!): Account - validators: [Validator!]! - communityWallets: [CommunityWallet!]! + getTopAccounts(limit: Float! = 100): [TopAccount!]! + getValidators: [Validator!]! + getCommunityWallets: [GqlCommunityWallet!]! walletTransactions(address: Bytes!): [Transaction!]! transaction(hash: Bytes!): Transaction! nodes: [Node!] diff --git a/api/src/stats/constants.ts b/api/src/stats/constants.ts index 5a22c77..950d607 100644 --- a/api/src/stats/constants.ts +++ b/api/src/stats/constants.ts @@ -1 +1,2 @@ export const STATS_CACHE_KEY = "__0L_CACHED_STATS__"; +export const ACCOUNTS_STATS_CACHE_KEY = "__0L_CACHED_ACCOUNTS_STATS__"; diff --git a/api/src/stats/stats.controller.ts b/api/src/stats/stats.controller.ts index 35636e5..5ff0d7d 100644 --- a/api/src/stats/stats.controller.ts +++ b/api/src/stats/stats.controller.ts @@ -1,12 +1,17 @@ -import { Controller, Get, Query, Res, ServiceUnavailableException } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { Response } from 'express'; +import { + Controller, + Get, + Res, + ServiceUnavailableException, +} from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { Response } from "express"; -import { StatsService } from './stats.service.js'; -import { redisClient } from '../redis/redis.service.js'; -import { STATS_CACHE_KEY } from './constants.js'; +import { StatsService } from "./stats.service.js"; +import { redisClient } from "../redis/redis.service.js"; +import { STATS_CACHE_KEY, ACCOUNTS_STATS_CACHE_KEY } from "./constants.js"; -@Controller('stats') +@Controller("stats") export class StatsController { private readonly cacheEnabled: boolean; @@ -14,7 +19,25 @@ export class StatsController { private readonly statsService: StatsService, config: ConfigService, ) { - this.cacheEnabled = config.get('cacheEnabled')!; + this.cacheEnabled = config.get("cacheEnabled")!; + } + + @Get() + public async getStats(@Res() res: Response) { + res.set("Content-Type", "application/json"); + + // Check if caching is enabled and the query is not present + if (this.cacheEnabled) { + const cachedStats = await redisClient.get(STATS_CACHE_KEY); + if (cachedStats) { + res.send(cachedStats); + return; + } + throw new ServiceUnavailableException("Cache not ready"); + } + + const stats = await this.statsService.getStats(); + res.send(stats); } @Get("/total-supply") @@ -29,21 +52,21 @@ export class StatsController { res.send({ circulatingSupply }); } - @Get() - public async getStats(@Res() res: Response) { - res.set('Content-Type', 'application/json'); + @Get("/accounts-stats") + public async getAccountsStats(@Res() res: Response) { + res.set("Content-Type", "application/json"); // Check if caching is enabled and the query is not present if (this.cacheEnabled) { - const cachedStats = await redisClient.get(STATS_CACHE_KEY); + const cachedStats = await redisClient.get(ACCOUNTS_STATS_CACHE_KEY); if (cachedStats) { res.send(cachedStats); return; } - throw new ServiceUnavailableException('Cache not ready'); + throw new ServiceUnavailableException("Cache not ready"); } - const stats = await this.statsService.getStats(); - res.send(stats); + const accountsStats = await this.statsService.getAccountsStats(); + res.send(accountsStats); } } diff --git a/api/src/stats/stats.processor.ts b/api/src/stats/stats.processor.ts index 5dfc359..fc01e56 100644 --- a/api/src/stats/stats.processor.ts +++ b/api/src/stats/stats.processor.ts @@ -5,7 +5,7 @@ import { Job, Queue } from "bullmq"; import { StatsService } from "./stats.service.js"; import { redisClient } from "../redis/redis.service.js"; -import { STATS_CACHE_KEY } from "./constants.js"; +import { STATS_CACHE_KEY, ACCOUNTS_STATS_CACHE_KEY } from "./constants.js"; @Processor("stats") export class StatsProcessor extends WorkerHost implements OnModuleInit { @@ -24,6 +24,11 @@ export class StatsProcessor extends WorkerHost implements OnModuleInit { every: 60 * 60 * 2 * 1_000, // 2 hours }, }); + + // Delay the execution of the job by 5 seconds on startup + setTimeout(async () => { + await this.updateStats(); + }, 5000); } public async process(job: Job) { @@ -40,5 +45,11 @@ export class StatsProcessor extends WorkerHost implements OnModuleInit { private async updateStats() { const stats = await this.statsService.getStats(); await redisClient.set(STATS_CACHE_KEY, JSON.stringify(stats)); + + const accountsStats = await this.statsService.getAccountsStats(); + await redisClient.set( + ACCOUNTS_STATS_CACHE_KEY, + JSON.stringify(accountsStats), + ); } } diff --git a/api/src/stats/stats.service.ts b/api/src/stats/stats.service.ts index 848ca4b..06d12e5 100644 --- a/api/src/stats/stats.service.ts +++ b/api/src/stats/stats.service.ts @@ -838,6 +838,103 @@ export class StatsService { } } + public async getAccountsStats(): Promise<{ + totalAccounts: number; + activeAddressesCount: { + lastDay: number; + last30Days: number; + last90Days: number; + }; + }> { + const totalAccounts = await this.getTotalUniqueAccounts(); + const activeAddressesCount = await this.getActiveAddressesCount(); + return { totalAccounts, activeAddressesCount }; + } + + public async getActiveAddressesCount(): Promise<{ + lastDay: number; + last30Days: number; + last90Days: number; + }> { + try { + const query = ` + SELECT + version, + address + FROM coin_balance + WHERE coin_module = 'libra_coin' + ORDER BY version ASC + `; + + const resultSet = await this.clickhouseService.client.query({ + query: query, + format: "JSONEachRow", + }); + + const rows = await resultSet.json<{ + version: string; + address: string; + }>(); + + if (!rows.length) { + return { + lastDay: 0, + last30Days: 0, + last90Days: 0, + }; + } + + const versions = rows.map((row) => parseInt(row.version, 10)); + const chunkSize = 1000; + const versionChunks = this.chunkArray(versions, chunkSize); + const allTimestampMappings = ( + await Promise.all( + versionChunks.map((chunk) => this.mapVersionsToTimestamps(chunk)), + ) + ).flat(); + + const versionToTimestampMap = new Map( + allTimestampMappings.map(({ version, timestamp }) => [ + version, + timestamp, + ]), + ); + + const now = Math.floor(Date.now() / 1000); + const oneDayAgo = now - 86400; + const thirtyDaysAgo = now - 30 * 86400; + const ninetyDaysAgo = now - 90 * 86400; + + const seenAddressesLastDay = new Set(); + const seenAddressesLast30Days = new Set(); + const seenAddressesLast90Days = new Set(); + + rows.forEach((row) => { + const version = parseInt(row.version, 10); + const timestamp = versionToTimestampMap.get(version) ?? 0; + + if (timestamp >= oneDayAgo) { + seenAddressesLastDay.add(row.address); + } + if (timestamp >= thirtyDaysAgo) { + seenAddressesLast30Days.add(row.address); + } + if (timestamp >= ninetyDaysAgo) { + seenAddressesLast90Days.add(row.address); + } + }); + + return { + lastDay: seenAddressesLastDay.size, + last30Days: seenAddressesLast30Days.size, + last90Days: seenAddressesLast90Days.size, + }; + } catch (error) { + console.error("Error in getActiveAddressesCount:", error); + throw error; + } + } + public async getTotalUniqueAccounts(): Promise { try { const query = ` @@ -856,8 +953,7 @@ export class StatsService { if (rows.length === 0) { return 0; } - - const uniqueAccountsCount = Number(rows[0]); + const uniqueAccountsCount = Number(rows[0]["unique_accounts"]); return uniqueAccountsCount; } catch (error) { @@ -991,12 +1087,12 @@ export class StatsService { // Query the slow_wallet table and join with the addressBalanceMap data const slowWalletQuery = ` - SELECT - hex(SW.address) AS address, - max(SW.unlocked) / 1e6 AS unlocked_balance - FROM slow_wallet SW - GROUP BY SW.address - `; + SELECT + hex(SW.address) AS address, + max(SW.unlocked) / 1e6 AS unlocked_balance + FROM slow_wallet SW + GROUP BY SW.address + `; const slowWalletResultSet = await this.clickhouseService.client.query({ query: slowWalletQuery, @@ -1299,9 +1395,7 @@ export class StatsService { const communityWallets = await this.communityWalletsService.getCommunityWallets(); const communityAddresses = new Set( - communityWallets.map((wallet) => - wallet.address.toString("hex").toUpperCase(), - ), + communityWallets.map((wallet) => wallet.address), ); // Query to get the latest balances and versions from coin_balance diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index dcd4713..0000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "explorer", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} diff --git a/web-app/package-lock.json b/web-app/package-lock.json index b44b45c..f1ac3bc 100644 --- a/web-app/package-lock.json +++ b/web-app/package-lock.json @@ -8,13 +8,12 @@ "name": "explorer", "version": "0.0.1", "dependencies": { - "@apollo/client": "^3.10.4", - "@aptos-labs/ts-sdk": "^1.18.1", - "@aptos-labs/wallet-adapter-react": "^3.0.6", + "@apollo/client": "^3.10.5", + "@aptos-labs/ts-sdk": "^1.19.0", + "@aptos-labs/wallet-adapter-react": "^3.2.0", "@headlessui/react": "^2.0.4", "@heroicons/react": "^2.1.3", "@noble/hashes": "^1.4.0", - "@types/styled-components": "^5.1.34", "aptos": "^1.21.0", "axios": "^1.7.2", "bn.js": "^5.2.1", @@ -26,16 +25,15 @@ "decimal.js": "^10.4.3", "echarts": "^5.5.0", "echarts-for-react": "^3.0.2", - "graphql": "^16.8.1", + "graphql": "^16.8.2", "graphql-ws": "^5.16.0", "lodash": "^4.17.21", - "posthog-js": "^1.138.1", + "posthog-js": "^1.139.2", "prismjs": "^1.29.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-qr-code": "^2.0.14", "react-router-dom": "^6.23.1", - "react-toastify": "^10.0.5", "styled-components": "^6.1.11" }, "devDependencies": { @@ -46,17 +44,18 @@ "@types/prismjs": "^1.26.4", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0", + "@types/styled-components": "^5.1.34", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", "@vitejs/plugin-react-swc": "^3.7.0", "autoprefixer": "^10.4.19", - "eslint": "^8.57.0", + "eslint": "^8.56.0", "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.7", "postcss": "^8.4.38", "tailwindcss": "^3.4.4", "typescript": "^5.4.5", - "vite": "^5.2.13" + "vite": "^5.3.1" }, "engines": { "node": ">=20.11.0" @@ -84,9 +83,9 @@ } }, "node_modules/@apollo/client": { - "version": "3.10.4", - "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.10.4.tgz", - "integrity": "sha512-51gk0xOwN6Ls1EbTG5svFva1kdm2APHYTzmFhaAdvUQoJFDxfc0UwQgDxGptzH84vkPlo1qunY1FuboyF9LI3Q==", + "version": "3.10.5", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.10.5.tgz", + "integrity": "sha512-bZh5wLAT8b4KdEmqnqiQeDUttnR+NJ+gDYSN8T+U0uFGN++5LO5PTwySih6kIU5ErGGGw4NHI94YdSET3uLuBA==", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "@wry/caches": "^1.0.0", @@ -156,9 +155,9 @@ } }, "node_modules/@aptos-labs/ts-sdk": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/@aptos-labs/ts-sdk/-/ts-sdk-1.18.1.tgz", - "integrity": "sha512-+tsm+UAT8BEMJsT30RpIT8rv6yDwFcs7W/YvyHPG2wnOvTjnGQe1CT8sB/qqUt4OiVhyPdddPQDB4+4oJBVyAQ==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@aptos-labs/ts-sdk/-/ts-sdk-1.19.0.tgz", + "integrity": "sha512-ReTQNh1heap8VpK9Js4FVUVflRs/zSol+jtMDFwHk6IY7eNkdtVck9rqp17/vghBGkQw7b0YZERFOz0UdcE5zA==", "dependencies": { "@aptos-labs/aptos-cli": "^0.1.2", "@aptos-labs/aptos-client": "^0.1.0", @@ -182,27 +181,138 @@ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" }, "node_modules/@aptos-labs/wallet-adapter-core": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@aptos-labs/wallet-adapter-core/-/wallet-adapter-core-4.2.1.tgz", - "integrity": "sha512-GbPvMsaPyxvfeUJB8SoglcctL3Sg3yYcOC/X/NY4NRLdh22oK5JIDnPKDt+fEg4UgrNUmBBXP06eEkH7qyC1ZQ==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@aptos-labs/wallet-adapter-core/-/wallet-adapter-core-4.6.0.tgz", + "integrity": "sha512-UreWrGmTZijXx4XzYJDfGUGW3174CwaiC8Q5QlSY6rne9hZ07TeUu7gR3ctX2CoRuUHug+KSqt7T+Cy6Ga8ONQ==", "dependencies": { + "@aptos-connect/wallet-adapter-plugin": "^1.0.0", "@aptos-labs/wallet-standard": "^0.1.0", "@atomrigslab/aptos-wallet-adapter": "^0.1.12", "buffer": "^6.0.3", "eventemitter3": "^4.0.7", "tweetnacl": "^1.0.3" }, + "peerDependencies": { + "@aptos-labs/ts-sdk": "^1.18.1", + "aptos": "^1.21.0" + } + }, + "node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-connect/wallet-adapter-plugin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@aptos-connect/wallet-adapter-plugin/-/wallet-adapter-plugin-1.0.0.tgz", + "integrity": "sha512-9Mii1izvp8xp5eDSUZIotSWfoUDGvngkDJ4qPspUzLEFLy44iftTpNbcM1P/J+G7lBU6XvtIgCLLmppt3Hiqhg==", + "dependencies": { + "@aptos-connect/wallet-api": "^0.1.1", + "@aptos-labs/wallet-adapter-core": "^3.5.0", + "@identity-connect/crypto": "^0.2.3", + "@identity-connect/dapp-sdk": "^0.9.0" + }, + "peerDependencies": { + "@aptos-labs/ts-sdk": "1.18.1", + "@aptos-labs/wallet-standard": "^0.1.0", + "aptos": "^1.21.0" + } + }, + "node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-connect/wallet-adapter-plugin/node_modules/@aptos-connect/wallet-api": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@aptos-connect/wallet-api/-/wallet-api-0.1.1.tgz", + "integrity": "sha512-If666Wz7m+ZK/RzDhm5Wy3oDkhnv14wKHW0jEVtXtHwTzYEgaOdC92RhZHqzPAqysipKSatBJJNVk58PzJLAUQ==", + "dependencies": { + "@identity-connect/api": "^0.6.1" + }, + "peerDependencies": { + "@aptos-labs/ts-sdk": "1.18.1", + "@aptos-labs/wallet-standard": "^0.1.0", + "aptos": "^1.20.0" + } + }, + "node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-connect/wallet-adapter-plugin/node_modules/@identity-connect/crypto": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@identity-connect/crypto/-/crypto-0.2.3.tgz", + "integrity": "sha512-HJmsNz4YeJg/BFgu94x9cbNUrlKTmk50yVuoF2Ry1+SwC2c6Vhy2CeaZa1SeevjHsk9hjSrqk42q+EZMZAuaJA==", + "dependencies": { + "@aptos-connect/wallet-api": "^0.1.0", + "@noble/hashes": "^1.3.1", + "ed2curve": "^0.3.0", + "tweetnacl": "^1.0.3" + }, + "peerDependencies": { + "@aptos-labs/ts-sdk": "1.18.1" + } + }, + "node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-connect/wallet-adapter-plugin/node_modules/@identity-connect/dapp-sdk": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@identity-connect/dapp-sdk/-/dapp-sdk-0.9.0.tgz", + "integrity": "sha512-EYB9PMyEagt3PCjJTwX3V34vyXi/asj7dAD22rvUJarlx+TIRPYODxTWoUR2jc7F9Q83cZbU7Iv/EL77diqYYQ==", + "dependencies": { + "@aptos-connect/wallet-api": "^0.1.1", + "@aptos-connect/web-transport": "^0.0.7", + "@identity-connect/api": "^0.6.1", + "@identity-connect/crypto": "^0.2.3", + "@identity-connect/wallet-api": "^0.1.1", + "axios": "^1.6.0", + "uuid": "^9.0.1" + }, + "peerDependencies": { + "@aptos-labs/ts-sdk": "1.18.1", + "@aptos-labs/wallet-standard": "^0.1.0" + } + }, + "node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-connect/wallet-adapter-plugin/node_modules/@identity-connect/dapp-sdk/node_modules/@aptos-connect/web-transport": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@aptos-connect/web-transport/-/web-transport-0.0.7.tgz", + "integrity": "sha512-4dYv/696bEZc75041ewKsWxg48/dTEDqP0TpIfK3KndGepKWDM9q3Lj8iZo+8Z9nhzxwulEqiAO7c0nvzXxVFA==", + "dependencies": { + "@aptos-connect/wallet-api": "^0.1.1", + "uuid": "^9.0.1" + }, + "peerDependencies": { + "@aptos-labs/ts-sdk": "1.18.1", + "@aptos-labs/wallet-standard": "^0.1.0", + "aptos": "^1.20.0" + } + }, + "node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-connect/wallet-adapter-plugin/node_modules/@identity-connect/dapp-sdk/node_modules/@identity-connect/wallet-api": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@identity-connect/wallet-api/-/wallet-api-0.1.1.tgz", + "integrity": "sha512-PGcJQrSnk6PLr/w5D1FKRP/Ip0DH8nvDuWe/5ZfStrGwKhG0L8yDZPbAmDfSOH2mUvVtafmayRYv/FOnqGtLLw==", + "peerDependencies": { + "@aptos-labs/ts-sdk": "1.18.1", + "aptos": "^1.20.0" + } + }, + "node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-labs/wallet-adapter-core": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@aptos-labs/wallet-adapter-core/-/wallet-adapter-core-3.16.0.tgz", + "integrity": "sha512-4pBNoDLzuIOxdNwJEO770bkxROuEIQis0H0lFOVVCL33jK8/MWLlQo8hFgc71ovN1vWfdERDEgPLbAtVChploQ==", + "dependencies": { + "@aptos-labs/wallet-standard": "^0.0.11", + "@atomrigslab/aptos-wallet-adapter": "^0.1.10", + "buffer": "^6.0.3", + "eventemitter3": "^4.0.7", + "tweetnacl": "^1.0.3" + }, "peerDependencies": { "@aptos-labs/ts-sdk": "^1.13.2", "aptos": "^1.21.0" } }, + "node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-labs/wallet-adapter-core/node_modules/@aptos-labs/wallet-standard": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@aptos-labs/wallet-standard/-/wallet-standard-0.0.11.tgz", + "integrity": "sha512-8dygyPBby7TaMJjUSyeVP4R1WC9D/FPpX9gVMMLaqTKCXrSbkzhGDxcuwbMZ3ziEwRmx3zz+d6BIJbDhd0hm5g==", + "dependencies": { + "@aptos-labs/ts-sdk": "^1.9.1", + "@wallet-standard/core": "1.0.3" + } + }, "node_modules/@aptos-labs/wallet-adapter-react": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@aptos-labs/wallet-adapter-react/-/wallet-adapter-react-3.0.6.tgz", - "integrity": "sha512-Pw6zLTuNGyLNc0Ha0bVBHNHfQXpVqTjHbEAfj9cYdA+vrLyKo1p0fU3xQl3alsNgrHhwvBpCgGNDT7vmaL8tuA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@aptos-labs/wallet-adapter-react/-/wallet-adapter-react-3.2.0.tgz", + "integrity": "sha512-31hENJYFszFL0xxS7Zr+F+XGNMUqIyqa4gASe+hKmceOAtP6VgwDNYmGE1Tsrmz2eDG7+U1ywg7yfke3O2f+KQ==", "dependencies": { - "@aptos-labs/wallet-adapter-core": "4.2.1" + "@aptos-labs/wallet-adapter-core": "4.6.0", + "@radix-ui/react-slot": "^1.0.2" }, "peerDependencies": { "react": "^18" @@ -276,6 +386,17 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==" }, + "node_modules/@babel/runtime": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@emotion/is-prop-valid": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", @@ -294,74 +415,10 @@ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -374,294 +431,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -877,6 +646,11 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, + "node_modules/@identity-connect/api": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@identity-connect/api/-/api-0.6.1.tgz", + "integrity": "sha512-CBeff9UZtQWhJBPEuwFCOcies2rFkn14BTLyyYLpI+Tlxv1XTCWSZKRx/Ewvexb4U/5OWWMY1s263gZBaOAiPQ==" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1054,6 +828,41 @@ "node": ">=14" } }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz", + "integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", + "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@react-aria/focus": { "version": "3.17.1", "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.17.1.tgz", @@ -1139,32 +948,6 @@ "node": ">=14.0.0" } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", - "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", - "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", @@ -1178,136 +961,6 @@ "darwin" ] }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", - "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", - "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", - "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", - "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", - "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", - "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", - "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", - "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", - "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", - "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@scure/base": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", @@ -1353,14 +1006,14 @@ } }, "node_modules/@swc/core": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.25.tgz", - "integrity": "sha512-qdGEIdLVoTjEQ7w72UyyQ0wLFY4XbHfZiidmPHKJQsvSXzdpHXxPdlTCea/mY4AhMqo/M+pvkJSXJAxZnFl7qw==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.29.tgz", + "integrity": "sha512-nvTtHJI43DUSOAf3h9XsqYg8YXKc0/N4il9y4j0xAkO0ekgDNo+3+jbw6MInawjKJF9uulyr+f5bAutTsOKVlw==", "dev": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.3", - "@swc/types": "^0.1.7" + "@swc/types": "^0.1.8" }, "engines": { "node": ">=10" @@ -1370,16 +1023,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.5.25", - "@swc/core-darwin-x64": "1.5.25", - "@swc/core-linux-arm-gnueabihf": "1.5.25", - "@swc/core-linux-arm64-gnu": "1.5.25", - "@swc/core-linux-arm64-musl": "1.5.25", - "@swc/core-linux-x64-gnu": "1.5.25", - "@swc/core-linux-x64-musl": "1.5.25", - "@swc/core-win32-arm64-msvc": "1.5.25", - "@swc/core-win32-ia32-msvc": "1.5.25", - "@swc/core-win32-x64-msvc": "1.5.25" + "@swc/core-darwin-arm64": "1.5.29", + "@swc/core-darwin-x64": "1.5.29", + "@swc/core-linux-arm-gnueabihf": "1.5.29", + "@swc/core-linux-arm64-gnu": "1.5.29", + "@swc/core-linux-arm64-musl": "1.5.29", + "@swc/core-linux-x64-gnu": "1.5.29", + "@swc/core-linux-x64-musl": "1.5.29", + "@swc/core-win32-arm64-msvc": "1.5.29", + "@swc/core-win32-ia32-msvc": "1.5.29", + "@swc/core-win32-x64-msvc": "1.5.29" }, "peerDependencies": { "@swc/helpers": "*" @@ -1391,9 +1044,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.25.tgz", - "integrity": "sha512-YbD0SBgVJS2DM0vwJTU5m7+wOyCjHPBDMf3nCBJQzFZzOLzK11eRW7SzU2jhJHr9HI9sKcNFfN4lIC2Sj+4inA==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.5.29.tgz", + "integrity": "sha512-6F/sSxpHaq3nzg2ADv9FHLi4Fu2A8w8vP8Ich8gIl16D2htStlwnaPmCLjRswO+cFkzgVqy/l01gzNGWd4DFqA==", "cpu": [ "arm64" ], @@ -1407,9 +1060,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.25.tgz", - "integrity": "sha512-OhP4TROT6gQuozn+ah0Y4UidSdgDmxwtQq3lgCUIAxJYErJAQ82/Y0kve2UaNmkSGjOHU+/b4siHPrYTkXOk0Q==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.5.29.tgz", + "integrity": "sha512-rF/rXkvUOTdTIfoYbmszbSUGsCyvqACqy1VeP3nXONS+LxFl4bRmRcUTRrblL7IE5RTMCKUuPbqbQSE2hK7bqg==", "cpu": [ "x64" ], @@ -1423,9 +1076,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.25.tgz", - "integrity": "sha512-tNmUfrAHxN2gvYPyYNnHx2CYlPO7DGAUuK/bZrqawu++djcg+atAV3eI3XYJgmHId7/sYAlDQ9wjkrOLofFjVg==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.5.29.tgz", + "integrity": "sha512-2OAPL8iWBsmmwkjGXqvuUhbmmoLxS1xNXiMq87EsnCNMAKohGc7wJkdAOUL6J/YFpean/vwMWg64rJD4pycBeg==", "cpu": [ "arm" ], @@ -1439,9 +1092,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.25.tgz", - "integrity": "sha512-stzpke+bRaNFM/HrZPRjX0aQZ86S/2DChVCwb8NAV1n5lu9mz1CS750y7WbbtX/KZjk92FsCeRy2qwkvjI0gWw==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.5.29.tgz", + "integrity": "sha512-eH/Q9+8O5qhSxMestZnhuS1xqQMr6M7SolZYxiXJqxArXYILLCF+nq2R9SxuMl0CfjHSpb6+hHPk/HXy54eIRA==", "cpu": [ "arm64" ], @@ -1455,9 +1108,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.25.tgz", - "integrity": "sha512-UckUfDYedish/bj2V1jgQDGgouLhyRpG7jgF3mp8jHir11V2K6JiTyjFoz99eOiclS3+hNdr4QLJ+ifrQMJNZw==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.5.29.tgz", + "integrity": "sha512-TERh2OICAJz+SdDIK9+0GyTUwF6r4xDlFmpoiHKHrrD/Hh3u+6Zue0d7jQ/he/i80GDn4tJQkHlZys+RZL5UZg==", "cpu": [ "arm64" ], @@ -1471,9 +1124,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.25.tgz", - "integrity": "sha512-LwbJEgNT3lXbvz4WFzVNXNvs8DvxpoXjMZk9K9Hig8tmZQJKHC2qZTGomcyK5EFzfj2HBuBXZnAEW8ZT9PcEaA==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.5.29.tgz", + "integrity": "sha512-WMDPqU7Ji9dJpA+Llek2p9t7pcy7Bob8ggPUvgsIlv3R/eesF9DIzSbrgl6j3EAEPB9LFdSafsgf6kT/qnvqFg==", "cpu": [ "x64" ], @@ -1487,9 +1140,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.25.tgz", - "integrity": "sha512-rsepMTgml0EkswWkBpg3Wrjj5eqjwTzZN5omAn1klzXSZnClTrfeHvBuoIJYVr1yx+jmBkqySgME2p7+magUAw==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.5.29.tgz", + "integrity": "sha512-DO14glwpdKY4POSN0201OnGg1+ziaSVr6/RFzuSLggshwXeeyVORiHv3baj7NENhJhWhUy3NZlDsXLnRFkmhHQ==", "cpu": [ "x64" ], @@ -1503,9 +1156,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.25.tgz", - "integrity": "sha512-DJDsLBsRBV3uQBShRK2x6fqzABp9RLNVxDUpTTvUjc7qywJ8vS/yn+POK/zCyVEqLagf1z/8D5CEQ+RAIJq1NA==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.5.29.tgz", + "integrity": "sha512-V3Y1+a1zG1zpYXUMqPIHEMEOd+rHoVnIpO/KTyFwAmKVu8v+/xPEVx/AGoYE67x4vDAAvPQrKI3Aokilqa5yVg==", "cpu": [ "arm64" ], @@ -1519,9 +1172,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.25.tgz", - "integrity": "sha512-BARL1ulHol53MEKC1ZVWM3A3FP757UUgG5Q8v97za+4a1SaIgbwvAQyHDxMYWi9+ij+OapK8YnWjJcFa17g8dw==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.5.29.tgz", + "integrity": "sha512-OrM6yfXw4wXhnVFosOJzarw0Fdz5Y0okgHfn9oFbTPJhoqxV5Rdmd6kXxWu2RiVKs6kGSJFZXHDeUq2w5rTIMg==", "cpu": [ "ia32" ], @@ -1535,9 +1188,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.5.25", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.25.tgz", - "integrity": "sha512-o+MHUWrQI9iR6EusEV8eNU2Ezi3KtlhUR4gfptQN5MbVzlgjTvQbhiKpE1GYOxp+0BLBbKRwITKOcdhxfEJ2Uw==", + "version": "1.5.29", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.5.29.tgz", + "integrity": "sha512-eD/gnxqKyZQQR0hR7TMkIlJ+nCF9dzYmVVNbYZWuA1Xy94aBPUsEk3Uw3oG7q6R3ErrEUPP0FNf2ztEnv+I+dw==", "cpu": [ "x64" ], @@ -1565,9 +1218,9 @@ } }, "node_modules/@swc/types": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", - "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.8.tgz", + "integrity": "sha512-RNFA3+7OJFNYY78x0FYwi1Ow+iF1eF5WvmfY1nXPOEH4R2p/D4Cr1vzje7dNAI2aLFqpv8Wyz4oKSWqIZArpQA==", "dev": true, "dependencies": { "@swc/counter": "^0.1.3" @@ -1687,6 +1340,7 @@ "version": "3.3.5", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "dev": true, "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" @@ -1728,12 +1382,14 @@ "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", + "devOptional": true }, "node_modules/@types/react": { "version": "18.3.3", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "devOptional": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1760,6 +1416,7 @@ "version": "5.1.34", "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.34.tgz", "integrity": "sha512-mmiVvwpYklFIv9E8qfxuPyIt/OuyIrn6gMOAMOFUO3WJfSrSE+sGUoa4PiZj77Ut7bKZpaa6o1fBKS/4TOEvnA==", + "dev": true, "dependencies": { "@types/hoist-non-react-statics": "*", "@types/react": "*", @@ -1772,16 +1429,16 @@ "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", - "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", + "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/type-utils": "7.12.0", - "@typescript-eslint/utils": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/type-utils": "7.13.0", + "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1805,15 +1462,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", - "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", + "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "debug": "^4.3.4" }, "engines": { @@ -1833,13 +1490,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", - "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0" + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1850,13 +1507,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", - "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", + "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.12.0", - "@typescript-eslint/utils": "7.12.0", + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/utils": "7.13.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1877,9 +1534,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", - "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1890,13 +1547,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", - "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/visitor-keys": "7.12.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1918,15 +1575,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", - "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", + "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.12.0", - "@typescript-eslint/types": "7.12.0", - "@typescript-eslint/typescript-estree": "7.12.0" + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -1940,12 +1597,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", - "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/types": "7.13.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { @@ -2331,9 +1988,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", "dev": true, "funding": [ { @@ -2350,10 +2007,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", + "caniuse-lite": "^1.0.30001629", + "electron-to-chromium": "^1.4.796", "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "update-browserslist-db": "^1.0.16" }, "bin": { "browserslist": "cli.js" @@ -2437,9 +2094,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001629", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001629.tgz", - "integrity": "sha512-c3dl911slnQhmxUIT4HhYzT7wnBK/XYpGnYLOj4nJBaRiw52Ibe7YxlDaAeRECvA786zCuExhxIUJ2K7nHMrBw==", + "version": "1.0.30001634", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz", + "integrity": "sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA==", "dev": true, "funding": [ { @@ -2810,10 +2467,18 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, + "node_modules/ed2curve": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/ed2curve/-/ed2curve-0.3.0.tgz", + "integrity": "sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ==", + "dependencies": { + "tweetnacl": "1.x.x" + } + }, "node_modules/electron-to-chromium": { - "version": "1.4.695", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.695.tgz", - "integrity": "sha512-eMijZmeqPtm774pCZIOrfUHMs/7ls++W1sLhxwqgu8KQ8E2WmMtzwyqOMt0XXUJ3HTIPfuwlfwF+I5cwnfItBA==", + "version": "1.4.803", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.803.tgz", + "integrity": "sha512-61H9mLzGOCLLVsnLiRzCbc63uldP0AniRYPV3hbGVtONA1pI7qSGILdbofR7A8TMbOypDocEAjH/e+9k1QIe3g==", "dev": true }, "node_modules/emoji-regex": { @@ -2831,9 +2496,9 @@ } }, "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -2843,29 +2508,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { @@ -3446,9 +3111,9 @@ "dev": true }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "version": "16.8.2", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.2.tgz", + "integrity": "sha512-cvVIBILwuoSyD54U4cF/UXDh5yAobhNV/tPygI4lZhgOIJQE/WLWC4waBRb4I6bDVYb3OVx3lfHbaQOEoUD5sg==", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -4203,9 +3868,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4387,9 +4052,9 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/posthog-js": { - "version": "1.138.1", - "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.138.1.tgz", - "integrity": "sha512-hLahTznM0/iSM3vl6QGcmdG/zgCcW2DaQqPf7OtXCoqxNdYCWTNp6/sqepd6CxtDmJfm1S5Cbu1tD9TSksOYcA==", + "version": "1.139.2", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.139.2.tgz", + "integrity": "sha512-myyuOADqZvYwgqmriwlKDEUDwLhscivFLh67UWBj4Wt9kOlmklvJb36W0ES2GAS6IdojbnGZGH5lF3heqreLWQ==", "dependencies": { "fflate": "^0.4.8", "preact": "^10.19.3" @@ -4571,18 +4236,6 @@ "react-dom": ">=16.8" } }, - "node_modules/react-toastify": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", - "integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==", - "dependencies": { - "clsx": "^2.1.0" - }, - "peerDependencies": { - "react": ">=18", - "react-dom": ">=18" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -4618,6 +4271,11 @@ "node": ">=8.10.0" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/rehackt": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/rehackt/-/rehackt-0.1.0.tgz", @@ -5231,9 +4889,9 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", "dev": true, "funding": [ { @@ -5250,8 +4908,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -5274,13 +4932,25 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vite": { - "version": "5.2.13", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.13.tgz", - "integrity": "sha512-SSq1noJfY9pR3I1TUENL3rQYDQCFqgD+lM6fTRAM8Nv6Lsg5hDLaXkjETVeBt+7vZBCMoibD+6IWnT2mJ+Zb/A==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.1.tgz", + "integrity": "sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==", "dev": true, "dependencies": { - "esbuild": "^0.20.1", + "esbuild": "^0.21.3", "postcss": "^8.4.38", "rollup": "^4.13.0" }, diff --git a/web-app/package.json b/web-app/package.json index 2e65682..de461be 100644 --- a/web-app/package.json +++ b/web-app/package.json @@ -13,13 +13,12 @@ "node": ">=20.11.0" }, "dependencies": { - "@apollo/client": "^3.10.4", - "@aptos-labs/ts-sdk": "^1.18.1", - "@aptos-labs/wallet-adapter-react": "^3.0.6", + "@apollo/client": "^3.10.5", + "@aptos-labs/ts-sdk": "^1.19.0", + "@aptos-labs/wallet-adapter-react": "^3.2.0", "@headlessui/react": "^2.0.4", "@heroicons/react": "^2.1.3", "@noble/hashes": "^1.4.0", - "@types/styled-components": "^5.1.34", "aptos": "^1.21.0", "axios": "^1.7.2", "bn.js": "^5.2.1", @@ -31,16 +30,15 @@ "decimal.js": "^10.4.3", "echarts": "^5.5.0", "echarts-for-react": "^3.0.2", - "graphql": "^16.8.1", + "graphql": "^16.8.2", "graphql-ws": "^5.16.0", "lodash": "^4.17.21", - "posthog-js": "^1.138.1", + "posthog-js": "^1.139.2", "prismjs": "^1.29.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-qr-code": "^2.0.14", "react-router-dom": "^6.23.1", - "react-toastify": "^10.0.5", "styled-components": "^6.1.11" }, "devDependencies": { @@ -51,16 +49,17 @@ "@types/prismjs": "^1.26.4", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0", + "@types/styled-components": "^5.1.34", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", "@vitejs/plugin-react-swc": "^3.7.0", "autoprefixer": "^10.4.19", - "eslint": "^8.57.0", + "eslint": "^8.56.0", "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.7", "postcss": "^8.4.38", "tailwindcss": "^3.4.4", "typescript": "^5.4.5", - "vite": "^5.2.13" + "vite": "^5.3.1" } } diff --git a/web-app/src/modules/core/App.tsx b/web-app/src/modules/core/App.tsx index 7617832..2683660 100644 --- a/web-app/src/modules/core/App.tsx +++ b/web-app/src/modules/core/App.tsx @@ -1,10 +1,8 @@ import { FC } from 'react'; import { RouterProvider } from 'react-router-dom'; -import 'react-toastify/dist/ReactToastify.css'; -import { ToastContainer, Slide } from 'react-toastify'; -import { ThemeProvider } from 'styled-components'; import { ApolloProvider } from '@apollo/client'; import { AptosWalletAdapterProvider, Wallet } from '@aptos-labs/wallet-adapter-react'; +import { ThemeProvider } from 'styled-components'; import { PosteroWallet } from '../postero-wallet'; import apolloClient from './apollo'; @@ -29,19 +27,6 @@ const App: FC = () => { - diff --git a/web-app/src/modules/core/router.tsx b/web-app/src/modules/core/router.tsx index 7ed22c7..44342f0 100644 --- a/web-app/src/modules/core/router.tsx +++ b/web-app/src/modules/core/router.tsx @@ -3,7 +3,7 @@ import Transactions from './routes/Transactions'; import Transaction from './routes/Transaction'; import Home from './routes/Home'; import Account from './routes/Account'; -// import Accounts from './routes/Accounts'; +import Accounts from './routes/Accounts'; import AccountOverview from './routes/Account/Overview'; import AccountTransactions from './routes/Account/UserTransactions'; import AccountResources from './routes/Account/Resources'; @@ -14,7 +14,6 @@ import Validators from './routes/Validators'; import Module from './routes/Account/Modules/Module'; import Stats from './routes/Stats'; import Postero from './routes/Postero'; -import CommunityWallets from './routes/CommunityWallets'; const router = createBrowserRouter([ { @@ -65,10 +64,10 @@ const router = createBrowserRouter([ path: '/blocks/:blockHeight', element: , }, - // { - // path: '/accounts', - // element: , - // }, + { + path: '/accounts', + element: , + }, { path: '/validators', element: , @@ -77,10 +76,6 @@ const router = createBrowserRouter([ path: '/stats', element: , }, - { - path: '/community-wallets', - element: , - }, { path: '/postero', element: , diff --git a/web-app/src/modules/core/routes/Account/Account.tsx b/web-app/src/modules/core/routes/Account/Account.tsx index 5a9d353..4a36b51 100644 --- a/web-app/src/modules/core/routes/Account/Account.tsx +++ b/web-app/src/modules/core/routes/Account/Account.tsx @@ -85,7 +85,7 @@ const Account: FC = ({ accountAddress }) => { +

{account.address} diff --git a/web-app/src/modules/core/routes/Account/Movements/TransferMovement.tsx b/web-app/src/modules/core/routes/Account/Movements/TransferMovement.tsx index 087cdf7..a8f0804 100644 --- a/web-app/src/modules/core/routes/Account/Movements/TransferMovement.tsx +++ b/web-app/src/modules/core/routes/Account/Movements/TransferMovement.tsx @@ -19,7 +19,7 @@ const TransferMovement: FC = ({ movement }) => { }, [transaction.arguments]); return ( -
+
{' → '} diff --git a/web-app/src/modules/core/routes/Accounts/Accounts.tsx b/web-app/src/modules/core/routes/Accounts/Accounts.tsx index ef028dd..ec7c78c 100644 --- a/web-app/src/modules/core/routes/Accounts/Accounts.tsx +++ b/web-app/src/modules/core/routes/Accounts/Accounts.tsx @@ -1,9 +1,18 @@ -import { FC } from 'react'; +import { FC, useState } from 'react'; import Page from '../../../ui/Page'; import AccountsStats from './components/AccountsStats'; -import AccountsTables from './components/AccountsTables'; +import ToggleButton from '../../../ui/ToggleButton'; +import TopAccountsTable from './components/TopAccountsTable'; +import CommunityWalletsTable from './components/CommunityWalletsTable'; const Accounts: FC = () => { + const [activeView, setActiveView] = useState('topAccounts'); + + const toggleOptions = [ + { label: 'Top Accounts', value: 'topAccounts' }, + { label: 'Community Wallets', value: 'communityWallets' }, + ]; + return (

@@ -11,7 +20,10 @@ const Accounts: FC = () => {

- +
+ + {activeView === 'topAccounts' ? : } +
); diff --git a/web-app/src/modules/core/routes/Accounts/components/AccountsStats.tsx b/web-app/src/modules/core/routes/Accounts/components/AccountsStats.tsx index ba3d2a7..bc77015 100644 --- a/web-app/src/modules/core/routes/Accounts/components/AccountsStats.tsx +++ b/web-app/src/modules/core/routes/Accounts/components/AccountsStats.tsx @@ -1,64 +1,47 @@ import { FC, useEffect, useState } from 'react'; +import axios from 'axios'; + import StatsCard from '../../../../ui/StatsCard'; +import { config } from '../../../../../config'; -const AccountsStats: FC = () => { - const [stats, setStats] = useState<{ - totalAccounts: string | null; - dailyActiveAccounts: string | null; - monthlyActiveAccounts: string | null; - quarterActiveAccounts: string | null; - }>({ - totalAccounts: null, - dailyActiveAccounts: null, - monthlyActiveAccounts: null, - quarterActiveAccounts: null, +const getData = async () => { + const res = await axios({ + url: `${config.apiHost}/stats/accounts-stats`, }); - const [loading, setLoading] = useState(true); + return res.data; +}; - useEffect(() => { - // Mock function to fetch data, replace with actual data fetching logic - const fetchStats = async () => { - setLoading(true); - const fetchedStats = await fetchDataFromAPI(); - setStats(fetchedStats); - setLoading(false); - }; +const AccountsStats: FC = () => { + const [data, setData] = useState(null); - fetchStats(); + useEffect(() => { + getData().then(setData); }, []); return (
- +
); }; -// Mock function to fetch data, replace with actual data fetching logic -const fetchDataFromAPI = async () => { - // Simulate data fetching delay - await new Promise((resolve) => setTimeout(resolve, 1000)); - return { - totalAccounts: (51234).toLocaleString(), - dailyActiveAccounts: (1500).toLocaleString(), - monthlyActiveAccounts: (5000).toLocaleString(), - quarterActiveAccounts: (10000).toLocaleString(), - }; -}; - export default AccountsStats; diff --git a/web-app/src/modules/core/routes/Accounts/components/CommunityWalletRow.tsx b/web-app/src/modules/core/routes/Accounts/components/CommunityWalletRow.tsx new file mode 100644 index 0000000..ac110bd --- /dev/null +++ b/web-app/src/modules/core/routes/Accounts/components/CommunityWalletRow.tsx @@ -0,0 +1,38 @@ +import { FC } from 'react'; +import AccountAddress from '../../../../ui/AccountAddress'; +import Money from '../../../../ui/Money'; +import { ICommunityWallet } from '../../../../interface/CommunityWallets.interface'; + +interface CommunityWalletRowProps { + wallet: ICommunityWallet; +} + +const CommunityWalletRow: FC = ({ wallet }) => { + return ( + + {wallet.rank} + + + + + + {wallet.name} + + + + + {wallet.description} + + + + {wallet.balance} + + + ); +}; + +export default CommunityWalletRow; diff --git a/web-app/src/modules/core/routes/Accounts/components/CommunityWalletRowSkeleton.tsx b/web-app/src/modules/core/routes/Accounts/components/CommunityWalletRowSkeleton.tsx new file mode 100644 index 0000000..bf8d8a7 --- /dev/null +++ b/web-app/src/modules/core/routes/Accounts/components/CommunityWalletRowSkeleton.tsx @@ -0,0 +1,27 @@ +import { FC } from 'react'; + +const CommunityWalletRowSkeleton: FC = () => { + return ( + + +
+ + +
+ + +
+
+ + +
+
+ + +
+ + + ); +}; + +export default CommunityWalletRowSkeleton; diff --git a/web-app/src/modules/core/routes/Accounts/components/CommunityWalletsTable.tsx b/web-app/src/modules/core/routes/Accounts/components/CommunityWalletsTable.tsx new file mode 100644 index 0000000..f9a2b17 --- /dev/null +++ b/web-app/src/modules/core/routes/Accounts/components/CommunityWalletsTable.tsx @@ -0,0 +1,136 @@ +import { FC, useState } from 'react'; +import { gql, useQuery } from '@apollo/client'; + +import SortableTh from './SortableTh'; +import CommunityWalletRow from './CommunityWalletRow'; +import CommunityWalletRowSkeleton from './CommunityWalletRowSkeleton'; +import { ICommunityWallet } from '../../../../interface/CommunityWallets.interface'; + +const GET_COMMUNITY_WALLETS = gql` + query CommunityWallets { + getCommunityWallets { + rank + address + name + balance + description + } + } +`; +type SortOrder = 'asc' | 'desc'; + +const CommunityWalletsTable: FC = () => { + const { data, loading } = useQuery(GET_COMMUNITY_WALLETS); + const [sortColumn, setSortColumn] = useState('rank'); + const [sortOrder, setSortOrder] = useState('desc'); + + const handleSort = (column: string) => { + if (sortColumn === column) { + setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc'); + } else { + setSortColumn(column); + setSortOrder('asc'); + } + }; + + const getSortedWallets = (wallets: ICommunityWallet[]) => { + const sortedWallets = [...wallets].sort((a, b) => { + const [aValue, bValue] = getValue(a, b, sortColumn); + + if (aValue === bValue) { + return a.address.localeCompare(b.address); + } + + return aValue < bValue ? -1 : 1; + }); + + if (sortOrder === 'asc') { + sortedWallets.reverse(); + } + + return sortedWallets; + }; + + const getValue = (a: ICommunityWallet, b: ICommunityWallet, column: string): [any, any] => { + let value1: any; + let value2: any; + + switch (column) { + case 'rank': + value1 = a.rank; + value2 = b.rank; + break; + case 'address': + value1 = a.address; + value2 = b.address; + break; + case 'name': + value1 = a.name; + value2 = b.name; + break; + case 'balance': + value1 = a.balance; + value2 = b.balance; + break; + case 'description': + value1 = a.description; + value2 = b.description; + break; + default: + value1 = a.rank; + value2 = b.rank; + } + + return [value1, value2]; + }; + + const columns = [ + { key: 'rank', label: 'Rank', className: 'text-center' }, + { key: 'address', label: 'Address', className: '' }, + { key: 'name', label: 'Name', className: 'text-left' }, + { key: 'description', label: 'Description', className: 'text-left' }, + { key: 'balance', label: 'Balance', className: 'text-right' }, + ]; + + const wallets = data?.getCommunityWallets ? getSortedWallets(data.getCommunityWallets) : []; + + return ( +
+
+
+
+ + + + {columns.map((col) => ( + + {col.label} + + ))} + + + + {!loading + ? wallets.map((wallet) => ( + + )) + : Array.from({ length: 10 }).map((_, index) => ( + + ))} + +
+
+
+
+
+ ); +}; + +export default CommunityWalletsTable; diff --git a/web-app/src/modules/core/routes/Accounts/components/SortableTh.tsx b/web-app/src/modules/core/routes/Accounts/components/SortableTh.tsx new file mode 100644 index 0000000..d6b885d --- /dev/null +++ b/web-app/src/modules/core/routes/Accounts/components/SortableTh.tsx @@ -0,0 +1,38 @@ +import { FC } from 'react'; +import { ArrowUpIcon, ArrowDownIcon } from '@heroicons/react/20/solid'; + +interface SortableThProps { + column: string; + sortColumn: string; + sortOrder: 'asc' | 'desc'; + onSort: (column: string) => void; + className?: string; + children: React.ReactNode; +} + +const SortableTh: FC = ({ + column, + sortColumn, + sortOrder, + onSort, + className, + children, +}) => { + return ( + onSort(column)} + > + {children} + {sortColumn === column && + (sortOrder === 'asc' ? ( + + ) : ( + + ))} + + ); +}; + +export default SortableTh; diff --git a/web-app/src/modules/core/routes/Accounts/components/TopAccountRow.tsx b/web-app/src/modules/core/routes/Accounts/components/TopAccountRow.tsx new file mode 100644 index 0000000..2381bbe --- /dev/null +++ b/web-app/src/modules/core/routes/Accounts/components/TopAccountRow.tsx @@ -0,0 +1,32 @@ +import { FC } from 'react'; +import { ITopAccount } from '../../../../interface/TopAccount.interface'; +import AccountAddress from '../../../../ui/AccountAddress'; +import Money from '../../../../ui/Money'; +import ProgressBar from '../../Validators/components/ProgressBar'; + +interface TopAccountRowProps { + account: ITopAccount; +} + +const TopAccountRow: FC = ({ account }) => { + return ( + + {account.rank} + + + + {account.publicName} + + {account.balance} + + + + + + ); +}; + +export default TopAccountRow; diff --git a/web-app/src/modules/core/routes/Accounts/components/TopAccountRowSkeleton.tsx b/web-app/src/modules/core/routes/Accounts/components/TopAccountRowSkeleton.tsx new file mode 100644 index 0000000..875fbe5 --- /dev/null +++ b/web-app/src/modules/core/routes/Accounts/components/TopAccountRowSkeleton.tsx @@ -0,0 +1,25 @@ +import { FC } from 'react'; + +const TopAccountRowSkeleton: FC = () => { + return ( + + +
+ + +
+ + +
+ + +
+ + +
+ + + ); +}; + +export default TopAccountRowSkeleton; diff --git a/web-app/src/modules/core/routes/Accounts/components/TopAccountsTable.tsx b/web-app/src/modules/core/routes/Accounts/components/TopAccountsTable.tsx new file mode 100644 index 0000000..1d70631 --- /dev/null +++ b/web-app/src/modules/core/routes/Accounts/components/TopAccountsTable.tsx @@ -0,0 +1,145 @@ +import { FC, useState } from 'react'; +import { gql, useQuery } from '@apollo/client'; +import { ITopAccount } from '../../../../interface/TopAccount.interface'; +import SortableTh from './SortableTh'; +import TopAccountRow from './TopAccountRow'; +import TopAccountRowSkeleton from './TopAccountRowSkeleton'; + +interface TopAccountsTableProps { + accounts?: ITopAccount[]; +} + +type SortOrder = 'asc' | 'desc'; + +const GET_TOP_ACCOUNTS = gql` + query Accounts { + getTopAccounts { + rank + address + publicName + balance + cumulativeShare { + amount + percentage + } + } + } +`; + +const TopAccountsTable: FC = () => { + const [sortColumn, setSortColumn] = useState('rank'); + const [sortOrder, setSortOrder] = useState('desc'); + + const { data } = useQuery(GET_TOP_ACCOUNTS); + const accounts: ITopAccount[] = data ? data.getTopAccounts : null; + + const handleSort = (column: string) => { + if (sortColumn === column) { + setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc'); + } else { + setSortColumn(column); + setSortOrder('asc'); + } + }; + + const getSortedAccounts = (accounts: ITopAccount[]) => { + const sortedAccounts = [...accounts].sort((a, b) => { + const [aValue, bValue] = getValue(a, b, sortColumn); + + if (aValue === bValue) { + return a.address.localeCompare(b.address); + } + + return aValue < bValue ? -1 : 1; + }); + + if (sortOrder === 'asc') { + sortedAccounts.reverse(); + } + + return sortedAccounts; + }; + + const getValue = (a: ITopAccount, b: ITopAccount, column: string): [any, any] => { + let value1: any; + let value2: any; + + switch (column) { + case 'rank': + value1 = a.rank; + value2 = b.rank; + break; + case 'address': + value1 = a.address; + value2 = b.address; + break; + case 'publicName': + value1 = a.publicName; + value2 = b.publicName; + break; + case 'balance': + value1 = a.balance; + value2 = b.balance; + break; + default: + value1 = a.rank; + value2 = b.rank; + } + + return [value1, value2]; + }; + + let sortedAccounts; + + if (accounts) { + sortedAccounts = getSortedAccounts(accounts); + } + + const columns = [ + { key: 'rank', label: 'Rank', className: 'text-center' }, + { key: 'address', label: 'Address', className: '' }, + { key: 'publicName', label: 'Public Name', className: 'text-left' }, + { key: 'balance', label: 'Balance', className: 'text-right' }, + { key: 'cumulativeShare', label: 'Cumulative Share (%)', className: 'text-right' }, + ]; + + return ( +
+
+
+
+ + + + {columns.map((col) => ( + + {col.label} + + ))} + + + + {sortedAccounts + ? sortedAccounts.map((account) => ( + + )) + : Array.from({ length: 10 }).map((_, index) => ( + + ))} + +
+
+
+
+
+ ); +}; + +export default TopAccountsTable; diff --git a/web-app/src/modules/core/routes/CommunityWallets/CommunityWallets.tsx b/web-app/src/modules/core/routes/CommunityWallets/CommunityWallets.tsx deleted file mode 100644 index 073b44b..0000000 --- a/web-app/src/modules/core/routes/CommunityWallets/CommunityWallets.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { gql, useQuery } from '@apollo/client'; -import { FC } from 'react'; - -import { ICommunityWalletInfo } from '../../../interface/CommunityWallets.interface'; -import CommunityWalletRow from '../../../ui/CommunityWalletsTable'; -import Page from '../../../ui/Page'; - -const GET_COMMUNITY_WALLETS = gql` - query CommunityWallets { - communityWallets { - address - name - description - } - } -`; - -const CommunityWallets: FC = () => { - const { data } = useQuery<{ - communityWallets: ICommunityWalletInfo[]; - }>(GET_COMMUNITY_WALLETS); - - if (!data) { - return null; - } - - return ( - -
-
-
-
-

Community wallets

-
- -
- -
- - - - - - - - - - - {data.communityWallets.map((communityWalletInfo: ICommunityWalletInfo) => { - return ( - - ); - })} - -
- Wallet - - Name - - Description - - Balance -
- - {/* @TODO: PAGINATION */} -
-
-
-
- ); -}; - -export default CommunityWallets; diff --git a/web-app/src/modules/core/routes/CommunityWallets/index.ts b/web-app/src/modules/core/routes/CommunityWallets/index.ts deleted file mode 100644 index 527b0fc..0000000 --- a/web-app/src/modules/core/routes/CommunityWallets/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./CommunityWallets"; diff --git a/web-app/src/modules/core/routes/Home/Stats.tsx b/web-app/src/modules/core/routes/Home/Stats.tsx index c6e2a88..ba7ab6f 100644 --- a/web-app/src/modules/core/routes/Home/Stats.tsx +++ b/web-app/src/modules/core/routes/Home/Stats.tsx @@ -2,7 +2,13 @@ import { format as d3Format } from 'd3-format'; import { FC, useEffect, useState } from 'react'; import { Link, NavLink } from 'react-router-dom'; import useAptos from '../../../aptos'; -import { useLedgerInfo, useTotalSupply, useValidatorSet } from '../../../ol'; +import { + useLedgerInfo, + useTotalSupply, + useValidatorSet, + useAccountsStats, + useTotalTransactions, +} from '../../../ol'; import Countdown from '../../../ui/Countdown'; import NodeMap from '../../../ui/NodeMap'; @@ -19,7 +25,7 @@ const Validators = () => {
Total Validators - {validatorSet ? validatorSet.active_validators.length : null} + {validatorSet?.active_validators.length}
@@ -44,6 +50,8 @@ const Stats: FC = () => { const totalSupply = useTotalSupply(); const ledgerInfo = useLedgerInfo(); + const accountsStats = useAccountsStats(); + const totalTransactions = useTotalTransactions(); useEffect(() => { let timeout: NodeJS.Timeout | undefined = undefined; @@ -155,27 +163,25 @@ const Stats: FC = () => { {false && ( <> - {/* @TODO: DUMMY DATA */}
Transactions - XXXX + {totalTransactions?.toLocaleString()}
- {/* @TODO: DUMMY DATA */}
Total Accounts - XXXX + {accountsStats?.totalAccounts?.toLocaleString()}
diff --git a/web-app/src/modules/core/routes/Home/Stats/PriceStats.tsx b/web-app/src/modules/core/routes/Home/Stats/PriceStats.tsx index 0b008a1..ecbb8d9 100644 --- a/web-app/src/modules/core/routes/Home/Stats/PriceStats.tsx +++ b/web-app/src/modules/core/routes/Home/Stats/PriceStats.tsx @@ -1,5 +1,4 @@ import { FC } from 'react'; -import { Link } from 'react-router-dom'; import clsx from 'clsx'; import Logo from '../../../../ui/Logo/Logo'; @@ -55,13 +54,14 @@ const PriceStats: FC = () => { LIBRA
- View on CoinGecko - + Coingecko logo
diff --git a/web-app/src/modules/core/routes/Stats/Stats.tsx b/web-app/src/modules/core/routes/Stats/Stats.tsx index 4e22df1..60850ad 100644 --- a/web-app/src/modules/core/routes/Stats/Stats.tsx +++ b/web-app/src/modules/core/routes/Stats/Stats.tsx @@ -7,6 +7,7 @@ import ChartComponent from './ChartComponent'; import StatItem from './components/StatItem'; import StatsContainer from './components/StatsContainer'; import Page from '../../../ui/Page'; +import AccountAddress from '../../../ui/AccountAddress'; const getData = async () => { const res = await fetch(`${config.apiHost}/stats`); @@ -272,14 +273,7 @@ const Coinstats = () => { ) => ( - - {account.address} - + {account.unlockedBalance} diff --git a/web-app/src/modules/core/routes/Validators/Validators.tsx b/web-app/src/modules/core/routes/Validators/Validators.tsx index b413630..46cd0d2 100644 --- a/web-app/src/modules/core/routes/Validators/Validators.tsx +++ b/web-app/src/modules/core/routes/Validators/Validators.tsx @@ -1,23 +1,22 @@ import { FC } from 'react'; import { gql, useQuery } from '@apollo/client'; - import Page from '../../../ui/Page'; import ValidatorsTable from './components/ValidatorsTable'; import ValidatorsStats from './components/ValidatorsStats'; -import { IValidator } from '../../../interface/Validator.interface'; const GET_VALIDATORS = gql` - query GetValidators { - validators { + query Validators { + getValidators { inSet index address votingPower - account { - balance - slowWallet { - unlocked - } + balance + unlocked + grade { + compliant + failedBlocks + proposedBlocks } grade { compliant @@ -25,6 +24,7 @@ const GET_VALIDATORS = gql` proposedBlocks } vouches { + address epoch } currentBid { @@ -33,14 +33,15 @@ const GET_VALIDATORS = gql` } city country + auditQualification } } `; const Validators: FC = () => { - const { data, error } = useQuery<{ - validators: IValidator[]; - }>(GET_VALIDATORS); + const { data, error } = useQuery(GET_VALIDATORS, { + pollInterval: 30000, // Poll every 30 seconds + }); if (error) { console.log('error', error); @@ -57,8 +58,8 @@ const Validators: FC = () => { Validators

- - + +
); diff --git a/web-app/src/modules/core/routes/Validators/components/ValidatorRow.tsx b/web-app/src/modules/core/routes/Validators/components/ValidatorRow.tsx index 6304e2c..62e2443 100644 --- a/web-app/src/modules/core/routes/Validators/components/ValidatorRow.tsx +++ b/web-app/src/modules/core/routes/Validators/components/ValidatorRow.tsx @@ -3,8 +3,9 @@ import clsx from 'clsx'; import AccountAddress from '../../../../ui/AccountAddress'; import Money from '../../../../ui/Money'; import { IValidator } from '../../../../interface/Validator.interface'; -// import ProgressBar from './ProgressBar'; import { CheckIcon, XMarkIcon } from '@heroicons/react/20/solid'; +import ProgressBar from './ProgressBar'; +import Vouches from './Vouches'; interface ValidatorRowProps { validator: IValidator; @@ -12,46 +13,54 @@ interface ValidatorRowProps { const ValidatorRow: FC = ({ validator }) => { return ( - + + {validator.inSet ? ( + + {validator.grade.compliant ? ( + + ) : ( + + )} + 0 ? 'text-red-500' : ''}> + {validator.grade.failedBlocks.toLocaleString()} + {' '} + / {validator.grade.proposedBlocks.toLocaleString()} + + ) : ( + + {validator.auditQualification?.toLocaleString()} + + )} - {validator.grade.compliant ? ( - - ) : ( - - )} - 0 ? 'text-red-500' : ''}> - {validator.grade.failedBlocks.toLocaleString()} - {' '} - / {validator.grade.proposedBlocks.toLocaleString()} - - - {validator.vouches.length.toLocaleString()} + {`${validator.currentBid && validator.currentBid.currentBid.toLocaleString()} (${ validator.currentBid && validator.currentBid.expirationEpoch.toLocaleString() })`} - {/*isActive && ( + + {Number(validator.balance)} + + {validator.inSet && ( - )*/} - - {validator.city ? `${validator.city}, ${validator.country}` : 'Unknown'} - - - {Number(validator.account.balance)} - + )} + {validator.inSet && ( + + {validator.city ? `${validator.city}, ${validator.country}` : 'Unknown'} + + )} {/* {validator.account.slowWallet ? ( - {Number(validator.account.slowWallet.unlocked)} + {Number(validator.unlocked)} ) : ( '' )} diff --git a/web-app/src/modules/core/routes/Validators/components/ValidatorRowSkeleton.tsx b/web-app/src/modules/core/routes/Validators/components/ValidatorRowSkeleton.tsx index 46183c5..5ca31f3 100644 --- a/web-app/src/modules/core/routes/Validators/components/ValidatorRowSkeleton.tsx +++ b/web-app/src/modules/core/routes/Validators/components/ValidatorRowSkeleton.tsx @@ -15,13 +15,16 @@ const ValidatorRowSkeleton: FC = () => {
-
+
-
+
+ + +
diff --git a/web-app/src/modules/core/routes/Validators/components/ValidatorsStats.tsx b/web-app/src/modules/core/routes/Validators/components/ValidatorsStats.tsx index bc4b747..aac3781 100644 --- a/web-app/src/modules/core/routes/Validators/components/ValidatorsStats.tsx +++ b/web-app/src/modules/core/routes/Validators/components/ValidatorsStats.tsx @@ -1,5 +1,4 @@ import { FC } from 'react'; - import Money from '../../../../ui/Money'; import StatsCard from '../../../../ui/StatsCard'; import { IValidator } from '../../../../interface/Validator.interface'; @@ -11,10 +10,8 @@ interface ValidatorsStatsProps { const ValidatorsStats: FC = ({ validators }) => { const validatorSet = validators && validators.filter((it) => it.inSet); const eligible = validators && validatorSet && validators.length - validatorSet.length; - const totalLibra = - validators && validators.reduce((acc, it) => acc + Number(it.account.balance), 0); - const liquidLibra = - validators && validators.reduce((acc, it) => acc + Number(it.account.slowWallet?.unlocked), 0); + const totalLibra = validators && validators.reduce((acc, it) => acc + Number(it.balance), 0); + const liquidLibra = validators && validators.reduce((acc, it) => acc + Number(it.unlocked), 0); return (
diff --git a/web-app/src/modules/core/routes/Validators/components/ValidatorsTable.tsx b/web-app/src/modules/core/routes/Validators/components/ValidatorsTable.tsx index b737408..23d4a96 100644 --- a/web-app/src/modules/core/routes/Validators/components/ValidatorsTable.tsx +++ b/web-app/src/modules/core/routes/Validators/components/ValidatorsTable.tsx @@ -1,6 +1,6 @@ import { FC, useState } from 'react'; import { IValidator } from '../../../../interface/Validator.interface'; -import ToggleButton from './ToggleButton'; +import ToggleButton from '../../../../ui/ToggleButton'; import SortableTh from './SortableTh'; import ValidatorRow from './ValidatorRow'; import ValidatorRowSkeleton from './ValidatorRowSkeleton'; @@ -15,7 +15,13 @@ const ValidatorsTable: FC = ({ validators }) => { const [sortColumn, setSortColumn] = useState('index'); const [sortOrder, setSortOrder] = useState('desc'); const [previousSortColumn, setPreviousSortColumn] = useState('vouches'); - const [isActive, setIsActive] = useState(true); + const [isActive] = useState(true); + const [activeValue, setActiveValue] = useState('active'); + + const toggleOptions = [ + { label: 'Active', value: 'active' }, + { label: 'Inactive', value: 'inactive' }, + ]; const handleSort = (column: string) => { if (sortColumn === column) { @@ -30,11 +36,10 @@ const ValidatorsTable: FC = ({ validators }) => { const getFilteredValidators = () => { return validators ? validators.filter((validator) => { - if (isActive) { + if (activeValue === 'active') { return validator.inSet; - } else { - return !validator.inSet; } + return !validator.inSet; }) : []; }; @@ -84,6 +89,10 @@ const ValidatorsTable: FC = ({ validators }) => { value2 = b.grade.proposedBlocks - b.grade.failedBlocks; } break; + case 'audit': + value1 = a.auditQualification ? a.auditQualification[a.auditQualification.length - 1] : ''; + value2 = b.auditQualification ? b.auditQualification[b.auditQualification.length - 1] : ''; + break; case 'vouches': value1 = a.vouches.length; value2 = b.vouches.length; @@ -93,20 +102,20 @@ const ValidatorsTable: FC = ({ validators }) => { value2 = b.currentBid ? b.currentBid.currentBid : 0; break; case 'cumulativeShare': - value1 = Number(a.account.balance); - value2 = Number(b.account.balance); + value1 = a.cumulativeBalance?.percentage ?? 0; + value2 = b.cumulativeBalance?.percentage ?? 0; break; case 'location': value1 = a.country ? a.country + a.city : ''; value2 = b.country ? b.country + b.city : ''; break; case 'balance': - value1 = Number(a.account.balance); - value2 = Number(b.account.balance); + value1 = Number(a.balance); + value2 = Number(b.balance); break; case 'unlocked': - value1 = a.account.slowWallet ? Number(a.account.slowWallet.unlocked) : 0; - value2 = b.account.slowWallet ? Number(b.account.slowWallet.unlocked) : 0; + value1 = a.unlocked ? Number(a.unlocked) : 0; + value2 = b.unlocked ? Number(b.unlocked) : 0; break; default: value1 = a.address; @@ -124,11 +133,11 @@ const ValidatorsTable: FC = ({ validators }) => { filteredValidators = getFilteredValidators(); sortedValidators = getSortedValidators(filteredValidators); - const totalBalance = sortedValidators.reduce((acc, v) => acc + Number(v.account.balance), 0); + const totalBalance = validators.reduce((acc, v) => acc + Number(v.balance), 0); let cumulativeBalanceAmount = 0; cumulativeValidators = sortedValidators.map((validator) => { - cumulativeBalanceAmount += Number(validator.account.balance); + cumulativeBalanceAmount += Number(validator.balance); const cumulativeBalance = { amount: cumulativeBalanceAmount, @@ -142,37 +151,30 @@ const ValidatorsTable: FC = ({ validators }) => { }); } - function handleSetActive(boo: boolean) { - /*if (isActive && sortColumn == 'index') { - setSortColumn('vouches'); - setSortOrder('asc'); - }*/ - setIsActive(boo); - } - const columns = [ { key: 'address', label: 'Address', className: '' }, - //...(isActive ? [{ key: 'index', label: 'Set Position', className: '' }] : []), - { key: 'grade', label: 'Grade', className: 'text-center' }, - { key: 'vouches', label: 'Vouches', className: '' }, + ...(activeValue === 'active' + ? [{ key: 'grade', label: 'Grade', className: 'text-center' }] + : [{ key: 'audit', label: 'Audit', className: 'text-center' }]), + { key: 'vouches', label: 'Vouches', className: 'text-center' }, { key: 'currentBid', label: 'Bid (Exp. Epoch)', className: 'text-right' }, - /*...(isActive + { key: 'balance', label: 'Balance', className: 'text-right' }, + ...(activeValue === 'active' ? [ { key: 'cumulativeShare', label: 'Cumulative Share (%)', className: 'text-left whitespace-nowrap', }, + { key: 'location', label: 'Location', className: 'text-left' }, ] - : []),*/ - { key: 'location', label: 'Location', className: 'text-left' }, - { key: 'balance', label: 'Balance', className: 'text-right' }, + : []), // { key: 'unlocked', label: 'Unlocked', className: 'text-right' }, ]; return ( -
- +
+
diff --git a/web-app/src/modules/core/routes/Validators/components/Vouches.tsx b/web-app/src/modules/core/routes/Validators/components/Vouches.tsx new file mode 100644 index 0000000..151c6b0 --- /dev/null +++ b/web-app/src/modules/core/routes/Validators/components/Vouches.tsx @@ -0,0 +1,104 @@ +import { FC, useState } from 'react'; +import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react'; +import { XMarkIcon } from '@heroicons/react/24/outline'; + +import AccountAddress from '../../../../ui/AccountAddress'; + +interface Vouch { + address: string; + epoch: number; +} + +interface VouchesProps { + vouches: Vouch[]; +} + +const Vouches: FC = ({ vouches }) => { + const [open, setOpen] = useState(!true); + + return ( + <> +
+ +
+ + + + +
+ + +
+
+ + +
+ +
+
+
+ + Vouches + + +
+ + + + + + + + + + {vouches.map((vouch, index) => ( + + + + + + ))} + +
#EpochAddress
{index + 1}{vouch.epoch} + +
+
+
+
+
+
+
+
+
+
+ + ); +}; + +export default Vouches; diff --git a/web-app/src/modules/core/styles/GlobalStyles.ts b/web-app/src/modules/core/styles/GlobalStyles.ts index 2c2c814..86f3aab 100644 --- a/web-app/src/modules/core/styles/GlobalStyles.ts +++ b/web-app/src/modules/core/styles/GlobalStyles.ts @@ -12,6 +12,10 @@ const GlobalStyle = createGlobalStyle` padding: 0; box-sizing: border-box; } + + tr, td { + height: 64px; + } `; export default GlobalStyle; diff --git a/web-app/src/modules/interface/CommunityWallets.interface.ts b/web-app/src/modules/interface/CommunityWallets.interface.ts index 3d1d2dc..4b6438d 100644 --- a/web-app/src/modules/interface/CommunityWallets.interface.ts +++ b/web-app/src/modules/interface/CommunityWallets.interface.ts @@ -1,5 +1,7 @@ -export interface ICommunityWalletInfo { - description: string | null; - name: string | null; +export interface ICommunityWallet { + rank: number; address: string; + name?: string; + balance: number; + description?: string; } diff --git a/web-app/src/modules/interface/TopAccount.interface.ts b/web-app/src/modules/interface/TopAccount.interface.ts new file mode 100644 index 0000000..2b22765 --- /dev/null +++ b/web-app/src/modules/interface/TopAccount.interface.ts @@ -0,0 +1,12 @@ +export interface ICumulativeShare { + amount: number; + percentage: number; +} + +export interface ITopAccount { + rank: number; + address: string; + publicName: string; + balance: number; + cumulativeShare: ICumulativeShare; +} diff --git a/web-app/src/modules/interface/Validator.interface.ts b/web-app/src/modules/interface/Validator.interface.ts index bb6f1de..20c0c98 100644 --- a/web-app/src/modules/interface/Validator.interface.ts +++ b/web-app/src/modules/interface/Validator.interface.ts @@ -3,14 +3,11 @@ export interface IValidator { inSet: boolean; index: number; votingPower: number; - account: { - balance: string; - slowWallet: { - unlocked: string; - } | null; - }; + balance?: number; + unlocked?: number; vouches: { epoch: number; + address: string; }[]; grade: { compliant: boolean; @@ -27,4 +24,5 @@ export interface IValidator { } | null; city: string | null; country: string | null; + auditQualification: [string] | null; } diff --git a/web-app/src/modules/ol/index.ts b/web-app/src/modules/ol/index.ts index 8204aa7..4dccc3b 100644 --- a/web-app/src/modules/ol/index.ts +++ b/web-app/src/modules/ol/index.ts @@ -1,12 +1,14 @@ -import { useEffect, useState } from "react"; -import { Types } from "aptos"; -import useAptos from "../aptos"; +import { useEffect, useState } from 'react'; +import { gql, useQuery } from '@apollo/client'; +import { Types } from 'aptos'; +import useAptos from '../aptos'; +import { config } from '../../config'; -export const COIN_NAME = "LibraCoin"; +export const COIN_NAME = 'LibraCoin'; -export const COIN_MODULE = "gas_coin"; +export const COIN_MODULE = 'gas_coin'; -export const OL_FRAMEWORK = "0x1"; +export const OL_FRAMEWORK = '0x1'; interface AggregatorData { handle: string; @@ -26,7 +28,7 @@ export interface CoinInfo { integer: { vec: []; }; - } + }, ]; }; symbol: string; @@ -50,15 +52,16 @@ export interface ValidatorSet { total_voting_power: string; } +export interface AccountStats { + totalAccounts: number; +} + export const useValidatorSet = (): ValidatorSet | undefined => { const aptos = useAptos(); const [validatorSet, setValidatorSet] = useState(); useEffect(() => { const load = async () => { - const res = await aptos.getAccountResource( - "0x1", - "0x1::stake::ValidatorSet" - ); + const res = await aptos.getAccountResource('0x1', '0x1::stake::ValidatorSet'); const validatorSet = res.data as ValidatorSet; setValidatorSet(validatorSet); }; @@ -79,22 +82,22 @@ export const useTotalSupply = (): Money | undefined => { useEffect(() => { const load = async () => { const res = await aptos.getAccountResource( - "0x1", - "0x1::coin::CoinInfo<0x1::libra_coin::LibraCoin>" + '0x1', + '0x1::coin::CoinInfo<0x1::libra_coin::LibraCoin>', ); const coinInfo = res.data as CoinInfo; const aggregatorData = coinInfo?.supply?.vec[0]?.aggregator?.vec[0]; const tableItemRequest = { - key_type: "address", - value_type: "u128", + key_type: 'address', + value_type: 'u128', key: aggregatorData.key, } as Types.TableItemRequest; const totalSupplyStr: string = await aptos.getTableItem( aggregatorData.handle, - tableItemRequest + tableItemRequest, ); let totalSupply = parseInt(totalSupplyStr, 10); totalSupply = totalSupply / Math.pow(10, coinInfo.decimals); @@ -133,4 +136,30 @@ export const useLedgerInfo = (): Types.IndexResponse | undefined => { }, []); return ledgerInfo; -}; \ No newline at end of file +}; + +export const useAccountsStats = (): AccountStats | undefined => { + const [accountsStats, setAccountsStats] = useState(); + + useEffect(() => { + const load = async () => { + const res = await fetch(`${config.apiHost}/stats/accounts-stats`); + const accountStats = (await res.json()) as AccountStats; + setAccountsStats(accountStats); + }; + load(); + }, []); + + return accountsStats; +}; + +export const useTotalTransactions = (): number | undefined => { + const GET_USER_TRANSACTIONS = gql` + query GetUserTransactions { + userTransactionsCount + } + `; + + const { data } = useQuery<{ userTransactionsCount: number }>(GET_USER_TRANSACTIONS); + return data?.userTransactionsCount; +}; diff --git a/web-app/src/modules/ui/AccountAddress/AccountAddress.tsx b/web-app/src/modules/ui/AccountAddress/AccountAddress.tsx index c8eeb0b..8fd78d7 100644 --- a/web-app/src/modules/ui/AccountAddress/AccountAddress.tsx +++ b/web-app/src/modules/ui/AccountAddress/AccountAddress.tsx @@ -1,11 +1,10 @@ import { FC } from 'react'; import { Link } from 'react-router-dom'; -import { toast } from 'react-toastify'; import { normalizeHexString } from '../../../utils'; import HexString from '../HexString'; -import CopyIcon from '../Icons/CopyIcon'; import AddressAvatar from '../AddressAvatar'; +import CopyButton from '../CopyButton'; interface Props { address: string; @@ -13,24 +12,9 @@ interface Props { const AccountAddress: FC = ({ address }) => { const normalizedAddress = normalizeHexString(address); - - const handleCopy = (event: React.MouseEvent) => { - event.preventDefault(); - event.stopPropagation(); - - navigator.clipboard - .writeText(address) - .then(() => { - toast.success('Address copied to clipboard'); - }) - .catch((err) => { - console.error('Failed to copy address: ', err); - }); - }; - return ( -
-
+
+
= ({ address }) => { > - +
); }; diff --git a/web-app/src/modules/ui/AddressAvatar/AddressAvatar.tsx b/web-app/src/modules/ui/AddressAvatar/AddressAvatar.tsx index 1514542..da30e4c 100644 --- a/web-app/src/modules/ui/AddressAvatar/AddressAvatar.tsx +++ b/web-app/src/modules/ui/AddressAvatar/AddressAvatar.tsx @@ -16,4 +16,4 @@ const AddressAvatar: React.FC = ({ address }) => { return {address}; }; -export default AddressAvatar; +export default AddressAvatar; \ No newline at end of file diff --git a/web-app/src/modules/ui/CommunityWalletsTable/CommunityWalletRow.tsx b/web-app/src/modules/ui/CommunityWalletsTable/CommunityWalletRow.tsx deleted file mode 100644 index 2329c3a..0000000 --- a/web-app/src/modules/ui/CommunityWalletsTable/CommunityWalletRow.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { gql, useQuery } from '@apollo/client'; -import { FC } from 'react'; -import { ICommunityWalletInfo } from '../../interface/CommunityWallets.interface'; -import AccountAddress from '../AccountAddress'; -import { IAccountInfo } from '../../interface/Account.interface'; -import Money from '../Money'; - -interface Props { - communityWalletInfo: ICommunityWalletInfo; -} - -const GET_ACCOUNT_BALANCE = gql` - query GetAccount($address: Bytes!) { - account(address: $address) { - balance - } - } -`; - -const CommunityWalletRow: FC = ({ communityWalletInfo }) => { - const { data } = useQuery(GET_ACCOUNT_BALANCE, { - variables: { - address: communityWalletInfo.address, - }, - }); - if (!data) { - return null; - } - - return ( - - - - - - {communityWalletInfo.name} - - {communityWalletInfo.description} - - {data.account.balance && {Number(data.account.balance)}} - - - ); -}; - -export default CommunityWalletRow; diff --git a/web-app/src/modules/ui/CommunityWalletsTable/index.ts b/web-app/src/modules/ui/CommunityWalletsTable/index.ts deleted file mode 100644 index fbbaf82..0000000 --- a/web-app/src/modules/ui/CommunityWalletsTable/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './CommunityWalletRow'; diff --git a/web-app/src/modules/ui/CopyButton/CopyButton.tsx b/web-app/src/modules/ui/CopyButton/CopyButton.tsx new file mode 100644 index 0000000..0be210e --- /dev/null +++ b/web-app/src/modules/ui/CopyButton/CopyButton.tsx @@ -0,0 +1,37 @@ +import { useState, FC } from 'react'; +import { CheckIcon } from '@heroicons/react/24/outline'; + +import CopyIcon from '../Icons/CopyIcon'; + +interface Props { + text: string; +} + +const CopyButton: FC = ({ text }) => { + const [isCopied, setIsCopied] = useState(false); + + const onClick = (event: React.MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + + navigator.clipboard + .writeText(text) + .then(() => { + setIsCopied(true); + setTimeout(() => { + setIsCopied(false); + }, 2_000); + }) + .catch((err) => { + console.error('Failed to copy text: ', err); + }); + }; + + return ( + + ); +}; + +export default CopyButton; diff --git a/web-app/src/modules/ui/CopyButton/index.ts b/web-app/src/modules/ui/CopyButton/index.ts new file mode 100644 index 0000000..a58fe32 --- /dev/null +++ b/web-app/src/modules/ui/CopyButton/index.ts @@ -0,0 +1 @@ +export { default } from "./CopyButton"; diff --git a/web-app/src/modules/ui/Icons/CopyIcon.tsx b/web-app/src/modules/ui/Icons/CopyIcon.tsx index ce90560..c66fa20 100644 --- a/web-app/src/modules/ui/Icons/CopyIcon.tsx +++ b/web-app/src/modules/ui/Icons/CopyIcon.tsx @@ -1,5 +1,11 @@ const CopyIcon = () => ( - + { Join our discord @@ -81,12 +82,7 @@ const Footer: React.FC = () => { rel="noopener" aria-label="GitHub" > - + { @@ -50,7 +50,7 @@ const Header: React.FC = () => { return (
-
diff --git a/web-app/src/modules/ui/Page/Page.tsx b/web-app/src/modules/ui/Page/Page.tsx index 6a5848e..412c3f2 100644 --- a/web-app/src/modules/ui/Page/Page.tsx +++ b/web-app/src/modules/ui/Page/Page.tsx @@ -11,7 +11,7 @@ const Page: FC = ({ title, children, __deprecated_grayBg: grayBg }) => { <> {title && (
-
+
{typeof title === 'string' ? (

{title} diff --git a/web-app/src/modules/ui/ToggleButton/ToggleButton.tsx b/web-app/src/modules/ui/ToggleButton/ToggleButton.tsx new file mode 100644 index 0000000..5ed312c --- /dev/null +++ b/web-app/src/modules/ui/ToggleButton/ToggleButton.tsx @@ -0,0 +1,37 @@ +import { FC } from 'react'; +import clsx from 'clsx'; + +interface ToggleOption { + label: string; + value: any; +} + +interface ToggleButtonProps { + options: ToggleOption[]; + activeValue: any; + onToggle: (value: any) => void; +} + +const ToggleButton: FC = ({ options, activeValue, onToggle }) => { + return ( +
+ {options.map((option, index) => ( + + ))} +
+ ); +}; + +export default ToggleButton; diff --git a/web-app/src/modules/ui/ToggleButton/index.ts b/web-app/src/modules/ui/ToggleButton/index.ts new file mode 100644 index 0000000..5061a17 --- /dev/null +++ b/web-app/src/modules/ui/ToggleButton/index.ts @@ -0,0 +1 @@ +export { default } from './ToggleButton';