From a451fe7b6c91e49a6611f770a6ed35ab1d8ddd6b Mon Sep 17 00:00:00 2001 From: Kat Date: Sun, 19 Jan 2025 13:30:14 -0600 Subject: [PATCH] Kat/send tokens (#71) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix cors and requestData errors * redeem mint wallet * add dynamic user info * add FE loading state * add lucid-evolution and wasm compatibility * submit endpoint * update ui to support lucid wallet loading * update lucid * recent changes * handle changes to profile switcher * add get wallet balance func * Fix hash * comment out output export * add send tokens func * add send from user func * add seize function * add alert updates * resolve merge issues * add call to look up blacklist * fix mint recipient and add error alert messages * implement table scroll and updates to alertbar * UI: Fix build * Add ui build to CI * Add recipient * wst-poc-cli: Add -threaded --------- Co-authored-by: colll78 Co-authored-by: Jann Müller --- .github/workflows/ci-ui.yaml | 19 + frontend/.eslintrc.json | 3 +- frontend/package-lock.json | 494 ++++++++++-------- frontend/package.json | 2 +- frontend/src/app/[username]/index.tsx | 95 +++- frontend/src/app/clientLayout.tsx | 21 +- frontend/src/app/components/AlertBar.tsx | 17 +- .../src/app/components/ProfileSwitcher.tsx | 9 +- frontend/src/app/components/WSTTable.tsx | 87 +-- frontend/src/app/mint-authority/page.tsx | 244 +++++++-- frontend/src/app/store/store.tsx | 98 ++-- frontend/src/app/store/types.ts | 14 +- frontend/src/app/styles/globals.css | 5 + frontend/src/app/styles/theme.tsx | 12 +- frontend/src/app/utils/walletUtils.ts | 86 +-- nix/containers.nix | 2 +- src/wst-poc.cabal | 1 + 17 files changed, 779 insertions(+), 430 deletions(-) create mode 100644 .github/workflows/ci-ui.yaml diff --git a/.github/workflows/ci-ui.yaml b/.github/workflows/ci-ui.yaml new file mode 100644 index 0000000..9f1fbe3 --- /dev/null +++ b/.github/workflows/ci-ui.yaml @@ -0,0 +1,19 @@ +name: "ci-ui" +on: + pull_request: + push: + tags: + - "v*" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 23 + - run: | + cd frontend + npm install + npm run export diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index aa93c91..29186a3 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -1,6 +1,7 @@ { "extends": ["next/core-web-vitals", "next/typescript"], "rules": { - "@next/next/no-page-custom-font": "off" + "@next/next/no-page-custom-font": "off", + "@typescript-eslint/no-explicit-any": "off" } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e45d811..f0cac9a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -68,13 +68,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", - "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", + "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.3", - "@babel/types": "^7.26.3", + "@babel/parser": "^7.26.5", + "@babel/types": "^7.26.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -115,12 +115,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", - "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.5.tgz", + "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.3" + "@babel/types": "^7.26.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -156,16 +156,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.26.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", - "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.5.tgz", + "integrity": "sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.3", - "@babel/parser": "^7.26.3", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.5", "@babel/template": "^7.25.9", - "@babel/types": "^7.26.3", + "@babel/types": "^7.26.5", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -174,9 +174,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", - "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz", + "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -524,19 +524,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@eslint/js": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", @@ -1159,9 +1146,9 @@ "license": "MIT" }, "node_modules/@lucid-evolution/lucid": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/@lucid-evolution/lucid/-/lucid-0.4.18.tgz", - "integrity": "sha512-2bu0PIUEdyM+vSgqkvlDpUUAoJFmWpYnsyqJxhkZsBMoJdBH9UINHjuSmPTdmmMNB/IOzP7yyqKZGfCioH2a8A==", + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/@lucid-evolution/lucid/-/lucid-0.4.20.tgz", + "integrity": "sha512-/LGWdg9MLP7trmWlpsIlnCHnUNHRWOo32ntoL9UBYIRr2ahl/8Aoj3+WzmVKRQkT752sWp+AZ1TerNVeu772Zw==", "license": "MIT", "dependencies": { "@anastasia-labs/cardano-multiplatform-lib-browser": "6.0.2-3", @@ -1171,11 +1158,11 @@ "@lucid-evolution/core-types": "0.1.21", "@lucid-evolution/core-utils": "0.1.16", "@lucid-evolution/plutus": "0.1.28", - "@lucid-evolution/provider": "0.1.84", + "@lucid-evolution/provider": "0.1.85", "@lucid-evolution/sign_data": "0.1.24", "@lucid-evolution/uplc": "0.2.18", - "@lucid-evolution/utils": "0.1.62", - "@lucid-evolution/wallet": "0.1.68", + "@lucid-evolution/utils": "0.1.63", + "@lucid-evolution/wallet": "0.1.69", "effect": "^3.10.4" } }, @@ -1205,9 +1192,9 @@ "license": "MIT" }, "node_modules/@lucid-evolution/provider": { - "version": "0.1.84", - "resolved": "https://registry.npmjs.org/@lucid-evolution/provider/-/provider-0.1.84.tgz", - "integrity": "sha512-KDaWE4M5C2FXkQDaI4AzTiYmXhPWrpdHd8VzvTeCaxVWVd94IpxJbS6X1lQEjmKLXT7p3RahGwgUjK4vM3nZ8Q==", + "version": "0.1.85", + "resolved": "https://registry.npmjs.org/@lucid-evolution/provider/-/provider-0.1.85.tgz", + "integrity": "sha512-a4t171fD2OO3SzFvlgjDDE9Npt47Kv6LYd0GkG3cjOM4ba5VZDnhXcfNn8lzidohm0HIFXLQ9Tytz9zDa8dFPw==", "license": "MIT", "dependencies": { "@anastasia-labs/cardano-multiplatform-lib-browser": "6.0.2-3", @@ -1216,8 +1203,8 @@ "@effect/schema": "^0.68.26", "@lucid-evolution/core-types": "0.1.21", "@lucid-evolution/core-utils": "0.1.16", - "@lucid-evolution/utils": "0.1.62", - "@lucid-evolution/wallet": "0.1.68", + "@lucid-evolution/utils": "0.1.63", + "@lucid-evolution/wallet": "0.1.69", "effect": "^3.11.7" } }, @@ -1265,9 +1252,9 @@ "integrity": "sha512-TukA/1XnhrliAfwopPzX04t8j/7dfVygE9F55MypfibA+btZVOLJpe0VAFmr46HMcxecL/S63iOjuiRHNe+5bw==" }, "node_modules/@lucid-evolution/utils": { - "version": "0.1.62", - "resolved": "https://registry.npmjs.org/@lucid-evolution/utils/-/utils-0.1.62.tgz", - "integrity": "sha512-x1K++Hu1WxImMcIHg4MNZ3sQFA0zfqWoi8ptqdGUkzmNRkjA4JmIZnslUJtGo6QC3k5RZbItb3YzpT5QHBpTSA==", + "version": "0.1.63", + "resolved": "https://registry.npmjs.org/@lucid-evolution/utils/-/utils-0.1.63.tgz", + "integrity": "sha512-oxdkIVo0O8/MufSN6d/EsnejDGvg4CNyGwdjzoLiq7MAgmSmz3Bwi2J6aezKCRMkPM12S4II0ZsNx0/EJmmKqA==", "license": "MIT", "dependencies": { "@anastasia-labs/cardano-multiplatform-lib-browser": "6.0.2-3", @@ -1298,9 +1285,9 @@ } }, "node_modules/@lucid-evolution/wallet": { - "version": "0.1.68", - "resolved": "https://registry.npmjs.org/@lucid-evolution/wallet/-/wallet-0.1.68.tgz", - "integrity": "sha512-yd6pkgG6Z9HeCWXbFzzZQhhQgBA6Va1djCWKUoIJJJIXkBCZ2eRsLluTGJnWaslp+MZ6zYXABQbgKuPDYjGxDA==", + "version": "0.1.69", + "resolved": "https://registry.npmjs.org/@lucid-evolution/wallet/-/wallet-0.1.69.tgz", + "integrity": "sha512-CdqgfVmzJkRbj88676PDRj46fcWZhh6IuHSp0LH6On+brRCwAHXEXtHg8X07Cwlk6kYfm/1VxbPO9DIlt/FpFg==", "license": "MIT", "dependencies": { "@anastasia-labs/cardano-multiplatform-lib-browser": "6.0.2-3", @@ -1308,14 +1295,14 @@ "@lucid-evolution/core-types": "0.1.21", "@lucid-evolution/core-utils": "0.1.16", "@lucid-evolution/sign_data": "0.1.24", - "@lucid-evolution/utils": "0.1.62", + "@lucid-evolution/utils": "0.1.63", "bip39": "^3.1.0" } }, "node_modules/@mui/core-downloads-tracker": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.3.1.tgz", - "integrity": "sha512-2OmnEyoHpj5//dJJpMuxOeLItCCHdf99pjMFfUFdBteCunAK9jW+PwEo4mtdGcLs7P+IgZ+85ypd52eY4AigoQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.0.tgz", + "integrity": "sha512-6u74wi+9zeNlukrCtYYET8Ed/n9AS27DiaXCZKAD3TRGFaqiyYSsQgN2disW83pI/cM1Q2lJY1JX4YfwvNtlNw==", "license": "MIT", "funding": { "type": "opencollective", @@ -1323,9 +1310,9 @@ } }, "node_modules/@mui/icons-material": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.3.1.tgz", - "integrity": "sha512-nJmWj1PBlwS3t1PnoqcixIsftE+7xrW3Su7f0yrjPw4tVjYrgkhU0hrRp+OlURfZ3ptdSkoBkalee9Bhf1Erfw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.4.0.tgz", + "integrity": "sha512-zF0Vqt8a+Zp2Oz8P+WvJflba6lLe3PhxIz1NNqn+n4A+wKLPbkeqY8ShmKjPyiCTg0RMbPrp993oUDl9xGsDlQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0" @@ -1338,7 +1325,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^6.3.1", + "@mui/material": "^6.4.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -1349,16 +1336,16 @@ } }, "node_modules/@mui/material": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.3.1.tgz", - "integrity": "sha512-ynG9ayhxgCsHJ/dtDcT1v78/r2GwQyP3E0hPz3GdPRl0uFJz/uUTtI5KFYwadXmbC+Uv3bfB8laZ6+Cpzh03gA==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.4.0.tgz", + "integrity": "sha512-hNIgwdM9U3DNmowZ8mU59oFmWoDKjc92FqQnQva3Pxh6xRKWtD2Ej7POUHMX8Dwr1OpcSUlT2+tEMeLb7WYsIg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/core-downloads-tracker": "^6.3.1", - "@mui/system": "^6.3.1", + "@mui/core-downloads-tracker": "^6.4.0", + "@mui/system": "^6.4.0", "@mui/types": "^7.2.21", - "@mui/utils": "^6.3.1", + "@mui/utils": "^6.4.0", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", @@ -1377,7 +1364,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^6.3.1", + "@mui/material-pigment-css": "^6.4.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -1433,13 +1420,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.3.1.tgz", - "integrity": "sha512-g0u7hIUkmXmmrmmf5gdDYv9zdAig0KoxhIQn1JN8IVqApzf/AyRhH3uDGx5mSvs8+a1zb4+0W6LC260SyTTtdQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.0.tgz", + "integrity": "sha512-rNHci8MP6NOdEWAfZ/RBMO5Rhtp1T6fUDMSmingg9F1T6wiUeodIQ+NuTHh2/pMoUSeP9GdHdgMhMmfsXxOMuw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/utils": "^6.3.1", + "@mui/utils": "^6.4.0", "prop-types": "^15.8.1" }, "engines": { @@ -1460,9 +1447,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.3.1.tgz", - "integrity": "sha512-/7CC0d2fIeiUxN5kCCwYu4AWUDd9cCTxWCyo0v/Rnv6s8uk6hWgJC3VLZBoDENBHf/KjqDZuYJ2CR+7hD6QYww==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.0.tgz", + "integrity": "sha512-ek/ZrDujrger12P6o4luQIfRd2IziH7jQod2WMbLqGE03Iy0zUwYmckRTVhRQTLPNccpD8KXGcALJF+uaUQlbg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", @@ -1494,16 +1481,16 @@ } }, "node_modules/@mui/system": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.3.1.tgz", - "integrity": "sha512-AwqQ3EAIT2np85ki+N15fF0lFXX1iFPqenCzVOSl3QXKy2eifZeGd9dGtt7pGMoFw5dzW4dRGGzRpLAq9rkl7A==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.0.tgz", + "integrity": "sha512-wTDyfRlaZCo2sW2IuOsrjeE5dl0Usrs6J7DxE3GwNCVFqS5wMplM2YeNiV3DO7s53RfCqbho+gJY6xaB9KThUA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/private-theming": "^6.3.1", - "@mui/styled-engine": "^6.3.1", + "@mui/private-theming": "^6.4.0", + "@mui/styled-engine": "^6.4.0", "@mui/types": "^7.2.21", - "@mui/utils": "^6.3.1", + "@mui/utils": "^6.4.0", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1548,9 +1535,9 @@ } }, "node_modules/@mui/utils": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.3.1.tgz", - "integrity": "sha512-sjGjXAngoio6lniQZKJ5zGfjm+LD2wvLwco7FbKe1fu8A7VIFmz2SwkLb+MDPLNX1lE7IscvNNyh1pobtZg2tw==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.0.tgz", + "integrity": "sha512-woOTATWNsTNR3YBh2Ixkj3l5RaxSiGoC9G8gOpYoFw1mZM77LWJeuMHFax7iIW4ahK0Cr35TF9DKtrafJmOmNQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.26.0", @@ -1593,36 +1580,6 @@ "fast-glob": "3.3.1" } }, - "node_modules/@next/eslint-plugin-next/node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/@next/eslint-plugin-next/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/@next/swc-darwin-arm64": { "version": "15.1.4", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.4.tgz", @@ -1864,9 +1821,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.17.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.12.tgz", - "integrity": "sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==", + "version": "20.17.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.14.tgz", + "integrity": "sha512-w6qdYetNL5KRBiSClK/KWai+2IMEJuAj+EujKCumalFOwXtvOXaEan9AuwcRID2IcOIAWSIfR495hBtgKlx2zg==", "dev": true, "license": "MIT", "dependencies": { @@ -1915,17 +1872,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz", - "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.20.0.tgz", + "integrity": "sha512-naduuphVw5StFfqp4Gq4WhIBE2gN1GEmMUExpJYknZJdRnc+2gDzB8Z3+5+/Kv33hPQRDGzQO/0opHE72lZZ6A==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.19.1", - "@typescript-eslint/type-utils": "8.19.1", - "@typescript-eslint/utils": "8.19.1", - "@typescript-eslint/visitor-keys": "8.19.1", + "@typescript-eslint/scope-manager": "8.20.0", + "@typescript-eslint/type-utils": "8.20.0", + "@typescript-eslint/utils": "8.20.0", + "@typescript-eslint/visitor-keys": "8.20.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1945,16 +1902,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz", - "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.20.0.tgz", + "integrity": "sha512-gKXG7A5HMyjDIedBi6bUrDcun8GIjnI8qOwVLiY3rx6T/sHP/19XLJOnIq/FgQvWLHja5JN/LSE7eklNBr612g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.19.1", - "@typescript-eslint/types": "8.19.1", - "@typescript-eslint/typescript-estree": "8.19.1", - "@typescript-eslint/visitor-keys": "8.19.1", + "@typescript-eslint/scope-manager": "8.20.0", + "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/typescript-estree": "8.20.0", + "@typescript-eslint/visitor-keys": "8.20.0", "debug": "^4.3.4" }, "engines": { @@ -1970,14 +1927,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", - "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.20.0.tgz", + "integrity": "sha512-J7+VkpeGzhOt3FeG1+SzhiMj9NzGD/M6KoGn9f4dbz3YzK9hvbhVTmLj/HiTp9DazIzJ8B4XcM80LrR9Dm1rJw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.19.1", - "@typescript-eslint/visitor-keys": "8.19.1" + "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/visitor-keys": "8.20.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1988,14 +1945,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz", - "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.20.0.tgz", + "integrity": "sha512-bPC+j71GGvA7rVNAHAtOjbVXbLN5PkwqMvy1cwGeaxUoRQXVuKCebRoLzm+IPW/NtFFpstn1ummSIasD5t60GA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.19.1", - "@typescript-eslint/utils": "8.19.1", + "@typescript-eslint/typescript-estree": "8.20.0", + "@typescript-eslint/utils": "8.20.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.0" }, @@ -2012,9 +1969,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", - "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.20.0.tgz", + "integrity": "sha512-cqaMiY72CkP+2xZRrFt3ExRBu0WmVitN/rYPZErA80mHjHx/Svgp8yfbzkJmDoQ/whcytOPO9/IZXnOc+wigRA==", "dev": true, "license": "MIT", "engines": { @@ -2026,14 +1983,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", - "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.20.0.tgz", + "integrity": "sha512-Y7ncuy78bJqHI35NwzWol8E0X7XkRVS4K4P4TCyzWkOJih5NDvtoRDW4Ba9YJJoB2igm9yXDdYI/+fkiiAxPzA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.19.1", - "@typescript-eslint/visitor-keys": "8.19.1", + "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/visitor-keys": "8.20.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -2062,6 +2019,36 @@ "balanced-match": "^1.0.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -2079,16 +2066,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz", - "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.20.0.tgz", + "integrity": "sha512-dq70RUw6UK9ei7vxc4KQtBRk7qkHZv447OUZ6RPQMQl71I3NZxQJX/f32Smr+iqWrB02pHKn2yAdHBb0KNrRMA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.19.1", - "@typescript-eslint/types": "8.19.1", - "@typescript-eslint/typescript-estree": "8.19.1" + "@typescript-eslint/scope-manager": "8.20.0", + "@typescript-eslint/types": "8.20.0", + "@typescript-eslint/typescript-estree": "8.20.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2103,13 +2090,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", - "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.20.0.tgz", + "integrity": "sha512-v/BpkeeYAsPkKCkR8BDwcno0llhzWVqPOamQrAEMdpZav2Y9OVjd9dwJyBLJWwf335B5DmlifECIkZRJCaGaHA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/types": "8.20.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2462,19 +2449,6 @@ "postcss": "^8.1.0" } }, - "node_modules/autoprefixer/node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -3388,18 +3362,18 @@ } }, "node_modules/effect": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.12.1.tgz", - "integrity": "sha512-aAZdh56Yp1ehOFYeMcHHctTtxfqm6kkOdZFTXK6Zf0QoaKKc1hPG6ocjrKOc0axE8JbG4eZw351ogNLrM4vo9w==", + "version": "3.12.4", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.12.4.tgz", + "integrity": "sha512-kPNCGhkuk/WQrO5wRA0FPEI84aG329ciOi5LEsmgxaPgnwJdtK/LeaWIiqKcAvcBEeuFbWLgvWi6l9BN2Jg7Gw==", "license": "MIT", "dependencies": { "fast-check": "^3.23.1" } }, "node_modules/electron-to-chromium": { - "version": "1.5.80", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.80.tgz", - "integrity": "sha512-LTrKpW0AqIuHwmlVNV+cjFYTnXtM9K37OGhpe0ZI10ScPSxqVSryZHIY3WnCS5NSYbBODRTZyhRMS2h5FAEqAw==", + "version": "1.5.83", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.83.tgz", + "integrity": "sha512-LcUDPqSt+V0QmI47XLzZrz5OqILSMGsPFkDYus22rIbgorSvBYEFqq854ltTmUdHkY92FSdAAvsh4jWEULMdfQ==", "license": "ISC" }, "node_modules/elliptic": { @@ -3570,9 +3544,9 @@ } }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", "dependencies": { @@ -3790,6 +3764,36 @@ } } }, + "node_modules/eslint-import-resolver-typescript/node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/eslint-module-utils": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", @@ -3916,9 +3920,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.37.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.3.tgz", - "integrity": "sha512-DomWuTQPFYZwF/7c9W2fkKkStqZmBd3uugfqBYLdkZ3Hii23WzZuOLUskGxB8qkSKqftxEeGL1TB2kMhrce0jA==", + "version": "7.37.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz", + "integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4048,19 +4052,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -4186,9 +4177,9 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "license": "MIT", "dependencies": { @@ -4196,7 +4187,7 @@ "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.8" + "micromatch": "^4.0.4" }, "engines": { "node": ">=8.6.0" @@ -4360,6 +4351,19 @@ "node": ">= 6" } }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -4477,6 +4481,28 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -5608,6 +5634,34 @@ } } }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/node-gyp-build-optional-packages": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz", @@ -5984,9 +6038,9 @@ } }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", + "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", "funding": [ { "type": "opencollective", @@ -6002,10 +6056,11 @@ } ], "license": "MIT", + "peer": true, "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -6338,28 +6393,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -7105,6 +7138,19 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index 8b7503d..d6e44a6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -42,4 +42,4 @@ "tsconfig-paths-webpack-plugin": "^4.2.0", "typescript": "^5" } -} +} \ No newline at end of file diff --git a/frontend/src/app/[username]/index.tsx b/frontend/src/app/[username]/index.tsx index a3d77b5..c350663 100644 --- a/frontend/src/app/[username]/index.tsx +++ b/frontend/src/app/[username]/index.tsx @@ -1,49 +1,112 @@ 'use client'; - //React imports -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; + +//Axios imports +import axios from 'axios'; //Mui imports import { Box, Typography } from '@mui/material'; //Local components import useStore from '../store/store'; +import { Accounts } from '../store/types'; +import { getWalletBalance, signAndSentTx } from '../utils/walletUtils'; import WalletCard from '../components/Card'; import WSTTextField from '../components/WSTTextField'; import CopyTextField from '../components/CopyTextField'; export default function Profile() { - const { currentUser, userA, userB, walletUser, setAlertStatus } = useStore(); + const { lucid, currentUser, mintAccount, changeAlertInfo, changeWalletAccountDetails } = useStore(); + const accounts = useStore((state) => state.accounts); + + useEffect(() => { + useStore.getState(); + // console.log("accounts changed:", accounts); + }, [accounts]); const getUserAccountDetails = () => { switch (currentUser) { - case "User A": return userA; - case "User B": return userB; - case "Connected Wallet": return walletUser; + case "User A": return accounts.userA; + case "User B": return accounts.userB; + case "Connected Wallet": return accounts.walletUser; }; }; // temp state for each text field - const [mintTokens, setMintTokens] = useState(0); - const [recipientAddress, setRecipientAddress] = useState('address'); + const [sendTokenAmount, setMintTokens] = useState(0); + const [sendRecipientAddress, setsendRecipientAddress] = useState('address'); + + const onSend = async () => { + if (getUserAccountDetails()?.status === 'Frozen') { + changeAlertInfo({ + severity: 'error', + message: 'Cannot send WST with frozen account.', + open: true, + }); + return; + } + console.log('start sending tokens'); + changeAlertInfo({severity: 'info', message: 'Transaction processing', open: true,}); + const accountInfo = getUserAccountDetails(); + if (!accountInfo) { + console.error("No valid send account found! Cannot send."); + return; + } + lucid.selectWallet.fromSeed(accountInfo.mnemonic); + const requestData = { + asset_name: Buffer.from('WST', 'utf8').toString('hex'), // Convert "WST" to hex + issuer: mintAccount.address, + quantity: sendTokenAmount, + recipient: sendRecipientAddress, + sender: accountInfo.address, + }; + try { + const response = await axios.post( + '/api/v1/tx/programmable-token/transfer', + requestData, + { + headers: { + 'Content-Type': 'application/json;charset=utf-8', + }, + } + ); + console.log('Send response:', response.data); + const tx = await lucid.fromTx(response.data.cborHex); + await signAndSentTx(lucid, tx); + await updateAccountBalance(sendRecipientAddress); + await updateAccountBalance(accountInfo.address); + changeAlertInfo({severity: 'success', message: 'Transaction sent successfully!', open: true,}); + } catch (error) { + console.error('Send failed:', error); + } + }; - const onSend = () => { - console.log('send tokens'); - setAlertStatus(true); + const updateAccountBalance = async (address: string) => { + const newAccountBalance = await getWalletBalance(address); + const walletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( + (key) => accounts[key].address === address + ); + if (walletKey) { + changeWalletAccountDetails(walletKey, { + ...accounts[walletKey], + balance: newAccountBalance, + }); + } }; const sendContent = setMintTokens(Number(e.target.value))} label="Number of Tokens to Send" fullWidth={true} /> setRecipientAddress(e.target.value)} + value={sendRecipientAddress} + onChange={(e) => setsendRecipientAddress(e.target.value)} label="Recipient’s Address" fullWidth={true} /> @@ -51,7 +114,7 @@ export default function Profile() { const receiveContent = @@ -82,4 +145,4 @@ export default function Profile() { ); -} +} \ No newline at end of file diff --git a/frontend/src/app/clientLayout.tsx b/frontend/src/app/clientLayout.tsx index 193f4b9..4a0f482 100644 --- a/frontend/src/app/clientLayout.tsx +++ b/frontend/src/app/clientLayout.tsx @@ -9,26 +9,26 @@ import NavDrawer from './components/NavDrawer'; //Local file import { ThemeModeProvider } from "./styles/themeContext"; import "./styles/globals.css"; -import { makeLucid, getWalletFromSeed, getWalletBalance } from "./utils/walletUtils"; +import { makeLucid, getWalletFromSeed } from "./utils/walletUtils"; import useStore from './store/store'; import WSTAppBar from "./components/WSTAppBar"; +import AlertBar from './components/AlertBar'; export default function ClientLayout({ children }: { children: React.ReactNode }) { - const { mintAccount, userA, userB, changeMintAccountDetails, changeWalletAAccountDetails, changeWalletBAccountDetails, setLucidInstance } = useStore(); + const { mintAccount, accounts, changeMintAccountDetails, changeWalletAccountDetails, setLucidInstance } = useStore(); useEffect(() => { const fetchUserWallets = async () => { try { // retrieve wallet info const mintAuthorityWallet = await getWalletFromSeed(mintAccount.mnemonic); - const walletA = await getWalletFromSeed(userA.mnemonic); - const walletB = await getWalletFromSeed(userB.mnemonic); + const walletA = await getWalletFromSeed(accounts.userA.mnemonic); + const walletB = await getWalletFromSeed(accounts.userB.mnemonic); - const mintStartBalance = await getWalletBalance(mintAuthorityWallet.address); // Update Zustand store with the initialized wallet information - changeMintAccountDetails({ ...mintAccount, address: mintAuthorityWallet.address, balance: mintStartBalance}); - changeWalletAAccountDetails({ ...userA, address: walletA.address}); - changeWalletBAccountDetails({ ...userB, address: walletB.address,}); + changeMintAccountDetails({ ...mintAccount, address: mintAuthorityWallet.address}); + changeWalletAccountDetails('userA', { ...accounts.userA, address: walletA.address},); + changeWalletAccountDetails('userB', { ...accounts.userB, address: walletB.address}); const initialLucid = await makeLucid(); setLucidInstance(initialLucid); @@ -39,9 +39,9 @@ export default function ClientLayout({ children }: { children: React.ReactNode } }; fetchUserWallets(); - }, []); + },[]); - if(userB.address === '') { + if(accounts.userB.address === '') { return
; @@ -54,6 +54,7 @@ export default function ClientLayout({ children }: { children: React.ReactNode }
{children}
+ diff --git a/frontend/src/app/components/AlertBar.tsx b/frontend/src/app/components/AlertBar.tsx index dcd8e5d..a2588f3 100644 --- a/frontend/src/app/components/AlertBar.tsx +++ b/frontend/src/app/components/AlertBar.tsx @@ -8,27 +8,22 @@ import Alert from '@mui/material/Alert'; //Local components import useStore from '../store/store'; -interface AlertBarProps { - severity?: 'success' | 'error' | 'info' | 'warning'; - message: string; -} - -export default function AlertBar({severity = 'success', message}: AlertBarProps) { -const { alertOpen, setAlertStatus } = useStore(); +export default function AlertBar() { +const { alertInfo, changeAlertInfo } = useStore(); const handleClose = () => { - setAlertStatus(false); + changeAlertInfo({ ...alertInfo, open: false }); }; return ( - + - {message} + {alertInfo.message} ); diff --git a/frontend/src/app/components/ProfileSwitcher.tsx b/frontend/src/app/components/ProfileSwitcher.tsx index 0a3b9ac..c1823b9 100644 --- a/frontend/src/app/components/ProfileSwitcher.tsx +++ b/frontend/src/app/components/ProfileSwitcher.tsx @@ -1,3 +1,4 @@ + 'use client' //React Imports import * as React from 'react'; @@ -18,9 +19,7 @@ import { selectLucidWallet, getWalletBalance } from '../utils/walletUtils'; export default function ProfileSwitcher() { const [anchorEl, setAnchorEl] = React.useState(null); - const currentUser = useStore(state => state.currentUser); - const walletUser = useStore(state => state.walletUser); - const changeToLaceWallet = useStore(state => state.changeToLaceWallet); + const { currentUser, accounts, changeWalletAccountDetails } = useStore(); const lucid = useStore(state => state.lucid); const changeUserAccount = useStore(state => state.changeUserAccount); const router = useRouter(); @@ -64,8 +63,8 @@ export default function ProfileSwitcher() { await selectLucidWallet(lucid, "Lace"); const userAddress = await lucid.wallet().address(); const userBalance = await getWalletBalance(userAddress); - changeToLaceWallet({ - ...walletUser, + changeWalletAccountDetails('walletUser', { + ...accounts.walletUser, address: userAddress, balance: userBalance, }); diff --git a/frontend/src/app/components/WSTTable.tsx b/frontend/src/app/components/WSTTable.tsx index 5b86250..018fc28 100644 --- a/frontend/src/app/components/WSTTable.tsx +++ b/frontend/src/app/components/WSTTable.tsx @@ -1,4 +1,10 @@ +'use client' +//Lucid imports +import type { Address, Credential as LucidCredential, Unit, UTxO } from "@lucid-evolution/core-types"; +import { toUnit } from "@lucid-evolution/lucid"; + //Mui imports +import { Box } from "@mui/material"; import TableContainer from "@mui/material/TableContainer"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; @@ -9,11 +15,37 @@ import Paper from "@mui/material/Paper"; //Local Imports import useStore from '../store/store'; +import { useEffect } from "react"; + +const progLogicBase : LucidCredential = { + type: "Script", + hash: "fca77bcce1e5e73c97a0bfa8c90f7cd2faff6fd6ed5b6fec1c04eefa" +} + +const stableCoin : Unit = toUnit("b34a184f1f2871aa4d33544caecefef5242025f45c3fa5213d7662a9", "575354") + export default function WSTTable() { - const { userA, userB, walletUser } = useStore(); + const { lucid, accounts } = useStore(); + const accountArray = Object.values(accounts); + + const getAccounts = async () => { + const progUTxOs : UTxO[] = await lucid.utxosAtWithUnit(progLogicBase, stableCoin); + const addresses = new Set(); + const valueMap = new Map(); + progUTxOs.forEach(utxo => { + addresses.add(utxo.address) + valueMap.set(utxo.address, Number(utxo.assets[stableCoin])) + }); + } + + useEffect(() => { + getAccounts(); + }, []); + return ( + @@ -24,44 +56,35 @@ export default function WSTTable() { - - - {userA?.address.slice(0,15)} - - - {userA?.status} - - - {`${userA?.balance} WST`} - - - - - {userB?.address.slice(0,15)} - - - {userB?.status} - - - {`${userB?.balance} WST`} - - - { - walletUser.address && - + { + accountArray.filter((acct) => acct.address !== "").map((acct, i) => ( + - {walletUser?.address.slice(0,15)} + {`${acct?.address.slice(0,15)}...${acct?.address.slice(104,108)}`} + + + {acct.status} - - {walletUser?.status} + + {`${acct?.balance} WST`} + + + )) + } + {/* {[...uniqueAddresses].map((address, index) => ( + + {`${address.slice(0,15)}...${address.slice(104,108)}`} + + Active - {`${walletUser?.balance} WST`} + {`${balanceMap.get(address)} WST`} - } + ))} */}
+
); -} \ No newline at end of file +} diff --git a/frontend/src/app/mint-authority/page.tsx b/frontend/src/app/mint-authority/page.tsx index 065855c..20e3136 100644 --- a/frontend/src/app/mint-authority/page.tsx +++ b/frontend/src/app/mint-authority/page.tsx @@ -1,45 +1,96 @@ 'use client'; //React imports -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; //Axios imports import axios from 'axios'; +//Lucid imports +import { CML, makeTxSignBuilder, paymentCredentialOf } from '@lucid-evolution/lucid'; +import type { Credential as LucidCredential } from "@lucid-evolution/core-types"; + //Mui imports import { Box, Typography } from '@mui/material'; import Checkbox from '@mui/material/Checkbox'; import FormControlLabel from '@mui/material/FormControlLabel'; -//Lucid imports -import { CML, makeTxSignBuilder } from "@lucid-evolution/lucid"; - //Local components import useStore from '../store/store'; +import { Accounts } from '../store/types'; import WalletCard from '../components/Card'; import WSTTextField from '../components/WSTTextField'; import CopyTextField from '../components/CopyTextField'; import WSTTable from '../components/WSTTable'; -import AlertBar from '../components/AlertBar'; -import { adjustMintOutput, deriveProgrammableAddress } from '../utils/walletUtils'; +import { getWalletBalance, signAndSentTx, getBlacklist } from '../utils/walletUtils'; + + export default function Home() { - const { lucid, mintAccount, selectedTab, errorMessage, setAlertStatus } = useStore(); + const { lucid, mintAccount, accounts, selectedTab, changeAlertInfo, changeMintAccountDetails, changeWalletAccountDetails } = useStore(); const [addressCleared, setAddressCleared] = useState(false); // Temporary state for each text field - const [mintTokens, setMintTokens] = useState(36); - const [recipientAddress, setRecipientAddress] = useState('addr_test1qpynxme7c0tcmmvgk2tjuv63aw7zk9tk6yqkaqd48ulhkyl5f6v47dp5rc7286z5f57339d0c79khw4y3lwxzm8ywkzsvudp69'); - const [accountNumber, setAccountNumber] = useState('addr_test1qpynxme7c0tcmmvgk2tjuv63aw7zk9tk6yqkaqd48ulhkyl5f6v47dp5rc7286z5f57339d0c79khw4y3lwxzm8ywkzsvudp69'); - const [reason, setReason] = useState('Enter reason here'); + const [mintTokensAmount, setMintTokens] = useState(0); + const [sendTokensAmount, setSendTokens] = useState(0); + const [mintRecipientAddress, setMintRecipientAddress] = useState('mint recipient address'); + const [sendRecipientAddress, setsendRecipientAddress] = useState('send recipient address'); + const [freezeAccountNumber, setFreezeAccountNumber] = useState('account to freeze'); + const [freezeReason, setFreezeReason] = useState('Enter reason here'); + const [seizeAccountNumber, setSeizeAccountNumber] = useState('account to seize'); + const [seizeReason, setSeizeReason] = useState('Enter reason here'); + + useEffect(() => { + const initialize = async () => { + await fetchUserDetails(); + await fetchBlacklistStatus(); + }; + initialize(); + }, []); + + const fetchUserDetails = async () => { + const mintBalance = await getWalletBalance(mintAccount.address); + const userABalance = await getWalletBalance(accounts.userA.address); + const userBBalance = await getWalletBalance(accounts.userB.address); + + // Update Zustand store with the initialized wallet information + await changeMintAccountDetails({ ...mintAccount, balance: mintBalance}); + await changeWalletAccountDetails('userA', { ...accounts.userA, balance: userABalance}); + await changeWalletAccountDetails('userB', { ...accounts.userB, balance: userBBalance}); + }; + + const fetchBlacklistStatus = async () => { + const blacklist = await getBlacklist(); + const { accounts, changeWalletAccountDetails } = useStore.getState(); + + Object.entries(accounts).map(async ([key, account]) => { + if (!account.address || account.address.trim() === "") { + // console.log(`${key} has no address yet, skipping`); + return; + } + const credential : LucidCredential = await paymentCredentialOf(account.address); + if(blacklist.includes(credential.hash)) { + // console.log('a match was found', key as keyof typeof accounts); + changeWalletAccountDetails(key as keyof typeof accounts, { ...account, status: 'Frozen',}); + } + }); + }; const handleAddressClearedChange = (event: { target: { checked: boolean | ((prevState: boolean) => boolean); }; }) => { setAddressCleared(event.target.checked); }; const onMint = async () => { + if (addressCleared === false) { + // setAlertStatus(true); + console.error("Recipient Address not cleared."); + return; + } + changeAlertInfo({severity: 'info', message: 'Processing Mint Request', open: true,}); + lucid.selectWallet.fromSeed(mintAccount.mnemonic); const requestData = { asset_name: Buffer.from('WST', 'utf8').toString('hex'), // Convert "WST" to hex issuer: mintAccount.address, - quantity: mintTokens, + quantity: mintTokensAmount, + recipient: mintRecipientAddress }; try { @@ -52,17 +103,17 @@ export default function Home() { }, } ); - lucid.selectWallet.fromSeed(mintAccount.mnemonic); console.log('Mint response:', response.data); const tx = await lucid.fromTx(response.data.cborHex); + // await signAndSentTx(lucid, tx); const txBuilder = await makeTxSignBuilder(lucid.wallet(), tx.toTransaction()).complete(); - const cmlTxInternal = txBuilder.toTransaction() - console.log("TxBody: " + cmlTxInternal.body().to_json()); - const cmlTx = adjustMintOutput(cmlTxInternal, (await deriveProgrammableAddress(lucid, recipientAddress)), BigInt(mintTokens)) + const cmlTx = txBuilder.toTransaction() + console.log("TxBody: " + cmlTx.body().to_json()); const witnessSet = txBuilder.toTransaction().witness_set(); const expectedScriptDataHash : CML.ScriptDataHash | undefined = CML.calc_script_data_hash(witnessSet.redeemers()!, CML.PlutusDataList.new(), lucid.config().costModels!, witnessSet.languages()); console.log('Calculated Script Data Hash:', expectedScriptDataHash?.to_hex()); const cmlTxBodyClone = CML.TransactionBody.from_cbor_hex(cmlTx!.body().to_cbor_hex()); + console.log("TxBody: " + cmlTxBodyClone.to_json()); console.log('Preclone script hash:', cmlTxBodyClone.script_data_hash()?.to_hex()); cmlTxBodyClone.set_script_data_hash(expectedScriptDataHash!); console.log('Postclone script hash:', cmlTxBodyClone.script_data_hash()?.to_hex()); @@ -71,35 +122,149 @@ export default function Home() { const txId = await cmlClonedSignedTx.submit(); await lucid.awaitTx(txId); + + changeAlertInfo({severity: 'success', message: 'Successful new WST mint', open: true,}); + await fetchUserDetails(); } catch (error) { console.error('Minting failed:', error); } }; - const onFreeze = () => { - console.log('freeze an account'); + const onSend = async () => { + lucid.selectWallet.fromSeed(mintAccount.mnemonic); + console.log('send tokens'); + changeAlertInfo({severity: 'info', message: 'Transaction processing', open: true,}); + const requestData = { + asset_name: Buffer.from('WST', 'utf8').toString('hex'), // Convert "WST" to hex + issuer: mintAccount.address, + quantity: sendTokensAmount, + recipient: sendRecipientAddress, + sender: mintAccount.address, + }; + try { + const response = await axios.post( + '/api/v1/tx/programmable-token/transfer', + requestData, + { + headers: { + 'Content-Type': 'application/json;charset=utf-8', + }, + } + ); + console.log('Send response:', response.data); + const tx = await lucid.fromTx(response.data.cborHex); + await signAndSentTx(lucid, tx); + const newAccountBalance = await getWalletBalance(sendRecipientAddress); + const recipientWalletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( + (key) => accounts[key].address === sendRecipientAddress + ); + if (recipientWalletKey) { + changeWalletAccountDetails(recipientWalletKey, { + ...accounts[recipientWalletKey], + balance: newAccountBalance, + }); + } + changeAlertInfo({severity: 'success', message: 'Transaction sent successfully!', open: true,}); + await fetchUserDetails(); + } catch (error) { + console.error('Send failed:', error); + } }; - const onSeize = () => { + const onFreeze = async () => { console.log('freeze an account'); + lucid.selectWallet.fromSeed(mintAccount.mnemonic); + changeAlertInfo({severity: 'info', message: 'Freeze request processing', open: true,}); + const requestData = { + issuer: mintAccount.address, + blacklist_address: freezeAccountNumber, + }; + try { + const response = await axios.post( + '/api/v1/tx/programmable-token/blacklist', + requestData, + { + headers: { + 'Content-Type': 'application/json;charset=utf-8', + }, + } + ); + console.log('Freeze response:', response.data); + const tx = await lucid.fromTx(response.data.cborHex); + await signAndSentTx(lucid, tx); + changeAlertInfo({severity: 'success', message: 'Account successfully frozen', open: true,}); + const frozenWalletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( + (key) => accounts[key].address === freezeAccountNumber + ); + if (frozenWalletKey) { + changeWalletAccountDetails(frozenWalletKey, { + ...accounts[frozenWalletKey], + status: 'Frozen', + }); + } + } catch (error: any) { + if (error.response.data.includes('DuplicateBlacklistNode')) { + changeAlertInfo({ + severity: 'error', + message: 'This account is already frozen.', + open: true, + }); + return; + } else { + console.error('Freeze failed:', error); + } + } }; - const onSend = () => { - console.log('send tokens'); - setAlertStatus(true); + const onSeize = async () => { + console.log('seize account funds'); + lucid.selectWallet.fromSeed(mintAccount.mnemonic); + changeAlertInfo({severity: 'info', message: 'WST seizure processing', open: true,}); + const requestData = { + issuer: mintAccount.address, + target: seizeAccountNumber, + }; + try { + const response = await axios.post( + '/api/v1/tx/programmable-token/seize', + requestData, + { + headers: { + 'Content-Type': 'application/json;charset=utf-8', + }, + } + ); + console.log('Seize response:', response.data); + const tx = await lucid.fromTx(response.data.cborHex); + await signAndSentTx(lucid, tx); + const newAccountBalance = await getWalletBalance(seizeAccountNumber); + const seizeWalletKey = (Object.keys(accounts) as (keyof Accounts)[]).find( + (key) => accounts[key].address === seizeAccountNumber + ); + if (seizeWalletKey) { + changeWalletAccountDetails(seizeWalletKey, { + ...accounts[seizeWalletKey], + balance: newAccountBalance, + }); + } + changeAlertInfo({severity: 'success', message: 'Funds successfully seized', open: true,}); + await fetchUserDetails(); + } catch (error) { + console.error('Seize failed:', error); + } }; const mintContent = setMintTokens(Number(e.target.value))} label="Number of Tokens to Mint" fullWidth={true} /> setRecipientAddress(e.target.value)} - label="Recipient’s Address" + value={mintRecipientAddress} + onChange={(e) => setMintRecipientAddress(e.target.value)} + label="Mint Recipient’s Address" fullWidth={true} /> setAccountNumber(e.target.value)} + value={freezeAccountNumber} + onChange={(e) => setFreezeAccountNumber(e.target.value)} label="Account Number" fullWidth={true} /> setReason(e.target.value)} + value={freezeReason} + onChange={(e) => setFreezeReason(e.target.value)} label="Reason" fullWidth={true} multiline={true} @@ -129,14 +294,14 @@ export default function Home() { const seizeContent = setAccountNumber(e.target.value)} +value={seizeAccountNumber} +onChange={(e) => setSeizeAccountNumber(e.target.value)} label="Account Number" fullWidth={true} /> setReason(e.target.value)} +value={seizeReason} +onChange={(e) => setSeizeReason(e.target.value)} label="Reason" fullWidth={true} multiline={true} @@ -147,14 +312,14 @@ maxRows={3} const sendContent = setMintTokens(Number(e.target.value))} + value={sendTokensAmount} + onChange={(e) => setSendTokens(Number(e.target.value))} label="Number of Tokens to Send" fullWidth={true} /> setRecipientAddress(e.target.value)} + value={sendRecipientAddress} + onChange={(e) => setsendRecipientAddress(e.target.value)} label="Recipient’s Address" fullWidth={true} /> @@ -227,7 +392,8 @@ maxRows={3} return (
{getContentComponent()} -
); } + + diff --git a/frontend/src/app/store/store.tsx b/frontend/src/app/store/store.tsx index 2624054..2da39f2 100644 --- a/frontend/src/app/store/store.tsx +++ b/frontend/src/app/store/store.tsx @@ -2,61 +2,63 @@ import { create } from "zustand"; //Local Imports -import { UserName, AccountInfo, MenuTab } from "./types"; +import { UserName, AccountInfo, Accounts, MenuTab, AccountKey, AlertInfo } from "./types"; import { LucidEvolution } from "@lucid-evolution/lucid"; export type State = { mintAccount: AccountInfo; - userA: AccountInfo; - userB: AccountInfo; - walletUser: AccountInfo; + accounts: Accounts; + blacklistAddresses: string[]; currentUser: UserName; selectedTab: MenuTab; - alertOpen: boolean; - errorMessage: boolean; + alertInfo: AlertInfo; lucid: LucidEvolution; }; export type Actions = { changeMintAccountDetails: (newAccountInfo: AccountInfo) => void; - changeWalletAAccountDetails: (newAccountInfo: AccountInfo) => void; - changeWalletBAccountDetails: (newAccountInfo: AccountInfo) => void; - changeToLaceWallet: (newAccountInfo: AccountInfo) => void; + changeWalletAccountDetails: (accountKey: AccountKey, newAccountInfo: AccountInfo) => void; changeUserAccount: (newUser: UserName) => void; selectTab: (tab: MenuTab) => void; - setAlertStatus: (status: boolean) => void; + changeAlertInfo: (alertInfo: AlertInfo) => void; setLucidInstance: (lucid: LucidEvolution) => void; }; const useStore = create((set) => ({ mintAccount: { + name: 'Mint Authority', address: 'addr_test1qq986m3uel86pl674mkzneqtycyg7csrdgdxj6uf7v7kd857kquweuh5kmrj28zs8czrwkl692jm67vna2rf7xtafhpqk3hecm', mnemonic: 'problem alert infant glance toss gospel tonight sheriff match else hover upset chicken desert anxiety cliff moment song large seed purpose chalk loan onion', balance: 0, }, - userA: { - address: '', - mnemonic: 'during dolphin crop lend pizza guilt hen earn easy direct inhale deputy detect season army inject exhaust apple hard front bubble emotion short portion', - balance: 0, - status: 'Active', - }, - userB: { - address: '', - mnemonic: 'tooth benefit wish capable stock inner motor cover diamond crash work amount foot help shell glad friend front degree pudding inflict filter twice resource', - balance: 0, - status: 'Active', - }, - walletUser: - { - address: '', - mnemonic: '', - balance: 0, - status: 'Active', + accounts: { + userA: { + address: '', + mnemonic: 'during dolphin crop lend pizza guilt hen earn easy direct inhale deputy detect season army inject exhaust apple hard front bubble emotion short portion', + balance: 0, + status: 'Active', + }, + userB: { + address: '', + mnemonic: 'silver legal flame powder fence kiss stable margin refuse hold unknown valid wolf kangaroo zero able waste jewel find salad sadness exhibit hello tape', + balance: 0, + status: 'Active', + }, + walletUser: { + address: '', + mnemonic: '', + balance: 0, + status: 'Active', + }, }, + blacklistAddresses: [], currentUser: 'Mint Authority', selectedTab: 'Mint Actions', - alertOpen: false, - errorMessage: false, + alertInfo: { + open: false, + message: 'Transaction sent successfully!', + severity: 'success', + }, lucid: {} as LucidEvolution, changeMintAccountDetails: (newAccountInfo: AccountInfo) => { @@ -65,22 +67,13 @@ const useStore = create((set) => ({ }); }, - changeWalletAAccountDetails: (newAccountInfo: AccountInfo) => { - set(() => { - return { userA: newAccountInfo }; - }); - }, - - changeWalletBAccountDetails: (newAccountInfo: AccountInfo) => { - set(() => { - return { userB: newAccountInfo }; - }); - }, - - changeToLaceWallet: (newAccountInfo: AccountInfo) => { - set(() => { - return { walletUser: newAccountInfo } - }); + changeWalletAccountDetails: (accountKey, newAccountInfo) => { + set((state) => ({ + accounts: { + ...state.accounts, + [accountKey]: newAccountInfo, + }, + })); }, changeUserAccount: (newUser: UserName) => { @@ -94,7 +87,7 @@ const useStore = create((set) => ({ firstAccessibleTab = 'Wallet'; break; case 'Connected Wallet': - if (useStore.getState().walletUser.address === useStore.getState().mintAccount.address) + if (useStore.getState().accounts.walletUser.address === useStore.getState().mintAccount.address) firstAccessibleTab = 'Mint Actions'; else firstAccessibleTab = 'Wallet'; @@ -109,8 +102,13 @@ const useStore = create((set) => ({ set({ selectedTab: tab }); }, - setAlertStatus: (status: boolean) => { - set({ alertOpen: status }); + changeAlertInfo: (partial: Partial) => { + set((state) => ({ + alertInfo: { + ...state.alertInfo, + ...partial, + }, + })); }, setLucidInstance: (lucid) => { @@ -118,4 +116,4 @@ const useStore = create((set) => ({ } })); -export default useStore; +export default useStore; \ No newline at end of file diff --git a/frontend/src/app/store/types.ts b/frontend/src/app/store/types.ts index 24e8c53..4510245 100644 --- a/frontend/src/app/store/types.ts +++ b/frontend/src/app/store/types.ts @@ -5,4 +5,16 @@ export type AccountInfo = { mnemonic: string, balance: number, status?: 'Active' | 'Frozen', -} \ No newline at end of file +}; +export type AccountKey = 'userA' | 'userB' | 'walletUser'; +export type Accounts = { + userA: AccountInfo; + userB: AccountInfo; + walletUser: AccountInfo; +}; +export type Severity = 'success' | 'error' | 'info' | 'warning'; +export type AlertInfo = { + open: boolean | undefined, + message: string, + severity: Severity, +}; \ No newline at end of file diff --git a/frontend/src/app/styles/globals.css b/frontend/src/app/styles/globals.css index fa48de4..33e4d00 100644 --- a/frontend/src/app/styles/globals.css +++ b/frontend/src/app/styles/globals.css @@ -48,6 +48,11 @@ a { height: 100%; } +.tableContainerBox { + height: 85%; + padding: 16px; +} + /* App loader styles */ .mainLoadingContainer { font-size: 50px; diff --git a/frontend/src/app/styles/theme.tsx b/frontend/src/app/styles/theme.tsx index 29907f8..619215d 100644 --- a/frontend/src/app/styles/theme.tsx +++ b/frontend/src/app/styles/theme.tsx @@ -335,8 +335,8 @@ export const getTheme = (mode: 'light') => createTheme({ root: ({theme}) => ({ backgroundColor: theme.palette.containerLowest.main, boxShadow: 'none', - minHeight: '80%', border: '1px solid #C9C6C6', + height: '100%', }), }, }, @@ -350,7 +350,11 @@ export const getTheme = (mode: 'light') => createTheme({ MuiTableCell: { styleOverrides: { stickyHeader: () => ({ - backgroundColor: 'rgba(57,82,205,0.12)', + background: `linear-gradient( + 0deg, + rgba(57,82,205,0.12), + rgba(57,82,205,0.12) + ), white`, fontSize: '14px', }), body: () => ({ @@ -369,6 +373,10 @@ export const getTheme = (mode: 'light') => createTheme({ backgroundColor: '#FFDBD2', color: '#3C0800', }), + filledInfo: () => ({ + backgroundColor: '#FFF2AC', + color: '#201C00', + }), }, }, }, diff --git a/frontend/src/app/utils/walletUtils.ts b/frontend/src/app/utils/walletUtils.ts index c4a4898..9f95ec5 100644 --- a/frontend/src/app/utils/walletUtils.ts +++ b/frontend/src/app/utils/walletUtils.ts @@ -2,7 +2,8 @@ import axios from 'axios'; //Lucis imports -import { Blockfrost, CML, Lucid, LucidEvolution, TxSigned, walletFromSeed, Credential, valueToAssets, Assets, UTxO, Address, paymentCredentialOf, credentialToAddress, toUnit, Unit } from "@lucid-evolution/lucid"; +import { Address, Assets, Blockfrost, CML, credentialToAddress, Lucid, LucidEvolution, makeTxSignBuilder, paymentCredentialOf, toUnit, TxSignBuilder, Unit, valueToAssets, walletFromSeed } from "@lucid-evolution/lucid"; +import type { Credential as LucidCredential } from "@lucid-evolution/core-types"; async function loadKey() { const response = await axios.get("/blockfrost-key", @@ -16,22 +17,22 @@ async function loadKey() { } export async function makeLucid() { - const API_KEY_ENV = process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY; - const API_KEY = (API_KEY_ENV) ? API_KEY_ENV : await loadKey(); + const API_KEY_ENV = process.env.NEXT_PUBLIC_BLOCKFROST_API_KEY; + const API_KEY = (API_KEY_ENV) ? API_KEY_ENV : await loadKey(); - const blockfrostURL = "https://cardano-preview.blockfrost.io/api/v0" + const blockfrostURL = "https://cardano-preview.blockfrost.io/api/v0" - const blockfrost = new Blockfrost(blockfrostURL, API_KEY); + const blockfrost = new Blockfrost(blockfrostURL, API_KEY); - const lucid = await Lucid(blockfrost, "Preview"); + const lucid = await Lucid(blockfrost, "Preview"); - return lucid; + return lucid; } export async function getWalletFromSeed(mnemonic: string) { try { - const mintWallet = walletFromSeed(mnemonic, {password: '', addressType: 'Base', accountIndex: 0, network: "Preview"}); - return mintWallet; + const wallet = walletFromSeed(mnemonic, {password: '', addressType: 'Base', accountIndex: 0, network: "Preview"}); + return wallet; } catch (error) { console.error('Failed to initialize KeyAgent:', error); throw error; @@ -62,22 +63,39 @@ export async function getWalletBalance(address: string){ } } -export function setScriptDataHash(tx: CML.Transaction, newScriptDataHash: CML.ScriptDataHash) : CML.Transaction { - const txBodyClone = CML.TransactionBody.from_cbor_hex(tx.body().to_cbor_hex()); - txBodyClone.set_script_data_hash(newScriptDataHash); - const clonedTx = CML.Transaction.new(txBodyClone, tx.witness_set(), true, tx.auxiliary_data()); - tx.free(); - return clonedTx; +export async function getBlacklist(){ + try { + const response = await axios.get( + '/api/v1/query/blacklist/addr_test1qq986m3uel86pl674mkzneqtycyg7csrdgdxj6uf7v7kd857kquweuh5kmrj28zs8czrwkl692jm67vna2rf7xtafhpqk3hecm', + { + headers: { + 'Content-Type': 'application/json;charset=utf-8', + }, + } + ); + + // console.log('Get blacklist:', response); + return response.data; + } catch (error) { + console.warn('Failed to get blacklist', error); + return error; + } } -export function adjustScriptDataHash(tx: TxSigned, costModel: CML.CostModels) : CML.Transaction { - const cmlTx = tx.toTransaction(); - const witnessSet = cmlTx.witness_set() - const plutusDatumsI = witnessSet.plutus_datums() - const plutusDatums : CML.PlutusDataList = (plutusDatumsI !== undefined) ? plutusDatumsI : CML.PlutusDataList.new(); - const expectedScriptDataHash : CML.ScriptDataHash | undefined = CML.calc_script_data_hash(witnessSet.redeemers()!, plutusDatums, costModel, witnessSet.languages()); - const fixedTx = setScriptDataHash(cmlTx, expectedScriptDataHash!); - return fixedTx +export async function signAndSentTx(lucid: LucidEvolution, tx: TxSignBuilder) { + const txBuilder = await makeTxSignBuilder(lucid.wallet(), tx.toTransaction()).complete(); + const cmlTx = txBuilder.toTransaction(); + const witnessSet = txBuilder.toTransaction().witness_set(); + const expectedScriptDataHash : CML.ScriptDataHash | undefined = CML.calc_script_data_hash(witnessSet.redeemers()!, CML.PlutusDataList.new(), lucid.config().costModels!, witnessSet.languages()); + console.log('Calculated Script Data Hash:', expectedScriptDataHash?.to_hex()); + const cmlTxBodyClone = CML.TransactionBody.from_cbor_hex(cmlTx!.body().to_cbor_hex()); + console.log('Preclone script hash:', cmlTxBodyClone.script_data_hash()?.to_hex()); + cmlTxBodyClone.set_script_data_hash(expectedScriptDataHash!); + console.log('Postclone script hash:', cmlTxBodyClone.script_data_hash()?.to_hex()); + const cmlClonedTx = CML.Transaction.new(cmlTxBodyClone, cmlTx!.witness_set(), true, cmlTx!.auxiliary_data()); + const cmlClonedSignedTx = await makeTxSignBuilder(lucid.wallet(), cmlClonedTx).sign.withWallet().complete(); + const txId = await cmlClonedSignedTx.submit(); + await lucid.awaitTx(txId); } export type WalletType = "Lace" | "Eternl" | "Nami" | "Yoroi"; @@ -87,12 +105,12 @@ export async function selectLucidWallet(lucid: LucidEvolution, wallet: WalletTyp lucid.selectWallet.fromAPI(api); } -const progLogicBase : Credential = { +const progLogicBase : LucidCredential = { type: "Script", hash: "fca77bcce1e5e73c97a0bfa8c90f7cd2faff6fd6ed5b6fec1c04eefa" } -const stableCoin : Unit = toUnit("b34a184f1f2871aa4d33544caecefef5242025f45c3fa5213d7662a9", "575354") +const stableCoin : Unit = toUnit("b34a184f1f2871aa4d33544caecefef5242025f45c3fa5213d7662a9", "575354"); export function adjustMintOutput(tx: CML.Transaction, receiverAddress: Address, mintedAmount: bigint) { const txB : CML.TransactionBody = tx.body() @@ -117,6 +135,10 @@ export function adjustMintOutput(tx: CML.Transaction, receiverAddress: Address, } else { new_outputs.add(output) } + // if (value !== undefined) { + // const newValue = value + 100 + // assets.insert(stableCoin, newValue) + // } } const newTxB : CML.TransactionBody = CML.TransactionBody.new(txB.inputs(), new_outputs, txB.fee()); const oldTxAuxHash = txB.auxiliary_data_hash() @@ -190,21 +212,10 @@ export function adjustMintOutput(tx: CML.Transaction, receiverAddress: Address, } -export async function getStablecoinAccounts(lucid: LucidEvolution) { - const progUTxOs : UTxO[] = await lucid.utxosAtWithUnit(progLogicBase, stableCoin); - const addresses = new Set(); - const valueMap = new Map(); - progUTxOs.forEach(utxo => { - addresses.add(utxo.address) - valueMap.set(utxo.address, Number(utxo.assets[stableCoin])) - }); - return { addresses: Array.from(addresses), valueMap }; -} - export async function deriveProgrammableAddress(lucid: LucidEvolution, userAddress: Address){ const network = lucid.config().network!; // user's payment credential - const ownerCred : Credential = paymentCredentialOf(userAddress); + const ownerCred : LucidCredential = paymentCredentialOf(userAddress); // construct the user's programmable token address // payment credential is always the programmable token base script hash @@ -215,4 +226,5 @@ export async function deriveProgrammableAddress(lucid: LucidEvolution, userAddre ownerCred, ); return userProgrammableTokenAddress; + } \ No newline at end of file diff --git a/nix/containers.nix b/nix/containers.nix index ed33021..f3f2572 100644 --- a/nix/containers.nix +++ b/nix/containers.nix @@ -3,7 +3,7 @@ frontendNpm = pkgs.buildNpmPackage rec { name = "frontend"; src = ../frontend; - npmDepsHash = "sha256-N15xhC5rFY0pgnP6BXIztgfx2wDztcEvU5iOwDFFmHs="; + npmDepsHash = "sha256-fV2smCrCa4Egb4WZtiQsaDN4egiLYDKJVlNkjAjwETA="; npmPackFlags = [ "--ignore-scripts" ]; npmBuildScript = "export"; installPhase = '' diff --git a/src/wst-poc.cabal b/src/wst-poc.cabal index ccf18d6..2a0c8a8 100644 --- a/src/wst-poc.cabal +++ b/src/wst-poc.cabal @@ -132,6 +132,7 @@ executable wst-poc-cli import: lang main-is: Main.hs hs-source-dirs: exe/wst-poc-cli + ghc-options: -threaded -rtsopts -O2 -with-rtsopts=-N build-depends: , base , wst-poc