diff --git a/e2e-tests/popup/buy-cspr/buy-cspr.spec.ts b/e2e-tests/popup/buy-cspr/buy-cspr.spec.ts index e10eec6fb..15ee207df 100644 --- a/e2e-tests/popup/buy-cspr/buy-cspr.spec.ts +++ b/e2e-tests/popup/buy-cspr/buy-cspr.spec.ts @@ -22,10 +22,6 @@ popup.describe('Popup UI: buy cspr', () => { ).toBeVisible(); await popupPage.getByRole('button', { name: 'Next' }).click(); - await popupExpect( - popupPage.getByRole('heading', { name: 'Review provider option' }) - ).toBeVisible(); - await popupPage.getByText('Topper by Uphold').click(); await popupExpect( @@ -43,7 +39,7 @@ popup.describe('Popup UI: buy cspr', () => { } ); - popup.skip( + popup( 'should redirect to Ramp provider page', async ({ popupPage, unlockVault, context }) => { await unlockVault(); @@ -64,10 +60,6 @@ popup.describe('Popup UI: buy cspr', () => { ).toBeVisible(); await popupPage.getByRole('button', { name: 'Next' }).click(); - await popupExpect( - popupPage.getByRole('heading', { name: 'Pick provider' }) - ).toBeVisible(); - await popupExpect( popupPage.getByRole('button', { name: 'Confirm' }) ).toBeDisabled(); diff --git a/package-lock.json b/package-lock.json index 6b834366b..daaddd094 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@noble/ciphers": "^0.3.0", "@scure/bip32": "1.3.2", "@scure/bip39": "1.2.1", + "@tanstack/react-query": "^5.52.3", "@types/argon2-browser": "1.18.1", "@types/webextension-polyfill": "0.9.2", "@zondax/ledger-casper": "^2.6.1", @@ -27,6 +28,7 @@ "big.js": "^6.2.1", "casper-cep18-js-client": "1.0.2", "casper-js-sdk": "2.15.4", + "casper-wallet-core": "git+ssh://git@github.com:make-software/casper-wallet-core.git#v0.9.1", "date-fns": "^2.30.0", "i18next": "^23.11.0", "i18next-browser-languagedetector": "^7.2.1", @@ -431,12 +433,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -485,34 +487,21 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.1.tgz", + "integrity": "sha512-Y956ghgTT4j7rKesabkh5WeqgSFZVFwaPR0IWFm7KFHFmmJ4afbG49SmfW4S+GyRPx0Dy5jxEWA5t0rpxfElWg==", "dev": true, "dependencies": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || >=14.0.0" }, "peerDependencies": { - "@babel/core": ">=7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@babel/eslint-parser/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { @@ -524,23 +513,14 @@ "node": ">=10" } }, - "node_modules/@babel/eslint-parser/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/@babel/generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", - "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dependencies": { - "@babel/types": "^7.23.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -548,24 +528,24 @@ } }, "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -612,19 +592,17 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.10", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", - "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz", + "integrity": "sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==", "dev": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.0", "semver": "^6.3.1" }, "engines": { @@ -680,6 +658,7 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -692,6 +671,7 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, "dependencies": { "@babel/types": "^7.22.5" }, @@ -700,12 +680,13 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -741,21 +722,21 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "engines": { "node": ">=6.9.0" } @@ -778,14 +759,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -806,12 +787,13 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -829,17 +811,17 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "engines": { "node": ">=6.9.0" } @@ -880,22 +862,26 @@ } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", - "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "dependencies": { + "@babel/types": "^7.25.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -952,17 +938,14 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.9.tgz", - "integrity": "sha512-EfH2LZ/vPa2wuPwJ26j+kYRkaubf89UlwxKXtxqEm57HrgSEYDB8t4swFP+p8LcI9yiP9ZRJJjo/58hS6BnaDA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.7.tgz", + "integrity": "sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.9", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/plugin-syntax-decorators": "^7.17.0", - "charcodes": "^0.2.0" + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-decorators": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1100,12 +1083,12 @@ } }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz", - "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.7.tgz", + "integrity": "sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -2465,32 +2448,29 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", - "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.3", - "@babel/types": "^7.23.3", - "debug": "^4.1.0", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -2498,12 +2478,12 @@ } }, "node_modules/@babel/types": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", - "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -4513,9 +4493,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "engines": { "node": ">=6.0.0" } @@ -4550,9 +4530,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -4712,6 +4692,37 @@ "integrity": "sha512-+VnaO5zYUwFQVuRqp2qLPGR5GwhhJ/lrp0yEmamJ/nI15P2GKwGBEWRDiITZR8i6AYxeiQSu2rOi/gqxehnPuA==", "dev": true }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/@noble/ciphers": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.3.0.tgz", @@ -5021,6 +5032,11 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "dev": true }, + "node_modules/@react-native/typescript-config": { + "version": "0.74.83", + "resolved": "https://registry.npmjs.org/@react-native/typescript-config/-/typescript-config-0.74.83.tgz", + "integrity": "sha512-UTcZZYkSD+vv2O67bL/wu0GCGJP3BCbIxXd9ZewNkJmiWl5BbfoNl23+EjmDwM2V66gu24VB/RsSMn0TdmFs8Q==" + }, "node_modules/@redux-devtools/cli": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@redux-devtools/cli/-/cli-4.0.0.tgz", @@ -6244,6 +6260,30 @@ "node": ">=10" } }, + "node_modules/@tanstack/query-core": { + "version": "5.52.3", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.52.3.tgz", + "integrity": "sha512-+Gh7lXn+eoAsarvvnndgqBeJ5lOjup8qgQnrTsFuhNTEAo0H934DxEPro4s3TlmvITfDTJ3UDCy7kY8Azm0qsA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.52.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.52.3.tgz", + "integrity": "sha512-1K7l2hkqlWuh5SdaTYPSwMmHJF5dDk5INK+EtiEwUZW4+usWTXZx7QeHuk078oSzTzaVkEFyT3VquK7F0hYkUw==", + "dependencies": { + "@tanstack/query-core": "5.52.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -7611,6 +7651,11 @@ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==" + }, "node_modules/@types/webextension-polyfill": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.9.2.tgz", @@ -8527,6 +8572,22 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/addons-linter/node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/addons-linter/node_modules/glob": { "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", @@ -8664,6 +8725,18 @@ "node": ">=10" } }, + "node_modules/addons-linter/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/addons-linter/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -8999,6 +9072,14 @@ "node": ">= 8" } }, + "node_modules/apisauce": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/apisauce/-/apisauce-3.0.1.tgz", + "integrity": "sha512-4HEmETv0skPW+bFS4TzB5nQ5y2TdafbUpnAjp83MW8Re9lHwngao2hpnk7aIaxExJqSTxkpWl+ThgZbqjx2bpQ==", + "dependencies": { + "axios": "^1.4.0" + } + }, "node_modules/append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", @@ -9271,8 +9352,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -9328,6 +9408,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -10525,6 +10615,54 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/casper-wallet-core": { + "name": "CasperWalletCommon", + "version": "0.1.0", + "resolved": "git+ssh://git@github.com/make-software/casper-wallet-core.git#1f3412b784ceea227cc2aa721ec0c835fdebb24a", + "dependencies": { + "@make-software/ces-js-parser": "^1.3.3", + "@react-native/typescript-config": "0.74.83", + "@types/uuid": "^10.0.0", + "apisauce": "^3.0.1", + "casper-cep18-js-client": "^1.0.2", + "casper-js-sdk": "2.15.4", + "date-fns": "^2.30.0", + "decimal.js": "^10.4.3", + "lru-cache": "10.4.3", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/casper-wallet-core/node_modules/@make-software/ces-js-parser": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@make-software/ces-js-parser/-/ces-js-parser-1.3.3.tgz", + "integrity": "sha512-uJ7BgnaVbb1pkGfDCgBqES+f5+RVlVPkAYxOC6Qz9kxzIcu9HYH1eA+8EkjRO2T36uBemTjBRO6R0TdH61PIAA==", + "dependencies": { + "ts-results": "^3.3.0" + }, + "peerDependencies": { + "casper-js-sdk": "^2.12.0" + } + }, + "node_modules/casper-wallet-core/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/casper-wallet-core/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/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -10547,15 +10685,6 @@ "node": ">=10" } }, - "node_modules/charcodes": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz", - "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", @@ -11142,7 +11271,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -11180,7 +11308,7 @@ "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, "node_modules/compressible": { @@ -12465,10 +12593,9 @@ } }, "node_modules/decimal.js": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz", - "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==", - "dev": true + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, "node_modules/decompress-response": { "version": "6.0.0", @@ -12823,7 +12950,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -14985,7 +15111,6 @@ "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, "funding": [ { "type": "individual", @@ -15051,7 +15176,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -21574,7 +21698,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -21583,7 +21706,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -23734,6 +23856,11 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -29640,12 +29767,12 @@ "dev": true }, "@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "requires": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" } }, "@babel/compat-data": { @@ -29683,69 +29810,53 @@ } }, "@babel/eslint-parser": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", - "integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.1.tgz", + "integrity": "sha512-Y956ghgTT4j7rKesabkh5WeqgSFZVFwaPR0IWFm7KFHFmmJ4afbG49SmfW4S+GyRPx0Dy5jxEWA5t0rpxfElWg==", "dev": true, "requires": { - "eslint-scope": "^5.1.1", + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "dependencies": { - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, "eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true } } }, "@babel/generator": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", - "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "requires": { - "@babel/types": "^7.23.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.25.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "dependencies": { "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "requires": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" } } } }, "@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { @@ -29785,19 +29896,17 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.23.10", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", - "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz", + "integrity": "sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-member-expression-to-functions": "^7.23.0", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.0", "semver": "^6.3.1" } }, @@ -29835,6 +29944,7 @@ "version": "7.23.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, "requires": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -29844,17 +29954,19 @@ "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, "requires": { "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", "dev": true, "requires": { - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" } }, "@babel/helper-module-imports": { @@ -29878,18 +29990,18 @@ } }, "@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" } }, "@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==" + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==" }, "@babel/helper-remap-async-to-generator": { "version": "7.22.20", @@ -29903,14 +30015,14 @@ } }, "@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" } }, "@babel/helper-simple-access": { @@ -29922,12 +30034,13 @@ } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", "dev": true, "requires": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" } }, "@babel/helper-split-export-declaration": { @@ -29939,14 +30052,14 @@ } }, "@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==" + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==" }, "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==" }, "@babel/helper-validator-option": { "version": "7.22.15", @@ -29975,19 +30088,23 @@ } }, "@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "requires": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" } }, "@babel/parser": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", - "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==" + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "requires": { + "@babel/types": "^7.25.2" + } }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.22.15", @@ -30020,17 +30137,14 @@ } }, "@babel/plugin-proposal-decorators": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.9.tgz", - "integrity": "sha512-EfH2LZ/vPa2wuPwJ26j+kYRkaubf89UlwxKXtxqEm57HrgSEYDB8t4swFP+p8LcI9yiP9ZRJJjo/58hS6BnaDA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.7.tgz", + "integrity": "sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.9", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/plugin-syntax-decorators": "^7.17.0", - "charcodes": "^0.2.0" + "@babel/helper-create-class-features-plugin": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-decorators": "^7.24.7" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { @@ -30118,12 +30232,12 @@ } }, "@babel/plugin-syntax-decorators": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.17.0.tgz", - "integrity": "sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.7.tgz", + "integrity": "sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.24.7" } }, "@babel/plugin-syntax-dynamic-import": { @@ -31035,39 +31149,36 @@ } }, "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" } }, "@babel/traverse": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", - "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.3", - "@babel/types": "^7.23.3", - "debug": "^4.1.0", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", + "requires": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", + "debug": "^4.3.1", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", - "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" } }, @@ -32491,9 +32602,9 @@ "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==" }, "@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/source-map": { "version": "0.3.5", @@ -32524,9 +32635,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "requires": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -32669,6 +32780,33 @@ "integrity": "sha512-+VnaO5zYUwFQVuRqp2qLPGR5GwhhJ/lrp0yEmamJ/nI15P2GKwGBEWRDiITZR8i6AYxeiQSu2rOi/gqxehnPuA==", "dev": true }, + "@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "requires": { + "eslint-scope": "5.1.1" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, "@noble/ciphers": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-0.3.0.tgz", @@ -32907,6 +33045,11 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "dev": true }, + "@react-native/typescript-config": { + "version": "0.74.83", + "resolved": "https://registry.npmjs.org/@react-native/typescript-config/-/typescript-config-0.74.83.tgz", + "integrity": "sha512-UTcZZYkSD+vv2O67bL/wu0GCGJP3BCbIxXd9ZewNkJmiWl5BbfoNl23+EjmDwM2V66gu24VB/RsSMn0TdmFs8Q==" + }, "@redux-devtools/cli": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@redux-devtools/cli/-/cli-4.0.0.tgz", @@ -33828,6 +33971,19 @@ "defer-to-connect": "^2.0.0" } }, + "@tanstack/query-core": { + "version": "5.52.3", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.52.3.tgz", + "integrity": "sha512-+Gh7lXn+eoAsarvvnndgqBeJ5lOjup8qgQnrTsFuhNTEAo0H934DxEPro4s3TlmvITfDTJ3UDCy7kY8Azm0qsA==" + }, + "@tanstack/react-query": { + "version": "5.52.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.52.3.tgz", + "integrity": "sha512-1K7l2hkqlWuh5SdaTYPSwMmHJF5dDk5INK+EtiEwUZW4+usWTXZx7QeHuk078oSzTzaVkEFyT3VquK7F0hYkUw==", + "requires": { + "@tanstack/query-core": "5.52.3" + } + }, "@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -35053,6 +35209,11 @@ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" }, + "@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==" + }, "@types/webextension-polyfill": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.9.2.tgz", @@ -35736,6 +35897,16 @@ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true }, + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, "glob": { "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", @@ -35833,6 +36004,12 @@ "lru-cache": "^6.0.0" } }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -36101,6 +36278,14 @@ "picomatch": "^2.0.4" } }, + "apisauce": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/apisauce/-/apisauce-3.0.1.tgz", + "integrity": "sha512-4HEmETv0skPW+bFS4TzB5nQ5y2TdafbUpnAjp83MW8Re9lHwngao2hpnk7aIaxExJqSTxkpWl+ThgZbqjx2bpQ==", + "requires": { + "axios": "^1.4.0" + } + }, "append-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", @@ -36319,8 +36504,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "at-least-node": { "version": "1.0.0", @@ -36358,6 +36542,16 @@ "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==", "dev": true }, + "axios": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -37269,6 +37463,42 @@ } } }, + "casper-wallet-core": { + "version": "git+ssh://git@github.com/make-software/casper-wallet-core.git#1f3412b784ceea227cc2aa721ec0c835fdebb24a", + "from": "casper-wallet-core@git+ssh://git@github.com:make-software/casper-wallet-core.git#v0.9.1", + "requires": { + "@make-software/ces-js-parser": "^1.3.3", + "@react-native/typescript-config": "0.74.83", + "@types/uuid": "^10.0.0", + "apisauce": "^3.0.1", + "casper-cep18-js-client": "^1.0.2", + "casper-js-sdk": "2.15.4", + "date-fns": "^2.30.0", + "decimal.js": "^10.4.3", + "lru-cache": "10.4.3", + "uuid": "^9.0.0" + }, + "dependencies": { + "@make-software/ces-js-parser": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@make-software/ces-js-parser/-/ces-js-parser-1.3.3.tgz", + "integrity": "sha512-uJ7BgnaVbb1pkGfDCgBqES+f5+RVlVPkAYxOC6Qz9kxzIcu9HYH1eA+8EkjRO2T36uBemTjBRO6R0TdH61PIAA==", + "requires": { + "ts-results": "^3.3.0" + } + }, + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + } + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -37285,12 +37515,6 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, - "charcodes": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/charcodes/-/charcodes-0.2.0.tgz", - "integrity": "sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==", - "dev": true - }, "charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", @@ -37734,7 +37958,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -37760,7 +37983,7 @@ "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, "compressible": { @@ -38721,10 +38944,9 @@ "dev": true }, "decimal.js": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz", - "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==", - "dev": true + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, "decompress-response": { "version": "6.0.0", @@ -38975,8 +39197,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegates": { "version": "1.0.0", @@ -40625,8 +40846,7 @@ "follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, "for-each": { "version": "0.3.3", @@ -40665,7 +40885,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -45518,14 +45737,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "requires": { "mime-db": "1.52.0" } @@ -47118,6 +47335,11 @@ "ipaddr.js": "1.9.1" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", diff --git a/package.json b/package.json index 021f1afea..36c89bc6b 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@noble/ciphers": "^0.3.0", "@scure/bip32": "1.3.2", "@scure/bip39": "1.2.1", + "@tanstack/react-query": "^5.52.3", "@types/argon2-browser": "1.18.1", "@types/webextension-polyfill": "0.9.2", "@zondax/ledger-casper": "^2.6.1", @@ -71,6 +72,7 @@ "big.js": "^6.2.1", "casper-cep18-js-client": "1.0.2", "casper-js-sdk": "2.15.4", + "casper-wallet-core": "git+ssh://git@github.com:make-software/casper-wallet-core.git#v0.9.1", "date-fns": "^2.30.0", "i18next": "^23.11.0", "i18next-browser-languagedetector": "^7.2.1", diff --git a/src/apps/popup/app-router.tsx b/src/apps/popup/app-router.tsx index 7e67ea351..c48e4e04f 100644 --- a/src/apps/popup/app-router.tsx +++ b/src/apps/popup/app-router.tsx @@ -5,7 +5,6 @@ import { HashRouter, Route, Routes } from 'react-router-dom'; import { useUserActivityTracker } from '@src/hooks/use-user-activity-tracker'; import { AccountSettingsPage } from '@popup/pages/account-settings'; -import { ActivityDetailsPage } from '@popup/pages/activity-details'; import { AddContactPage } from '@popup/pages/add-contact'; import { AllAccountsPage } from '@popup/pages/all-accounts'; import { BackupSecretPhrasePage } from '@popup/pages/backup-secret-phrase'; @@ -16,6 +15,7 @@ import { ConnectedSitesPage } from '@popup/pages/connected-sites'; import { ContactDetailsPage } from '@popup/pages/contact-details'; import { ContactsBookPage } from '@popup/pages/contacts'; import { CreateAccountPage } from '@popup/pages/create-account'; +import { DeployDetailsPage } from '@popup/pages/deploy-details'; import { DownloadAccountKeysPage } from '@popup/pages/download-account-keys'; import { HomePageContent } from '@popup/pages/home'; import { ImportAccountFromLedgerPage } from '@popup/pages/import-account-from-ledger'; @@ -203,10 +203,6 @@ function AppRoutes() { element={} /> } /> - } - /> } /> } /> } /> @@ -252,6 +248,7 @@ function AppRoutes() { path={RouterPath.SignWithLedgerInNewWindow} element={} /> + } /> ); } diff --git a/src/apps/popup/index.tsx b/src/apps/popup/index.tsx index cc051bf5f..3ca701e98 100644 --- a/src/apps/popup/index.tsx +++ b/src/apps/popup/index.tsx @@ -1,3 +1,4 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import React, { Suspense, useState } from 'react'; import { createRoot } from 'react-dom/client'; // skeleton styles @@ -26,6 +27,20 @@ import { AppRouter } from './app-router'; const Tree = () => { const [state, setState] = useState(null); + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 3 * 60 * 1000, + refetchInterval: 3 * 60 * 1000, + gcTime: 3 * 60 * 1000, + retry: false + }, + mutations: { + retry: false + } + } + }); + setCSPForSafari(); const isSystemDarkTheme = useSystemThemeDetector(); @@ -60,9 +75,11 @@ const Tree = () => { - - - + + + + + diff --git a/src/apps/popup/pages/activity-details/content.tsx b/src/apps/popup/pages/activity-details/content.tsx deleted file mode 100644 index a25d0444c..000000000 --- a/src/apps/popup/pages/activity-details/content.tsx +++ /dev/null @@ -1,402 +0,0 @@ -import React from 'react'; -import { Trans, useTranslation } from 'react-i18next'; -import { useSelector } from 'react-redux'; -import styled from 'styled-components'; - -import { - ActivityType, - ActivityTypeName, - AuctionManagerEntryPoint, - getBlockExplorerContractUrl -} from '@src/constants'; - -import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; - -import { - AlignedFlexRow, - AlignedSpaceBetweenFlexRow, - BorderBottomPseudoElementProps, - ContentContainer, - FlexColumn, - ParagraphContainer, - RightAlignedFlexColumn, - SpaceBetweenFlexRow, - SpacingSize, - borderBottomPseudoElementRules -} from '@libs/layout'; -import { ExtendedDeploy } from '@libs/services/account-activity-service'; -import { - Avatar, - ContractIcon, - CopyToClipboard, - DeployStatus, - Hash, - HashVariant, - Link, - SvgIcon, - Tile, - Tooltip, - Typography, - isPendingStatus -} from '@libs/ui/components'; -import { - divideErc20Balance, - formatCurrency, - formatNumber, - formatTimestamp, - formatTimestampAge, - motesToCSPR, - motesToCurrency -} from '@libs/ui/utils'; - -interface ActivityDetailsPageContentProps { - fromAccount?: string; - toAccount?: string; - deployInfo?: ExtendedDeploy | null; - type?: ActivityType | null; - amount?: string | null; - symbol?: string | null; -} - -export const ExecutionTypesMap = { - 1: 'WASM deploy', //"ModuleBytes" - 2: 'Contract call', //"StoredContractByHash" - 3: 'Contract call', //"StoredContractByName", - 4: 'Contract call', //"StoredVersionedContractByHash", - 5: 'Contract call', //"StoredVersionedContractByName", - 6: 'Transfer' -}; - -const Erc20EventType = { - erc20_approve: 'approve', - erc20_transfer: 'transfer', - erc20_transfer_from: 'transfer_from', - erc20_mint: 'mint', - erc20_burn: 'burn' -}; - -const ItemContainer = styled(AlignedSpaceBetweenFlexRow)` - padding: 16px 16px 16px 0; -`; - -const AddressContainer = styled(FlexColumn)` - padding: 16px 12px 16px 0; -`; - -const AmountRowContainer = styled(AlignedSpaceBetweenFlexRow)<{ - emptyAmount?: boolean; -}>` - padding: ${({ emptyAmount }) => - emptyAmount ? '16px 16px 16px 0' : '8px 16px 8px 0'}; -`; - -const AmountContainer = styled.div` - max-width: 160px; -`; - -const RowsContainer = styled(FlexColumn)` - margin-top: 12px; - - & > *:not(:last-child) { - ${borderBottomPseudoElementRules}; - } - - & > *:last-child { - padding-left: ${({ marginLeftForSeparatorLine }) => - marginLeftForSeparatorLine}px; - } -`; - -export const ActivityDetailsPageContent = ({ - fromAccount, - toAccount, - deployInfo, - type, - amount, - symbol -}: ActivityDetailsPageContentProps) => { - const { t } = useTranslation(); - - const { casperLiveUrl } = useSelector(selectApiConfigBasedOnActiveNetwork); - - if (deployInfo == null) return null; - - // TODO: update when activity will be added for NFT - const EVENT_TYPE_LOCALE = { - [Erc20EventType.erc20_transfer]: t('Transfer of'), - [Erc20EventType.erc20_transfer_from]: t('Transfer from'), - [Erc20EventType.erc20_approve]: t('Approve of'), - [Erc20EventType.erc20_burn]: t('Burn of'), - [Erc20EventType.erc20_mint]: t('Mint of'), - [AuctionManagerEntryPoint.delegate]: t('Delegate with'), - [AuctionManagerEntryPoint.undelegate]: t('Undelegate with'), - [AuctionManagerEntryPoint.redelegate]: t('Redelegate with') - }; - - const decimals = deployInfo.contractPackage?.metadata?.decimals; - const eventType = EVENT_TYPE_LOCALE[deployInfo.entryPoint?.name!]; - - const transferAmount = - deployInfo.amount != null - ? Number.isInteger(decimals) && decimals !== undefined - ? divideErc20Balance(deployInfo?.amount, decimals) - : motesToCSPR(deployInfo.amount) - : null; - - const formattedTransferAmount = transferAmount - ? formatNumber(transferAmount, { - precision: { min: 5 } - }) - : '-'; - const transferAmountInUSD = - deployInfo.amount != null && - deployInfo.rate && - formatCurrency(motesToCurrency(deployInfo.amount, deployInfo.rate), 'USD', { - precision: 5 - }); - - const paymentAmountInCSPR = - deployInfo.paymentAmount != null && - formatNumber(motesToCSPR(deployInfo.paymentAmount), { - precision: { min: 5 } - }); - const paymentAmountInUSD = - deployInfo.paymentAmount != null && - deployInfo.rate && - formatCurrency( - motesToCurrency(deployInfo.paymentAmount, deployInfo.rate), - 'USD', - { - precision: 5 - } - ); - - const costAmountInCSPR = formatNumber(motesToCSPR(deployInfo.cost || '0'), { - precision: { min: 5 } - }); - const costAmountInUSD = formatCurrency( - String(deployInfo.currencyCost) || '0', - 'USD', - { - precision: 5 - } - ); - - return ( - - - - {type && {ActivityTypeName[type]}} - - - - - - - - - - - From - - - To - - - - - - - - - - - - - - - - - Deploy hash - - - - - - Age - - - - {formatTimestampAge(deployInfo.timestamp)} - - - - - - Action - - {deployInfo.contractPackage && eventType ? ( - - {eventType} - - - - - {deployInfo.contractPackage.contract_name} - - - - isClicked ? ( - - ) : ( - - ) - } - valueToCopy={ - deployInfo.contractPackage.contract_package_hash || - deployInfo.contractHash! - } - /> - - - {deployInfo.contractPackage.contract_name === 'Auction' - ? 'System Contract' - : 'contract'} - - - - - ) : ( - - {ExecutionTypesMap[deployInfo.executionTypeId]} - - )} - - - - Amount - - 18 - ? `${formattedTransferAmount} ${ - formattedTransferAmount !== '-' - ? deployInfo.contractPackage?.metadata?.symbol || 'CSPR' - : '' - }` - : undefined - } - > - - - - {isPendingStatus(deployInfo.status) - ? `${amount} ${symbol || 'CSPR'}` - : `${formattedTransferAmount} ${ - formattedTransferAmount !== '-' - ? deployInfo.contractPackage?.metadata?.symbol || - 'CSPR' - : '' - }`} - - - {!deployInfo.contractPackage?.metadata?.symbol && ( - - {transferAmountInUSD} - - )} - - - - - - Payment Amount - - - {isPendingStatus(deployInfo.status) ? ( - - {`${paymentAmountInCSPR} CSPR`} - - ) : ( - <> - - {`${paymentAmountInCSPR} CSPR`} - - - {paymentAmountInUSD} - - - )} - - - - - Cost - - - {isPendingStatus(deployInfo.status) ? ( - - - ) : ( - <> - - {`${costAmountInCSPR} CSPR`} - - - {costAmountInUSD} - - - )} - - - - - - ); -}; diff --git a/src/apps/popup/pages/activity-details/index.tsx b/src/apps/popup/pages/activity-details/index.tsx deleted file mode 100644 index 10faec7c8..000000000 --- a/src/apps/popup/pages/activity-details/index.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React, { useEffect, useState } from 'react'; - -import { RouterPath, useTypedLocation, useTypedNavigate } from '@popup/router'; - -import { - HeaderPopup, - HeaderSubmenuBarNavLink, - HeaderViewInExplorer, - PopupLayout -} from '@libs/layout'; -import { - ExtendedDeploy, - dispatchFetchExtendedDeploysInfo -} from '@libs/services/account-activity-service'; -import { HomePageTabsId } from '@libs/ui/components'; - -import { ActivityDetailsPageContent } from './content'; - -export const ActivityDetailsPage = () => { - const [deployInfo, setDeployInfo] = useState(null); - - const location = useTypedLocation(); - const navigate = useTypedNavigate(); - - const { activityDetailsData } = location.state; - - useEffect(() => { - if (!activityDetailsData) { - navigate(RouterPath.Home); - } - }, [activityDetailsData, navigate]); - - useEffect(() => { - if (activityDetailsData?.deployHash) { - dispatchFetchExtendedDeploysInfo(activityDetailsData?.deployHash).then( - ({ payload: deployInfoResponse }) => { - setDeployInfo(deployInfoResponse); - } - ); - } - }, [activityDetailsData?.deployHash]); - - return ( - ( - ( - <> - { - if (activityDetailsData?.isDeploysList) { - navigate(RouterPath.Home, { - state: { - // set the active tab to deploys - activeTabId: HomePageTabsId.Deploys - } - }); - } - } - : undefined - } - /> - - - )} - /> - )} - renderContent={() => ( - - )} - /> - ); -}; diff --git a/src/apps/popup/pages/deploy-details/components/action-rows/associated-action-rows.tsx b/src/apps/popup/pages/deploy-details/components/action-rows/associated-action-rows.tsx new file mode 100644 index 000000000..083aa1f86 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/action-rows/associated-action-rows.tsx @@ -0,0 +1,71 @@ +import { IAccountInfo } from 'casper-wallet-core/src/domain/accountInfo'; +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; + +import { DeployIcon, getBlockExplorerContractUrl } from '@src/constants'; + +import { SimpleContainer } from '@popup/pages/deploy-details/components/common'; + +import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { Link, Typography } from '@libs/ui/components'; +import { AccountInfoIcon } from '@libs/ui/components/account-info-icon/account-info-icon'; +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface AssociatedActionRowsProps { + publicKey: string; + contractPackageHash: string; + contractName: string; + callerAccountInfo: Maybe; +} + +export const AssociatedActionRows = ({ + publicKey, + contractPackageHash, + contractName, + callerAccountInfo +}: AssociatedActionRowsProps) => { + const { t } = useTranslation(); + + const { casperLiveUrl } = useSelector(selectApiConfigBasedOnActiveNetwork); + + const link = getBlockExplorerContractUrl( + casperLiveUrl, + contractPackageHash || '' + ); + + return ( + + + + + + + with + + + + {contractName} + + + + + contract + + + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/components/action-rows/auction-action-rows.tsx b/src/apps/popup/pages/deploy-details/components/action-rows/auction-action-rows.tsx new file mode 100644 index 000000000..e12acc2c8 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/action-rows/auction-action-rows.tsx @@ -0,0 +1,166 @@ +import { IAccountInfo } from 'casper-wallet-core/src/domain/accountInfo'; +import { IAuctionDeploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React from 'react'; + +import { AuctionDeployEntryPoint, DeployIcon } from '@src/constants'; + +import { DefaultActionRows } from '@popup/pages/deploy-details/components/action-rows/default-action-rows'; +import { + ActionContainerWithLink, + AmountRow, + ContainerWithAmount +} from '@popup/pages/deploy-details/components/common'; +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +const ManageAuctionBidAction = ({ + amount, + title, + fiatAmount, + contractPackageHash, + contractName +}: { + amount: string; + title: string; + fiatAmount: string; + contractPackageHash: string; + contractName: string; +}) => ( + + + +); + +const DelegationAuctionAction = ({ + amount, + title, + fiatAmount, + toValidatorAccountInfo, + fromValidatorAccountInfo, + entryPoint, + toValidator, + fromValidator +}: { + amount: string; + title: string; + fiatAmount: string; + toValidatorAccountInfo: Maybe; + fromValidatorAccountInfo: Maybe; + entryPoint: string; + toValidator: Maybe; + fromValidator: Maybe; +}) => { + const isDelegate = entryPoint === AuctionDeployEntryPoint.delegate; + const isUndelegate = entryPoint === AuctionDeployEntryPoint.undelegate; + const isRedelegate = entryPoint === AuctionDeployEntryPoint.redelegate; + + return ( + + {isDelegate && ( + + )} + {(isUndelegate || isRedelegate) && ( + <> + + + + )} + + ); +}; + +interface AuctionActionRowsProps { + deploy: IAuctionDeploy; +} + +export const AuctionActionRows = ({ deploy }: AuctionActionRowsProps) => { + const { + entryPoint, + formattedDecimalAmount, + fiatAmount, + fromValidator, + toValidator, + fromValidatorAccountInfo, + toValidatorAccountInfo + } = deploy; + const isManageAuctionBidDeploy = + entryPoint === AuctionDeployEntryPoint.activate || + entryPoint === AuctionDeployEntryPoint.withdraw || + entryPoint === AuctionDeployEntryPoint.add; + + const isDelegationDeploy = + entryPoint === AuctionDeployEntryPoint.delegate || + entryPoint === AuctionDeployEntryPoint.undelegate || + entryPoint === AuctionDeployEntryPoint.redelegate; + + const title = getEntryPointName(deploy, true); + + if (isManageAuctionBidDeploy) { + return ( + + ); + } + + if (isDelegationDeploy) { + return ( + + ); + } + + return ( + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/components/action-rows/cep18-action-rows.tsx b/src/apps/popup/pages/deploy-details/components/action-rows/cep18-action-rows.tsx new file mode 100644 index 000000000..08e73f1a8 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/action-rows/cep18-action-rows.tsx @@ -0,0 +1,107 @@ +import { ICep18Deploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { Cep18DeployEntryPoint, DeployIcon } from '@src/constants'; + +import { DefaultActionRows } from '@popup/pages/deploy-details/components/action-rows/default-action-rows'; +import { + AmountRow, + ContractInfoRow, + SimpleContainer +} from '@popup/pages/deploy-details/components/common'; +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface Cep18ActionRowsProps { + deploy: ICep18Deploy; +} + +export const Cep18ActionRows = ({ deploy }: Cep18ActionRowsProps) => { + const { + entryPoint, + recipientKey, + contractPackageHash, + contractName, + formattedDecimalAmount, + symbol, + iconUrl + } = deploy; + const isTransfer = entryPoint === Cep18DeployEntryPoint.transfer; + const isMint = entryPoint === Cep18DeployEntryPoint.mint; + const isBurn = entryPoint === Cep18DeployEntryPoint.burn; + const isApprove = entryPoint === Cep18DeployEntryPoint.approve; + + const title = getEntryPointName(deploy, true); + + if (isTransfer || isMint) { + return ( + + + + + + ); + } + + if (isApprove) { + return ( + + + + + + ); + } + + if (isBurn) { + return ( + + + + + + ); + } + + return ( + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/components/action-rows/cspr-market-action-rows.tsx b/src/apps/popup/pages/deploy-details/components/action-rows/cspr-market-action-rows.tsx new file mode 100644 index 000000000..2db0f6773 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/action-rows/cspr-market-action-rows.tsx @@ -0,0 +1,94 @@ +import { ICasperMarketDeploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { CsprMarketDeployEntryPoint } from '@src/constants'; + +import { DefaultActionRows } from '@popup/pages/deploy-details/components/action-rows/default-action-rows'; +import { + AmountRow, + ContractInfoRow, + NftInfoRow, + SimpleContainer +} from '@popup/pages/deploy-details/components/common'; +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface CsprMarketActionRowsProps { + deploy: ICasperMarketDeploy; +} + +export const CsprMarketActionRows = ({ deploy }: CsprMarketActionRowsProps) => { + const { + entryPoint, + contractName, + contractPackageHash, + nftTokenIds, + offererAccountInfo + } = deploy; + const isDelist = entryPoint === CsprMarketDeployEntryPoint.delist_token; + const isListAction = + entryPoint === CsprMarketDeployEntryPoint.delist_token || + entryPoint === CsprMarketDeployEntryPoint.list_token; + const isOfferAction = + entryPoint === CsprMarketDeployEntryPoint.accept_offer || + entryPoint === CsprMarketDeployEntryPoint.make_offer || + entryPoint === CsprMarketDeployEntryPoint.cancel_offer; + + const title = getEntryPointName(deploy, true); + + if (isListAction) { + return ( + + + + + ); + } + + if (isOfferAction) { + return ( + + + + + + + ); + } + + return ( + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/components/action-rows/default-action-rows.tsx b/src/apps/popup/pages/deploy-details/components/action-rows/default-action-rows.tsx new file mode 100644 index 000000000..00212a195 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/action-rows/default-action-rows.tsx @@ -0,0 +1,64 @@ +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; + +import { DeployIcon, getBlockExplorerContractUrl } from '@src/constants'; + +import { SimpleContainer } from '@popup/pages/deploy-details/components/common'; + +import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { Link, Typography } from '@libs/ui/components'; +import { AccountInfoIcon } from '@libs/ui/components/account-info-icon/account-info-icon'; + +interface DefaultActionRowsProps { + title: string; + contractName: Maybe; + additionalInfo?: string; + iconUrl?: string; + contractPackageHash: string; +} + +export const DefaultActionRows = ({ + title, + contractName, + additionalInfo, + iconUrl, + contractPackageHash +}: DefaultActionRowsProps) => { + const { t } = useTranslation(); + + const { casperLiveUrl } = useSelector(selectApiConfigBasedOnActiveNetwork); + + const link = getBlockExplorerContractUrl( + casperLiveUrl, + contractPackageHash || '' + ); + + return ( + + + + with + + + + {contractName} + + {additionalInfo && ( + + {additionalInfo} + + )} + + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/components/action-rows/native-transfer-action-rows.tsx b/src/apps/popup/pages/deploy-details/components/action-rows/native-transfer-action-rows.tsx new file mode 100644 index 000000000..b3b9de9e3 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/action-rows/native-transfer-action-rows.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import { ContainerWithAmount } from '@popup/pages/deploy-details/components/common'; + +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface NativeTransferActionRowsProps { + amount: string; + publicKey: string; + fiatAmount: string; + isReceive: boolean; + title: string; + accountName?: string; +} + +export const NativeTransferActionRows = ({ + amount, + publicKey, + fiatAmount, + isReceive, + title, + accountName +}: NativeTransferActionRowsProps) => ( + + + +); diff --git a/src/apps/popup/pages/deploy-details/components/action-rows/nft-actions-rows.tsx b/src/apps/popup/pages/deploy-details/components/action-rows/nft-actions-rows.tsx new file mode 100644 index 000000000..e5e15369e --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/action-rows/nft-actions-rows.tsx @@ -0,0 +1,156 @@ +import { INftDeploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { DeployIcon, NftDeployEntryPoint } from '@src/constants'; + +import { DefaultActionRows } from '@popup/pages/deploy-details/components/action-rows/default-action-rows'; +import { + ContractInfoRow, + NftInfoRow, + SimpleContainer +} from '@popup/pages/deploy-details/components/common'; +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface NftActionsRowsProps { + deploy: INftDeploy; +} + +export const NftActionsRows = ({ deploy }: NftActionsRowsProps) => { + const { + entryPoint, + nftTokenIds, + recipientKey, + contractPackageHash, + contractName, + callerPublicKey, + iconUrl, + callerAccountInfo, + recipientAccountInfo + } = deploy; + const isBurn = entryPoint === NftDeployEntryPoint.burn; + const isMint = entryPoint === NftDeployEntryPoint.mint; + const isTransfer = entryPoint === NftDeployEntryPoint.transfer; + const isUpdate = entryPoint === NftDeployEntryPoint.update_token_meta; + const isApprove = + entryPoint === NftDeployEntryPoint.approve || + entryPoint === NftDeployEntryPoint.set_approval_for_all; + + const title = getEntryPointName(deploy, true); + + if (isBurn) { + return ( + + + + + ); + } + + if (isMint) { + return ( + + + + + ); + } + + if (isTransfer) { + return ( + + + + + + ); + } + + if (isUpdate) { + return ( + + + + ); + } + + if (isApprove) { + return ( + + + + + ); + } + + return ( + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/components/common.tsx b/src/apps/popup/pages/deploy-details/components/common.tsx new file mode 100644 index 000000000..993e5b362 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/common.tsx @@ -0,0 +1,263 @@ +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React, { useCallback } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; +import styled from 'styled-components'; + +import { getBlockExplorerContractUrl } from '@src/constants'; +import { isEqualCaseInsensitive } from '@src/utils'; + +import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; + +import { + AlignedFlexRow, + LeftAlignedFlexColumn, + SpacingSize +} from '@libs/layout'; +import { Link, SvgIcon, Typography } from '@libs/ui/components'; +import { AccountInfoIcon } from '@libs/ui/components/account-info-icon/account-info-icon'; + +const AlignedFlexRowContainer = styled(AlignedFlexRow)` + column-gap: 8px; + flex-wrap: wrap; +`; + +export const NftIndexContainer = styled.div` + padding: 0 6px; + background: ${({ theme }) => theme.color.backgroundSecondary}; + max-width: 296px; +`; + +interface ContainerProps { + title: string; + children: React.ReactNode; +} + +export const SimpleContainer = ({ title, children }: ContainerProps) => ( + + {title} + {children} + +); + +interface ActionContainerWithAmountProps { + title: string; + children: React.ReactNode; + amount: string; + fiatAmount: string; +} + +export const ContainerWithAmount = ({ + title, + children, + amount, + fiatAmount +}: ActionContainerWithAmountProps) => ( + + + {title} + {amount} + + CSPR + + + {`(${fiatAmount})`} + + + {children} + +); + +interface ActionContainerWithLinkProps { + title: string; + children: React.ReactNode; + contractName: string; + contractIcon: string; + contractPackageHash: string; +} + +export const ActionContainerWithLink = ({ + title, + children, + contractName, + contractIcon, + contractPackageHash +}: ActionContainerWithLinkProps) => { + const { casperLiveUrl } = useSelector(selectApiConfigBasedOnActiveNetwork); + + const link = getBlockExplorerContractUrl( + casperLiveUrl, + contractPackageHash || '' + ); + + return ( + + + {title} + + + {contractName} + + + {children} + + ); +}; + +interface NftInfoRowProps { + nftTokenIds: string[]; + label?: string; + contractName?: string; + imgLogo?: Maybe; + publicKey?: string; + isApprove?: boolean; + defaultSvg?: string; +} + +export const NftInfoRow = ({ + nftTokenIds, + imgLogo, + contractName, + label, + publicKey, + isApprove, + defaultSvg +}: NftInfoRowProps) => { + const { t } = useTranslation(); + + const { csprStudioCep47ContractHash, casperLiveUrl } = useSelector( + selectApiConfigBasedOnActiveNetwork + ); + + const link = getBlockExplorerContractUrl(casperLiveUrl, publicKey || ''); + + const getCollectionName = useCallback(() => { + if ( + publicKey && + isEqualCaseInsensitive(publicKey, csprStudioCep47ContractHash) + ) { + return 'CSPR.studio'; + } + + return contractName; + }, [publicKey, contractName, csprStudioCep47ContractHash]); + + return ( + + {label && ( + + {label} + + )} + {nftTokenIds.length > 1 && ( + + all + + )} + + + {getCollectionName()} + + + {isApprove || nftTokenIds.length > 1 ? 'NFT(s)' : 'NFT'} + + {nftTokenIds.map(id => ( + + + {id} + + + ))} + + ); +}; + +interface AmountRowProps { + label?: string; + amount: string; + symbol: string; + fiatAmount?: string; +} + +export const AmountRow = ({ + label, + amount, + symbol, + fiatAmount +}: AmountRowProps) => { + const { t } = useTranslation(); + + return ( + + {label && ( + + {label} + + )} + {amount} + + {symbol} + + {fiatAmount && ( + + {`(${fiatAmount})`} + + )} + + ); +}; + +interface ContractInfoRowProps { + publicKey: string; + contractName: string; + iconUrl?: Maybe; + label?: string; + additionalInfo?: string; + defaultSvg?: string; +} + +export const ContractInfoRow = ({ + publicKey, + contractName, + label, + additionalInfo, + iconUrl, + defaultSvg +}: ContractInfoRowProps) => { + const { t } = useTranslation(); + + const { casperLiveUrl } = useSelector(selectApiConfigBasedOnActiveNetwork); // Fetch the live Casper network URL from Redux store. // Assuming 'publicKey' is the public key of the contract. // Replace 'casperLiveUrl' with the actual live Casper network URL. // Fetch the contract details using the public key. // Display the contract name, icon, and additional information. // If the contract details are not found, display a + + const link = getBlockExplorerContractUrl(casperLiveUrl, publicKey || ''); + + return ( + + {label && ( + + {label} + + )} + + + {contractName} + + {additionalInfo && ( + + {additionalInfo} + + )} + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/components/deploy-details-action.tsx b/src/apps/popup/pages/deploy-details/components/deploy-details-action.tsx new file mode 100644 index 000000000..37c59748d --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/deploy-details-action.tsx @@ -0,0 +1,153 @@ +import { IDeploy } from 'casper-wallet-core'; +import { + isAssociatedKeysDeploy, + isAuctionDeploy, + isCasperMarketDeploy, + isCep18Deploy, + isNativeCsprDeploy, + isNftDeploy, + isWasmDeployExecutionType +} from 'casper-wallet-core/src/utils/deploy'; +import React from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +import { AssociatedActionRows } from '@popup/pages/deploy-details/components/action-rows/associated-action-rows'; +import { AuctionActionRows } from '@popup/pages/deploy-details/components/action-rows/auction-action-rows'; +import { Cep18ActionRows } from '@popup/pages/deploy-details/components/action-rows/cep18-action-rows'; +import { CsprMarketActionRows } from '@popup/pages/deploy-details/components/action-rows/cspr-market-action-rows'; +import { DefaultActionRows } from '@popup/pages/deploy-details/components/action-rows/default-action-rows'; +import { NativeTransferActionRows } from '@popup/pages/deploy-details/components/action-rows/native-transfer-action-rows'; +import { NftActionsRows } from '@popup/pages/deploy-details/components/action-rows/nft-actions-rows'; +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { + AlignedSpaceBetweenFlexRow, + BorderBottomPseudoElementProps, + FlexColumn, + borderBottomPseudoElementRules +} from '@libs/layout'; +import { Tile, Typography } from '@libs/ui/components'; + +const RowsContainer = styled(FlexColumn)` + margin-top: 16px; + + & > *:not(:last-child) { + ${borderBottomPseudoElementRules}; + } + + & > *:first-child { + padding: 8px 0; + } +`; + +const RowContainer = styled(AlignedSpaceBetweenFlexRow)` + padding: 16px; +`; + +interface ActionProps { + deploy: IDeploy; +} + +const Container = ({ children }: { children: React.ReactNode }) => { + const { t } = useTranslation(); + + return ( + + + + Action + + {children} + + + ); +}; + +export const DeployDetailsAction = ({ deploy }: ActionProps) => { + const title = getEntryPointName(deploy, true); + + if (isNativeCsprDeploy(deploy)) { + return ( + + + + ); + } + + if (isWasmDeployExecutionType(deploy)) { + return ( + + {title} + + ); + } + + if (isAuctionDeploy(deploy)) { + return ( + + + + ); + } + + if (isAssociatedKeysDeploy(deploy)) { + return ( + + + + ); + } + + if (isCasperMarketDeploy(deploy)) { + return ( + + + + ); + } + + if (isCep18Deploy(deploy)) { + return ( + + + + ); + } + + if (isNftDeploy(deploy)) { + return ( + + + + ); + } + + return ( + + + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/components/deploy-details-result.tsx b/src/apps/popup/pages/deploy-details/components/deploy-details-result.tsx new file mode 100644 index 000000000..5b20b34b4 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/deploy-details-result.tsx @@ -0,0 +1,126 @@ +import { IDeploy } from 'casper-wallet-core'; +import { + isAssociatedKeysDeploy, + isCasperMarketDeploy, + isCep18Deploy, + isNftDeploy +} from 'casper-wallet-core/src/utils/deploy'; +import React from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import styled from 'styled-components'; + +import { AssociatedResultRows } from '@popup/pages/deploy-details/components/result-rows/associated-result-rows'; +import { Cep18ResultRows } from '@popup/pages/deploy-details/components/result-rows/cep18-result-rows'; +import { NativeTransferResultRows } from '@popup/pages/deploy-details/components/result-rows/native-transfer-result-rows'; +import { NftResultRows } from '@popup/pages/deploy-details/components/result-rows/nft-result-rows'; + +import { + BorderBottomPseudoElementProps, + FlexColumn, + borderBottomPseudoElementRules +} from '@libs/layout'; +import { Status, Tile, Typography, getDeployStatus } from '@libs/ui/components'; + +const RowsContainer = styled(FlexColumn)` + margin: 0; + + & > *:not(:last-child) { + padding: 16px 16px 16px 0; + ${borderBottomPseudoElementRules}; + } + + & > *:first-child { + padding: 8px 0; + } + + & > *:last-child { + padding: 16px 16px 16px + ${({ marginLeftForSeparatorLine }) => marginLeftForSeparatorLine}px; + } +`; + +const Container = ({ children }: { children: React.ReactNode }) => { + const { t } = useTranslation(); + + return ( + + + + Results + + {children} + + + ); +}; + +interface DeployDetailsResultProps { + deploy: IDeploy; +} + +export const DeployDetailsResult = ({ deploy }: DeployDetailsResultProps) => { + const deployStatus = getDeployStatus(deploy); + + if (deployStatus === Status.Error) { + return null; + } + + if (isAssociatedKeysDeploy(deploy)) { + return ( + + + + ); + } + + if (deploy.transfersActionsResult.length) { + return ( + + {deploy?.transfersActionsResult.map((action, id) => ( + + ))} + + ); + } + + if ( + (isNftDeploy(deploy) || isCasperMarketDeploy(deploy)) && + deploy.nftActionsResult.length + ) { + return ( + + {deploy.nftActionsResult.map((action, id) => ( + + ))} + + ); + } + + if (isCep18Deploy(deploy) && deploy.cep18ActionsResult.length) { + return ( + + {deploy.cep18ActionsResult.map((action, id) => ( + + ))} + + ); + } + + return null; +}; diff --git a/src/apps/popup/pages/deploy-details/components/result-rows/associated-result-rows.tsx b/src/apps/popup/pages/deploy-details/components/result-rows/associated-result-rows.tsx new file mode 100644 index 000000000..ca5a4e303 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/result-rows/associated-result-rows.tsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import { SimpleContainer } from '@popup/pages/deploy-details/components/common'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface AssociatedResultRowsProps { + publicKey: string; +} + +export const AssociatedResultRows = ({ + publicKey +}: AssociatedResultRowsProps) => ( + + + + + +); diff --git a/src/apps/popup/pages/deploy-details/components/result-rows/cep18-result-rows.tsx b/src/apps/popup/pages/deploy-details/components/result-rows/cep18-result-rows.tsx new file mode 100644 index 000000000..47a19bba2 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/result-rows/cep18-result-rows.tsx @@ -0,0 +1,138 @@ +import { ICep18ActionsResult } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { + Cep18DeployEntryPoint, + DeployIcon, + DeployResultEntryPointNameMap +} from '@src/constants'; + +import { + AmountRow, + ContractInfoRow, + SimpleContainer +} from '@popup/pages/deploy-details/components/common'; + +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface Cep18ResultRowsProps { + action: ICep18ActionsResult; + contractPackageHash: string; +} + +export const Cep18ResultRows = ({ + action, + contractPackageHash +}: Cep18ResultRowsProps) => { + const { + entryPoint, + formattedDecimalAmount, + symbol, + recipientKey, + callerPublicKey, + contractName, + iconUrl + } = action; + const isTransfer = entryPoint === Cep18DeployEntryPoint.transfer; + const isMint = entryPoint === Cep18DeployEntryPoint.mint; + const isBurn = entryPoint === Cep18DeployEntryPoint.burn; + const isApprove = entryPoint === Cep18DeployEntryPoint.approve; + + const title = DeployResultEntryPointNameMap[action.entryPoint]; + + if (isApprove) { + return ( + + + + + + ); + } + + if (isBurn) { + return ( + + + + + + ); + } + + if (isMint) { + return ( + + + + + + ); + } + + if (isTransfer) { + return ( + + + + + + + ); + } + + return null; +}; diff --git a/src/apps/popup/pages/deploy-details/components/result-rows/native-transfer-result-rows.tsx b/src/apps/popup/pages/deploy-details/components/result-rows/native-transfer-result-rows.tsx new file mode 100644 index 000000000..321808a6c --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/result-rows/native-transfer-result-rows.tsx @@ -0,0 +1,46 @@ +import { IAccountInfo } from 'casper-wallet-core/src/domain/accountInfo'; +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React from 'react'; + +import { ContainerWithAmount } from '@popup/pages/deploy-details/components/common'; + +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface NativeTransferResultRowsProps { + amount: string; + toPublicKey: string; + fromPublicKey: string; + fiatAmount: string; + callerAccountInfo: Maybe; + recipientAccountInfo: Maybe; +} + +export const NativeTransferResultRows = ({ + amount, + toPublicKey, + fromPublicKey, + fiatAmount, + callerAccountInfo, + recipientAccountInfo +}: NativeTransferResultRowsProps) => ( + + + + +); diff --git a/src/apps/popup/pages/deploy-details/components/result-rows/nft-result-rows.tsx b/src/apps/popup/pages/deploy-details/components/result-rows/nft-result-rows.tsx new file mode 100644 index 000000000..ab888eefa --- /dev/null +++ b/src/apps/popup/pages/deploy-details/components/result-rows/nft-result-rows.tsx @@ -0,0 +1,155 @@ +import { INftActionsResult } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { + DeployIcon, + DeployResultEntryPointNameMap, + NftDeployEntryPoint +} from '@src/constants'; + +import { + ContractInfoRow, + NftInfoRow, + SimpleContainer +} from '@popup/pages/deploy-details/components/common'; + +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; + +interface NftResultRowsProps { + action: INftActionsResult; + contractPackageHash: string; +} + +export const NftResultRows = ({ + action, + contractPackageHash +}: NftResultRowsProps) => { + const { + entryPoint, + nftTokenIds, + recipientKey, + callerPublicKey, + contractName, + iconUrl, + recipientAccountInfo, + callerAccountInfo + } = action; + + const isBurn = entryPoint === NftDeployEntryPoint.burn; + const isMint = entryPoint === NftDeployEntryPoint.mint; + const isTransfer = entryPoint === NftDeployEntryPoint.transfer; + const isUpdate = entryPoint === NftDeployEntryPoint.update_token_meta; + const isApprove = + entryPoint === NftDeployEntryPoint.approve || + entryPoint === NftDeployEntryPoint.set_approval_for_all; + + const title = DeployResultEntryPointNameMap[action.entryPoint]; + + if (isBurn) { + return ( + + + + + ); + } + + if (isMint) { + return ( + + + + + ); + } + + if (isTransfer) { + return ( + + + + + + ); + } + + if (isUpdate) { + return ( + + + + ); + } + + if (isApprove) { + return ( + + + + + ); + } + + return null; +}; diff --git a/src/apps/popup/pages/deploy-details/content.tsx b/src/apps/popup/pages/deploy-details/content.tsx new file mode 100644 index 000000000..eac6ffefa --- /dev/null +++ b/src/apps/popup/pages/deploy-details/content.tsx @@ -0,0 +1,180 @@ +import { IDeploy } from 'casper-wallet-core'; +import React, { useEffect, useState } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; +import styled from 'styled-components'; + +import { DeployDetailsAction } from '@popup/pages/deploy-details/components/deploy-details-action'; +import { DeployDetailsResult } from '@popup/pages/deploy-details/components/deploy-details-result'; +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; + +import { + AlignedSpaceBetweenFlexRow, + BorderBottomPseudoElementProps, + ContentContainer, + FlexColumn, + FlexRow, + ParagraphContainer, + RightAlignedFlexColumn, + SpaceBetweenFlexRow, + SpacingSize, + borderBottomPseudoElementRules +} from '@libs/layout'; +import { dispatchFetchExtendedDeploysInfo } from '@libs/services/account-activity-service'; +import { + DeployStatus, + Hash, + HashVariant, + Tile, + Typography +} from '@libs/ui/components'; +import { formatShortTimestamp } from '@libs/ui/utils'; + +const TitleContainer = styled(SpaceBetweenFlexRow)` + align-items: end; +`; + +const RowsContainer = styled(FlexColumn)` + margin-top: 12px; + + & > *:not(:last-child) { + ${borderBottomPseudoElementRules}; + } + + & > *:last-child { + padding-left: ${({ marginLeftForSeparatorLine }) => + marginLeftForSeparatorLine}px; + } +`; + +const RowContainer = styled(AlignedSpaceBetweenFlexRow)<{ + withTwoRows?: boolean; +}>` + padding: ${({ withTwoRows }) => + withTwoRows ? '12px 16px 12px 0' : '16px 16px 16px 0'}; +`; + +interface DeployDetailsPageContentProps { + deploy?: IDeploy; +} + +export const DeployDetailsPageContent = ({ + deploy +}: DeployDetailsPageContentProps) => { + const [singleDeploy, setSingleDeploy] = useState( + null + ); + + const { t } = useTranslation(); + + const activeAccount = useSelector(selectVaultActiveAccount); + // const activeAccount = { + // publicKey: + // '0203b9b4cd6085590b68bfccaf7ea1744766e5225928beba99155a1bd79870f7a984' + // }; + + useEffect(() => { + setSingleDeploy(deploy); + }, [deploy]); + + useEffect(() => { + if (deploy?.deployHash && activeAccount?.publicKey) { + dispatchFetchExtendedDeploysInfo( + deploy.deployHash, + activeAccount?.publicKey + ).then(({ payload: resp }) => { + setSingleDeploy(resp); + }); + } + }, [activeAccount?.publicKey, deploy?.deployHash]); + + if (!singleDeploy) { + return null; + } + + const deployName = getEntryPointName(singleDeploy, true); + + return ( + + + + + {deployName} + + + + + + + + + + + Deploy hash + + + + + + Timestamp + + + {formatShortTimestamp(singleDeploy.timestamp)} + + + + + Payment amount + + + + + {singleDeploy.formattedPaymentAmount} + + + CSPR + + + + {singleDeploy.fiatPaymentAmount} + + + + + + Cost + + + + + {singleDeploy.formattedCost} + + + CSPR + + + + {singleDeploy.fiatCost} + + + + + + + ); +}; diff --git a/src/apps/popup/pages/deploy-details/index.tsx b/src/apps/popup/pages/deploy-details/index.tsx new file mode 100644 index 000000000..003aa0b99 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/index.tsx @@ -0,0 +1,52 @@ +import React from 'react'; + +import { DeployDetailsPageContent } from '@popup/pages/deploy-details/content'; +import { RouterPath, useTypedLocation, useTypedNavigate } from '@popup/router'; + +import { + HeaderPopup, + HeaderSubmenuBarNavLink, + HeaderViewInExplorer, + PopupLayout +} from '@libs/layout'; +import { HomePageTabsId } from '@libs/ui/components'; + +export const DeployDetailsPage = () => { + const location = useTypedLocation(); + const navigate = useTypedNavigate(); + + const { deploy, navigateHome } = location.state; + + return ( + ( + ( + <> + { + navigate(RouterPath.Home, { + state: { + // set the active tab to deploys + activeTabId: HomePageTabsId.Deploys + } + }); + } + : undefined + } + /> + + + )} + /> + )} + renderContent={() => } + /> + ); +}; diff --git a/src/apps/popup/pages/deploy-details/utils.ts b/src/apps/popup/pages/deploy-details/utils.ts new file mode 100644 index 000000000..439c8c7f9 --- /dev/null +++ b/src/apps/popup/pages/deploy-details/utils.ts @@ -0,0 +1,23 @@ +import { IDeploy } from 'casper-wallet-core'; + +import { + DeployActionEntryPointNameMap, + DeployPlateEntryPointNameMap, + ExecutionTypesMap +} from '@src/constants'; + +export const getEntryPointName = (deploy: IDeploy, isAction?: boolean) => { + if (deploy?.type === 'CSPR_NATIVE') { + return 'Transfer'; + } else if (deploy?.type === 'ASSOCIATED_KEYS') { + return 'Update account'; + } + + const entryPointName = deploy?.entryPoint + ? isAction + ? DeployActionEntryPointNameMap[deploy.entryPoint] + : DeployPlateEntryPointNameMap[deploy.entryPoint] + : ExecutionTypesMap[deploy.executionTypeId ?? 2]; + + return entryPointName ?? deploy?.entryPoint; +}; diff --git a/src/apps/popup/pages/home/components/deploys-list/index.tsx b/src/apps/popup/pages/home/components/deploys-list/index.tsx index 9cff364f9..381fb6456 100644 --- a/src/apps/popup/pages/home/components/deploys-list/index.tsx +++ b/src/apps/popup/pages/home/components/deploys-list/index.tsx @@ -1,34 +1,25 @@ import React, { useEffect } from 'react'; import useInfiniteScroll from 'react-infinite-scroll-hook'; -import { useSelector } from 'react-redux'; - -import { selectAccountDeploys } from '@background/redux/account-info/selectors'; - -import { useFetchAccountDeploys } from '@hooks/use-fetch-account-deploys'; -import { useMapAccountDeploysListWithPendingTransactions } from '@hooks/use-map-account-deploys-list-with-pending-transactions'; import { SpacingSize } from '@libs/layout'; -import { - AccountActivityPlate, - List, - LoadingActivityView, - NoActivityView -} from '@libs/ui/components'; +import { useFetchDeploys } from '@libs/services/deploys'; +import { List, LoadingActivityView, NoActivityView } from '@libs/ui/components'; +import { DeployPlate } from '@libs/ui/components/deploy-plate/deploy-plate'; export const DeploysList = () => { - const { loadMoreDeploys, loading, hasNextPage } = useFetchAccountDeploys(); + const { + deploys, + isDeploysLoading, + fetchDeploysNextPage, + hasDeploysNextPage + } = useFetchDeploys(); const [sentryRef] = useInfiniteScroll({ - loading, - hasNextPage, - onLoadMore: loadMoreDeploys, + loading: isDeploysLoading, + hasNextPage: hasDeploysNextPage, + onLoadMore: fetchDeploysNextPage, delayInMs: 0 }); - const accountDeploysList = useSelector(selectAccountDeploys); - - const { accountDeploysListWithPendingTransactions } = - useMapAccountDeploysListWithPendingTransactions(accountDeploysList); - useEffect(() => { const container = document.querySelector('#ms-container'); @@ -53,32 +44,28 @@ export const DeploysList = () => { return ( <> - {accountDeploysListWithPendingTransactions != null && - accountDeploysListWithPendingTransactions?.length > 0 && ( - ( - - )} - marginLeftForItemSeparatorLine={54} - /> - )} + {deploys != null && deploys?.length > 0 && ( + ( + + )} + marginLeftForItemSeparatorLine={54} + /> + )} - {(loading || hasNextPage) && } + {(isDeploysLoading || hasDeploysNextPage) && ( + + )} - {(accountDeploysListWithPendingTransactions == null || - accountDeploysListWithPendingTransactions.length === 0) && - !loading && ( - - )} + {(deploys == null || deploys.length === 0) && !isDeploysLoading && ( + + )} ); }; diff --git a/src/apps/popup/pages/nft-details/content.tsx b/src/apps/popup/pages/nft-details/content.tsx index e2bb53b6b..77f6257ad 100644 --- a/src/apps/popup/pages/nft-details/content.tsx +++ b/src/apps/popup/pages/nft-details/content.tsx @@ -19,6 +19,7 @@ import { RouterPath, useTypedNavigate } from '@popup/router'; import { accountTrackingIdOfSentNftTokensRemoved } from '@background/redux/account-info/actions'; import { selectAccountTrackingIdOfSentNftTokens } from '@background/redux/account-info/selectors'; import { dispatchToMainStore } from '@background/redux/utils'; +import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; import { useAsyncEffect } from '@hooks/use-async-effect'; @@ -110,6 +111,7 @@ export const NftDetailsContent = ({ const accountTrackingIdOfSentNftTokens = useSelector( selectAccountTrackingIdOfSentNftTokens ); + const activeAccount = useSelector(selectVaultActiveAccount); const isButtonDisabled = Boolean( accountTrackingIdOfSentNftTokens[nftToken?.tracking_id!] @@ -145,7 +147,10 @@ export const NftDetailsContent = ({ const interval = setInterval(async () => { const { payload: extendedDeployInfo } = - await dispatchFetchExtendedDeploysInfo(deployHash); + await dispatchFetchExtendedDeploysInfo( + deployHash, + activeAccount?.publicKey! + ); if (extendedDeployInfo) { if (extendedDeployInfo.status === Status.Executed) { @@ -159,7 +164,11 @@ export const NftDetailsContent = ({ }, 10000); return () => clearInterval(interval); - }, [accountTrackingIdOfSentNftTokens, nftToken?.tracking_id]); + }, [ + accountTrackingIdOfSentNftTokens, + activeAccount?.publicKey, + nftToken?.tracking_id + ]); const tokenStandard = nftToken ? MapNFTTokenStandardToName[nftToken.token_standard_id] diff --git a/src/apps/popup/pages/sign-with-ledger-in-new-window/index.tsx b/src/apps/popup/pages/sign-with-ledger-in-new-window/index.tsx index 8f3b04e16..455d052a4 100644 --- a/src/apps/popup/pages/sign-with-ledger-in-new-window/index.tsx +++ b/src/apps/popup/pages/sign-with-ledger-in-new-window/index.tsx @@ -2,8 +2,7 @@ import { DeployUtil } from 'casper-js-sdk'; import React, { useState } from 'react'; import { useSelector } from 'react-redux'; -import { fetchAndDispatchExtendedDeployInfo } from '@src/utils'; - +import { accountPendingDeployHashesChanged } from '@background/redux/account-info/actions'; import { selectLedgerDeploy, selectLedgerRecipientToSaveOnSuccess @@ -55,7 +54,9 @@ export const SignWithLedgerInNewWindowPage = () => { } if ('result' in resp) { - fetchAndDispatchExtendedDeployInfo(resp.result.deploy_hash); + dispatchToMainStore( + accountPendingDeployHashesChanged(resp.result.deploy_hash) + ); } setIsSuccess(true); diff --git a/src/apps/popup/pages/stakes/index.tsx b/src/apps/popup/pages/stakes/index.tsx index 42c97f58b..bb1b32d65 100644 --- a/src/apps/popup/pages/stakes/index.tsx +++ b/src/apps/popup/pages/stakes/index.tsx @@ -9,7 +9,6 @@ import { STAKE_COST_MOTES, StakeSteps } from '@src/constants'; -import { fetchAndDispatchExtendedDeployInfo } from '@src/utils'; import { AmountStep } from '@popup/pages/stakes/amount-step'; import { ConfirmStep } from '@popup/pages/stakes/confirm-step'; @@ -24,6 +23,7 @@ import { import { ValidatorDropdownInput } from '@popup/pages/stakes/validator-dropdown-input'; import { RouterPath, useTypedNavigate } from '@popup/router'; +import { accountPendingDeployHashesChanged } from '@background/redux/account-info/actions'; import { selectAccountBalance } from '@background/redux/account-info/selectors'; import { ledgerDeployChanged } from '@background/redux/ledger/actions'; import { @@ -180,7 +180,9 @@ export const StakesPage = () => { sendSignDeploy(signedDeploy, nodeUrl) .then(resp => { if ('result' in resp) { - fetchAndDispatchExtendedDeployInfo(resp.result.deploy_hash); + dispatchToMainStore( + accountPendingDeployHashesChanged(resp.result.deploy_hash) + ); setStakeStep(StakeSteps.Success); } else { diff --git a/src/apps/popup/pages/token-details/content.tsx b/src/apps/popup/pages/token-details/content.tsx index 2074b8c47..0fa17c1f9 100644 --- a/src/apps/popup/pages/token-details/content.tsx +++ b/src/apps/popup/pages/token-details/content.tsx @@ -9,8 +9,8 @@ import { } from '@libs/layout'; import { ContractPackageWithBalance } from '@libs/services/erc20-service'; import { - CasperTokenActivityList, - Erc20TokenActivityList, + CasperTokenTransferDeploysList, + Cep18TokenDeploysList, Typography } from '@libs/ui/components'; @@ -41,9 +41,9 @@ export const TokenPageContent: React.FC = ({ {tokenName === 'Casper' ? ( - + ) : ( - + )} ); diff --git a/src/apps/popup/pages/transfer-nft/index.tsx b/src/apps/popup/pages/transfer-nft/index.tsx index 3a5b4ba7c..ad7f190e3 100644 --- a/src/apps/popup/pages/transfer-nft/index.tsx +++ b/src/apps/popup/pages/transfer-nft/index.tsx @@ -4,10 +4,7 @@ import { Trans, useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { useParams } from 'react-router-dom'; -import { - MapNFTTokenStandardToName, - fetchAndDispatchExtendedDeployInfo -} from '@src/utils'; +import { MapNFTTokenStandardToName } from '@src/utils'; import { TransferNFTSteps, @@ -16,7 +13,10 @@ import { } from '@popup/pages/transfer-nft/utils'; import { RouterPath, useTypedLocation, useTypedNavigate } from '@popup/router'; -import { accountTrackingIdOfSentNftTokensChanged } from '@background/redux/account-info/actions'; +import { + accountPendingDeployHashesChanged, + accountTrackingIdOfSentNftTokensChanged +} from '@background/redux/account-info/actions'; import { selectAccountBalance, selectAccountNftTokens @@ -203,7 +203,7 @@ export const TransferNftPage = () => { }) ); - fetchAndDispatchExtendedDeployInfo(deployHash); + dispatchToMainStore(accountPendingDeployHashesChanged(deployHash)); setTransferNFTStep(TransferNFTSteps.Success); } else { diff --git a/src/apps/popup/pages/transfer/index.tsx b/src/apps/popup/pages/transfer/index.tsx index 24955ad32..f896a7900 100644 --- a/src/apps/popup/pages/transfer/index.tsx +++ b/src/apps/popup/pages/transfer/index.tsx @@ -5,10 +5,10 @@ import { useSelector } from 'react-redux'; import styled from 'styled-components'; import { ERC20_PAYMENT_AMOUNT_AVERAGE_MOTES } from '@src/constants'; -import { fetchAndDispatchExtendedDeployInfo } from '@src/utils'; import { RouterPath, useTypedLocation, useTypedNavigate } from '@popup/router'; +import { accountPendingDeployHashesChanged } from '@background/redux/account-info/actions'; import { selectAllPublicKeys } from '@background/redux/contacts/selectors'; import { ledgerDeployChanged, @@ -165,7 +165,9 @@ export const TransferPage = () => { dispatchToMainStore(recipientPublicKeyAdded(recipientPublicKey)); if ('result' in resp) { - fetchAndDispatchExtendedDeployInfo(resp.result.deploy_hash); + dispatchToMainStore( + accountPendingDeployHashesChanged(resp.result.deploy_hash) + ); setTransferStep(TransactionSteps.Success); } else { diff --git a/src/apps/popup/router/paths.ts b/src/apps/popup/router/paths.ts index 4778a5822..23bb70415 100644 --- a/src/apps/popup/router/paths.ts +++ b/src/apps/popup/router/paths.ts @@ -14,7 +14,6 @@ export enum RouterPath { BackupSecretPhrase = '/backup-secret-phrase', DownloadAccountKeys = '/download-account-keys', Transfer = '/transfer', - ActivityDetails = '/activity-details', Token = '/token/:tokenName', Receive = '/receive', NftDetails = '/nft-details/:contractPackageHash/nfts/:tokenId', @@ -32,5 +31,6 @@ export enum RouterPath { ImportAccountFromTorus = '/import-account-from-torus', BuyCSPR = '/buy-cspr', ImportAccountFromLedger = '/import-account-from-ledger', - SignWithLedgerInNewWindow = '/sign-with-ledger-in-new-window' + SignWithLedgerInNewWindow = '/sign-with-ledger-in-new-window', + DeployDetails = '/deploys-details' } diff --git a/src/apps/popup/router/types.ts b/src/apps/popup/router/types.ts index 1d624bf6a..cb8db1ff4 100644 --- a/src/apps/popup/router/types.ts +++ b/src/apps/popup/router/types.ts @@ -1,4 +1,4 @@ -import { ActivityType } from '@src/constants'; +import { IDeploy } from 'casper-wallet-core'; import { TokenType } from '@hooks/use-casper-token'; @@ -6,15 +6,6 @@ import { ErrorLocationState } from '@libs/layout/error/types'; export interface LocationState extends ErrorLocationState { showNavigationMenu?: boolean; - activityDetailsData?: { - fromAccount: string; - toAccount: string; - deployHash: string; - type: ActivityType | null; - amount?: string; - symbol?: string; - isDeploysList?: boolean; - }; activeTabId?: number; tokenData?: TokenType | null; nftData?: { @@ -22,4 +13,6 @@ export interface LocationState extends ErrorLocationState { url?: string; }; recipientPublicKey?: string; + deploy?: IDeploy; + navigateHome?: boolean; } diff --git a/src/assets/icons/associated-keys.svg b/src/assets/icons/associated-keys.svg new file mode 100644 index 000000000..89fda99c8 --- /dev/null +++ b/src/assets/icons/associated-keys.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/auction.svg b/src/assets/icons/auction.svg new file mode 100644 index 000000000..7e2e9df83 --- /dev/null +++ b/src/assets/icons/auction.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/cep-18-default.svg b/src/assets/icons/cep-18-default.svg new file mode 100644 index 000000000..b71d10588 --- /dev/null +++ b/src/assets/icons/cep-18-default.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/copy.svg b/src/assets/icons/copy.svg index b32b3b9c4..9a9d6afe6 100644 --- a/src/assets/icons/copy.svg +++ b/src/assets/icons/copy.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/icons/cspr-market.svg b/src/assets/icons/cspr-market.svg new file mode 100644 index 000000000..8f702bcce --- /dev/null +++ b/src/assets/icons/cspr-market.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/cspr-studio.svg b/src/assets/icons/cspr-studio.svg new file mode 100644 index 000000000..0866d0562 --- /dev/null +++ b/src/assets/icons/cspr-studio.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/generic.svg b/src/assets/icons/generic.svg new file mode 100644 index 000000000..05dbbdd15 --- /dev/null +++ b/src/assets/icons/generic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/nft-contract-icon.svg b/src/assets/icons/nft-contract-icon.svg index 9dea5d081..60911cd6e 100644 --- a/src/assets/icons/nft-contract-icon.svg +++ b/src/assets/icons/nft-contract-icon.svg @@ -1,4 +1,6 @@ - - - + + + + + diff --git a/src/background/index.ts b/src/background/index.ts index ec02045d3..d3645c896 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,3 +1,4 @@ +import { CasperNetwork } from 'casper-wallet-core/src/domain/common/common'; import { RootAction, getType } from 'typesafe-actions'; import { Tabs, @@ -33,22 +34,19 @@ import { } from '@background/redux/account-balances/actions'; import { accountBalanceChanged, - accountCasperActivityChanged, accountCasperActivityCountChanged, - accountCasperActivityUpdated, + accountCep18TransferDeploysDataChanged, + accountCsprTransferDeploysDataChanged, accountCurrencyRateChanged, - accountDeploysAdded, accountDeploysCountChanged, - accountDeploysUpdated, + accountDeploysDataChanged, accountErc20Changed, - accountErc20TokensActivityChanged, - accountErc20TokensActivityUpdated, accountInfoReset, accountNftTokensAdded, accountNftTokensCountChanged, accountNftTokensUpdated, - accountPendingTransactionsChanged, - accountPendingTransactionsRemove, + accountPendingDeployHashesChanged, + accountPendingDeployHashesRemove, accountTrackingIdOfSentNftTokensChanged, accountTrackingIdOfSentNftTokensRemoved } from '@background/redux/account-info/actions'; @@ -115,9 +113,6 @@ import { sdkEvent } from '@content/sdk-event'; import { SdkMethod, isSDKMethod, sdkMethod } from '@content/sdk-method'; import { - MapExtendedDeploy, - MapPaginatedExtendedDeploys, - fetchAccountCasperActivity, fetchAccountExtendedDeploys, fetchExtendedDeploysInfo } from '@libs/services/account-activity-service'; @@ -180,7 +175,10 @@ import { themeModeSettingChanged, vaultSettingsReseted } from './redux/settings/actions'; -import { selectApiConfigBasedOnActiveNetwork } from './redux/settings/selectors'; +import { + selectActiveNetworkSetting, + selectApiConfigBasedOnActiveNetwork +} from './redux/settings/selectors'; import { vaultCipherCreated, vaultCipherReseted @@ -188,6 +186,8 @@ import { import { selectVaultCipherDoesExist } from './redux/vault-cipher/selectors'; import { ServiceMessage, serviceMessage } from './service-message'; import { emitSdkEventToActiveTabsWithOrigin } from './utils'; +// to resolve all repositories +import './wallet-repositories'; // setup default onboarding action async function handleActionClick() { @@ -618,16 +618,13 @@ runtime.onMessage.addListener( case getType(recipientPublicKeyReseted): case getType(accountBalanceChanged): case getType(accountCurrencyRateChanged): - case getType(accountCasperActivityChanged): - case getType(accountCasperActivityUpdated): + case getType(accountCsprTransferDeploysDataChanged): case getType(accountInfoReset): - case getType(accountPendingTransactionsChanged): - case getType(accountPendingTransactionsRemove): + case getType(accountPendingDeployHashesChanged): + case getType(accountPendingDeployHashesRemove): case getType(accountErc20Changed): - case getType(accountErc20TokensActivityChanged): - case getType(accountErc20TokensActivityUpdated): - case getType(accountDeploysAdded): - case getType(accountDeploysUpdated): + case getType(accountCep18TransferDeploysDataChanged): + case getType(accountDeploysDataChanged): case getType(accountNftTokensAdded): case getType(accountNftTokensUpdated): case getType(accountNftTokensCountChanged): @@ -729,16 +726,18 @@ runtime.onMessage.addListener( store.getState() ); + const network = selectActiveNetworkSetting(store.getState()); + try { const data = await fetchExtendedDeploysInfo({ deployHash: action.payload.deployHash, - casperClarityApiUrl + casperClarityApiUrl, + publicKey: action.payload.publicKey, + network: network.toLowerCase() as CasperNetwork }); return sendResponse( - serviceMessage.fetchExtendedDeploysInfoResponse( - MapExtendedDeploy(data) - ) + serviceMessage.fetchExtendedDeploysInfoResponse(data) ); } catch (error) { console.error(error); @@ -808,17 +807,18 @@ runtime.onMessage.addListener( store.getState() ); + const network = selectActiveNetworkSetting(store.getState()); + try { const data = await fetchAccountExtendedDeploys({ casperClarityApiUrl, publicKey: action.payload.publicKey, - page: action.payload.page + page: action.payload.page, + network: network.toLowerCase() as CasperNetwork }); return sendResponse( - serviceMessage.fetchAccountExtendedDeploysResponse( - MapPaginatedExtendedDeploys(data) - ) + serviceMessage.fetchAccountExtendedDeploysResponse(data) ); } catch (error) { console.error(error); @@ -827,27 +827,6 @@ runtime.onMessage.addListener( return; } - case getType(serviceMessage.fetchAccountCasperActivityRequest): { - const { casperClarityApiUrl } = selectApiConfigBasedOnActiveNetwork( - store.getState() - ); - - try { - const data = await fetchAccountCasperActivity({ - casperClarityApiUrl, - accountHash: action.payload.accountHash, - page: action.payload.page - }); - - return sendResponse( - serviceMessage.fetchAccountCasperActivityResponse(data) - ); - } catch (error) { - console.error(error); - } - return; - } - case getType(serviceMessage.fetchNftTokensRequest): { const { casperClarityApiUrl } = selectApiConfigBasedOnActiveNetwork( store.getState() diff --git a/src/background/redux/account-info/actions.ts b/src/background/redux/account-info/actions.ts index b7d13f07d..476ef4115 100644 --- a/src/background/redux/account-info/actions.ts +++ b/src/background/redux/account-info/actions.ts @@ -1,11 +1,11 @@ import { createAction } from 'typesafe-actions'; import { - Erc20TokenActionResult, - ExtendedDeploy, - ExtendedDeployWithId, - TransferResultWithId -} from '@libs/services/account-activity-service/types'; + AccountDeploysDataType, + Cep18TransferDeploysDataType, + CsprTransferDeploysDataType +} from '@background/redux/account-info/types'; + import { AccountBalance } from '@libs/services/balance-service/types'; import { ContractPackageWithBalance } from '@libs/services/erc20-service/types'; import { NFTTokenResult } from '@libs/services/nft-service/types'; @@ -22,47 +22,30 @@ export const accountCurrencyRateChanged = createAction( 'ACCOUNT_CURRENCY_RATE_CHANGED' )(); -export const accountCasperActivityChanged = createAction( - 'ACCOUNT_CASPER_ACTIVITY_CHANGED' -)(); - -export const accountCasperActivityUpdated = createAction( - 'ACCOUNT_CASPER_ACTIVITY_UPDATED' -)(); - -export const accountErc20TokensActivityChanged = createAction( - 'ACCOUNT_ERC20_TOKEN_ACTIVITY_CHANGED' -)<{ - activityList: Erc20TokenActionResult[]; - contractPackageHash: string; - tokenActivityCount: number; -}>(); +export const accountCsprTransferDeploysDataChanged = createAction( + 'ACCOUNT_CSPR_TRANSFER_DEPLOYS_DATA_CHANGED' +)(); -export const accountErc20TokensActivityUpdated = createAction( - 'ACCOUNT_ERC20_TOKEN_ACTIVITY_UPDATED' +export const accountCep18TransferDeploysDataChanged = createAction( + 'ACCOUNT_CEP18_TRANSFER_DEPLOYS_DATA_CHANGED' )<{ - activityList: Erc20TokenActionResult[]; + cep18TransferDeploysData: Cep18TransferDeploysDataType; contractPackageHash: string; - tokenActivityCount: number; }>(); export const accountInfoReset = createAction('ACCOUNT_INFO_RESET')(); -export const accountPendingTransactionsChanged = createAction( - 'ACCOUNT_PENDING_TRANSACTIONS_CHANGED' -)(); +export const accountPendingDeployHashesChanged = createAction( + 'ACCOUNT_PENDING_DEPLOY_HASHES_CHANGED' +)(); -export const accountPendingTransactionsRemove = createAction( +export const accountPendingDeployHashesRemove = createAction( 'ACCOUNT_PENDING_TRANSACTIONS_REMOVE' )(); -export const accountDeploysAdded = createAction('ACCOUNT_DEPLOYS_ADDED')< - ExtendedDeployWithId[] | null ->(); - -export const accountDeploysUpdated = createAction('ACCOUNT_DEPLOYS_UPDATED')< - ExtendedDeployWithId[] ->(); +export const accountDeploysDataChanged = createAction( + 'ACCOUNT_DEPLOYS_DATA_CHANGED' +)(); export const accountNftTokensAdded = createAction('ACCOUNT_NFT_TOKENS_ADDED')< NFTTokenResult[] | null diff --git a/src/background/redux/account-info/reducer.ts b/src/background/redux/account-info/reducer.ts index dd73e2981..a652a3386 100644 --- a/src/background/redux/account-info/reducer.ts +++ b/src/background/redux/account-info/reducer.ts @@ -1,23 +1,22 @@ import { createReducer } from 'typesafe-actions'; +import { isEqualCaseInsensitive } from '@src/utils'; + import { accountBalanceChanged, - accountCasperActivityChanged, accountCasperActivityCountChanged, - accountCasperActivityUpdated, + accountCep18TransferDeploysDataChanged, + accountCsprTransferDeploysDataChanged, accountCurrencyRateChanged, - accountDeploysAdded, accountDeploysCountChanged, - accountDeploysUpdated, + accountDeploysDataChanged, accountErc20Changed, - accountErc20TokensActivityChanged, - accountErc20TokensActivityUpdated, accountInfoReset, accountNftTokensAdded, accountNftTokensCountChanged, accountNftTokensUpdated, - accountPendingTransactionsChanged, - accountPendingTransactionsRemove, + accountPendingDeployHashesChanged, + accountPendingDeployHashesRemove, accountTrackingIdOfSentNftTokensChanged, accountTrackingIdOfSentNftTokensRemoved } from './actions'; @@ -32,11 +31,11 @@ const initialState: AccountInfoState = { totalBalanceFiat: null }, currencyRate: null, - accountCasperActivity: [], - accountErc20TokensActivity: null, - pendingTransactions: [], + csprTransferDeploysData: null, + cep18TransferDeploysData: null, + pendingDeployHashes: [], erc20Tokens: [], - accountDeploys: [], + accountDeploysData: null, accountNftTokens: [], nftTokensCount: 0, accountDeploysCount: 0, @@ -65,94 +64,162 @@ export const reducer = createReducer(initialState) }) ) .handleAction( - accountCasperActivityChanged, - (state, { payload }): AccountInfoState => ({ - ...state, - accountCasperActivity: payload - }) - ) - .handleAction(accountCasperActivityUpdated, (state, { payload }) => ({ - ...state, - accountCasperActivity: - state.accountCasperActivity != null - ? [...state.accountCasperActivity, ...payload] - : payload - })) - .handleAction( - accountErc20TokensActivityChanged, - ( - state, - { payload: { contractPackageHash, activityList, tokenActivityCount } } - ) => ({ - ...state, - accountErc20TokensActivity: { - ...state.accountErc20TokensActivity, - [contractPackageHash]: { - tokenActivityCount, - tokenActivityList: activityList - } + accountCsprTransferDeploysDataChanged, + (state, { payload }): AccountInfoState => { + const csprTransferDeploysData = state.csprTransferDeploysData; + + if ( + payload && + csprTransferDeploysData && + payload.pages[0].itemCount > csprTransferDeploysData.pages[0].itemCount + ) { + return { + ...state, + csprTransferDeploysData: payload + }; } - }) + + if ( + payload && + csprTransferDeploysData?.pageParams && + payload.pageParams.length < csprTransferDeploysData.pageParams.length + ) { + const updatedDeploysData = { ...csprTransferDeploysData }; + + payload.pageParams.forEach((pageParam, index) => { + const element = csprTransferDeploysData?.pageParams.find( + el => el === pageParam + ); + if (!element) { + updatedDeploysData.pageParams.push(pageParam); + updatedDeploysData.pages.push(payload.pages[index]); + } + }); + + return { + ...state, + csprTransferDeploysData: updatedDeploysData + }; + } + + return { + ...state, + csprTransferDeploysData: payload + }; + } ) .handleAction( - accountErc20TokensActivityUpdated, + accountCep18TransferDeploysDataChanged, ( state, - { payload: { activityList, contractPackageHash, tokenActivityCount } } + { + payload: { cep18TransferDeploysData: payloadData, contractPackageHash } + } ) => { - const tokensActivity = state.accountErc20TokensActivity || {}; + const cep18TransferDeploysData = state.cep18TransferDeploysData || {}; + const deploy = cep18TransferDeploysData[contractPackageHash]; + + if ( + payloadData && + deploy && + payloadData.pages[0].itemCount > deploy.pages[0].itemCount + ) { + return { + ...state, + cep18TransferDeploysData: { + ...state.cep18TransferDeploysData, + [contractPackageHash]: payloadData + } + }; + } + + if ( + payloadData && + deploy && + payloadData.pageParams.length < deploy.pageParams.length + ) { + const updatedDeploy = { ...deploy }; + payloadData.pageParams.forEach((pageParam, index) => { + const element = deploy?.pageParams.find(el => el === pageParam); + + if (!element) { + updatedDeploy.pageParams.push(pageParam); + updatedDeploy.pages.push(payloadData.pages[index]); + } + }); + + return { + ...state, + cep18TransferDeploysData: { + [contractPackageHash]: updatedDeploy + } + }; + } return { ...state, - accountErc20TokensActivity: { - ...state.accountErc20TokensActivity, - [contractPackageHash]: tokensActivity[contractPackageHash] - ? { - tokenActivityCount, - tokenActivityList: [ - ...tokensActivity[contractPackageHash].tokenActivityList, - ...activityList - ] - } - : { - tokenActivityCount, - tokenActivityList: activityList - } + cep18TransferDeploysData: { + ...state.cep18TransferDeploysData, + [contractPackageHash]: payloadData } }; } ) - .handleAction(accountPendingTransactionsChanged, (state, { payload }) => { - const pendingTransactions = { - ...payload, - id: payload.deployHash - }; - + .handleAction(accountPendingDeployHashesChanged, (state, { payload }) => { return { ...state, - pendingTransactions: - state.pendingTransactions?.length > 0 - ? [pendingTransactions, ...state.pendingTransactions] - : [pendingTransactions] + pendingDeployHashes: [payload, ...state.pendingDeployHashes] }; }) - .handleAction(accountPendingTransactionsRemove, (state, { payload }) => ({ + .handleAction(accountPendingDeployHashesRemove, (state, { payload }) => ({ ...state, - pendingTransactions: state.pendingTransactions.filter( - transaction => transaction.deployHash !== payload + pendingDeployHashes: state.pendingDeployHashes.filter( + deploy => !isEqualCaseInsensitive(deploy, payload) ) })) - .handleAction(accountDeploysAdded, (state, { payload }) => ({ - ...state, - accountDeploys: payload - })) - .handleAction(accountDeploysUpdated, (state, { payload }) => ({ - ...state, - accountDeploys: - state.accountDeploys != null - ? [...state.accountDeploys, ...payload] - : payload - })) + .handleAction(accountDeploysDataChanged, (state, { payload }) => { + const stateDeploysData = state.accountDeploysData; + + if ( + payload && + stateDeploysData && + payload.pages[0].item_count > stateDeploysData.pages[0].item_count + ) { + return { + ...state, + accountDeploysData: payload + }; + } + + if ( + payload && + stateDeploysData?.pageParams && + payload.pageParams.length < stateDeploysData.pageParams.length + ) { + const updatedDeploysData = { ...stateDeploysData }; + + payload.pageParams.forEach((pageParam, index) => { + const element = stateDeploysData?.pageParams.find( + el => el === pageParam + ); + + if (!element) { + updatedDeploysData.pageParams.push(pageParam); + updatedDeploysData.pages.push(payload.pages[index]); + } + }); + + return { + ...state, + accountDeploysData: updatedDeploysData + }; + } + + return { + ...state, + accountDeploysData: payload + }; + }) .handleAction(accountNftTokensAdded, (state, { payload }) => ({ ...state, accountNftTokens: payload diff --git a/src/background/redux/account-info/selectors.ts b/src/background/redux/account-info/selectors.ts index 9eba5ea3f..1831e47b9 100644 --- a/src/background/redux/account-info/selectors.ts +++ b/src/background/redux/account-info/selectors.ts @@ -6,20 +6,20 @@ export const selectAccountBalance = (state: RootState) => export const selectAccountCurrencyRate = (state: RootState) => state.accountInfo.currencyRate; -export const selectAccountCasperActivity = (state: RootState) => - state.accountInfo.accountCasperActivity; +export const selectAccountCsprTransferDeploysData = (state: RootState) => + state.accountInfo.csprTransferDeploysData; -export const selectAccountErc20TokensActivity = (state: RootState) => - state.accountInfo.accountErc20TokensActivity; +export const selectAccountCep18TransferDeploysData = (state: RootState) => + state.accountInfo.cep18TransferDeploysData; -export const selectPendingTransactions = (state: RootState) => - state.accountInfo.pendingTransactions; +export const selectPendingDeployHashes = (state: RootState) => + state.accountInfo.pendingDeployHashes; export const selectErc20Tokens = (state: RootState) => state.accountInfo.erc20Tokens; -export const selectAccountDeploys = (state: RootState) => - state.accountInfo.accountDeploys; +export const selectAccountDeploysData = (state: RootState) => + state.accountInfo.accountDeploysData; export const selectAccountNftTokens = (state: RootState) => state.accountInfo.accountNftTokens; diff --git a/src/background/redux/account-info/types.ts b/src/background/redux/account-info/types.ts index 65458d56a..4f75f4450 100644 --- a/src/background/redux/account-info/types.ts +++ b/src/background/redux/account-info/types.ts @@ -1,20 +1,21 @@ -import { - Erc20TokenActionResult, - ExtendedDeployWithId, - TransferResultWithId -} from '@libs/services/account-activity-service'; +import { InfiniteData } from '@tanstack/react-query'; +import { IDeploy } from 'casper-wallet-core'; +import { CsprTransferDeployDto } from 'casper-wallet-core/src/data/dto'; +import { CloudPaginatedResponse } from 'casper-wallet-core/src/domain/common/http/data-provider'; + import { AccountBalance } from '@libs/services/balance-service'; import { ContractPackageWithBalance } from '@libs/services/erc20-service'; import { NFTTokenResult } from '@libs/services/nft-service'; +import { PaginatedResponse } from '@libs/services/types'; export interface AccountInfoState { balance: AccountBalance; erc20Tokens: ContractPackageWithBalance[]; currencyRate: number | null; - accountCasperActivity: TransferResultWithId[]; - accountErc20TokensActivity: Record | null; - pendingTransactions: ExtendedDeployWithId[]; - accountDeploys: ExtendedDeployWithId[] | null; + csprTransferDeploysData: CsprTransferDeploysDataType | null; + cep18TransferDeploysData: Record | null; + pendingDeployHashes: string[]; + accountDeploysData: AccountDeploysDataType | null; accountNftTokens: NFTTokenResult[] | null; nftTokensCount: number; accountDeploysCount: number; @@ -22,7 +23,14 @@ export interface AccountInfoState { accountTrackingIdOfSentNftTokens: Record; } -interface AccountErc20TokenActivity { - tokenActivityList: Erc20TokenActionResult[]; - tokenActivityCount: number; -} +export type CsprTransferDeploysDataType = + | InfiniteData, unknown> + | undefined; + +export type Cep18TransferDeploysDataType = + | InfiniteData, unknown> + | undefined; + +export type AccountDeploysDataType = + | InfiniteData, unknown> + | undefined; diff --git a/src/background/redux/settings/selectors.ts b/src/background/redux/settings/selectors.ts index bdc8d28bc..05e10e3f8 100644 --- a/src/background/redux/settings/selectors.ts +++ b/src/background/redux/settings/selectors.ts @@ -2,7 +2,11 @@ import { createSelector } from 'reselect'; import { RootState } from 'typesafe-actions'; import { + AssociatedKeysContractHash, AuctionManagerContractHash, + AuctionPoolContractHash, + CSPRMarketContractHash, + CSPRStudioCep47ContractHash, CasperClarityApiUrl, CasperLiveUrl, CasperNodeUrl, @@ -28,7 +32,11 @@ export const selectApiConfigBasedOnActiveNetwork = createSelector( casperWalletApiUrl: CasperWalletApiUrl.MainnetUrl, networkName: NetworkName.Mainnet, nodeUrl: CasperNodeUrl.MainnetUrl, - auctionManagerContractHash: AuctionManagerContractHash.Mainnet + auctionManagerContractHash: AuctionManagerContractHash.Mainnet, + csprMarketContractHash: CSPRMarketContractHash.Mainnet, + associatedKeysContractHash: AssociatedKeysContractHash.Mainnet, + csprStudioCep47ContractHash: CSPRStudioCep47ContractHash.Mainnet, + auctionPoolContractHash: AuctionPoolContractHash.Mainnet }; case NetworkSetting.Testnet: return { @@ -37,7 +45,11 @@ export const selectApiConfigBasedOnActiveNetwork = createSelector( casperWalletApiUrl: CasperWalletApiUrl.TestnetUrl, networkName: NetworkName.Testnet, nodeUrl: CasperNodeUrl.TestnetUrl, - auctionManagerContractHash: AuctionManagerContractHash.Testnet + auctionManagerContractHash: AuctionManagerContractHash.Testnet, + csprMarketContractHash: CSPRMarketContractHash.Testnet, + associatedKeysContractHash: AssociatedKeysContractHash.Testnet, + csprStudioCep47ContractHash: CSPRStudioCep47ContractHash.Testnet, + auctionPoolContractHash: AuctionPoolContractHash.Testnet }; default: throw new Error(`Unknown network: ${activeNetwork}`); diff --git a/src/background/service-message.ts b/src/background/service-message.ts index ac056b819..c07582218 100644 --- a/src/background/service-message.ts +++ b/src/background/service-message.ts @@ -1,8 +1,8 @@ +import { CloudPaginatedResponse, IDeploy } from 'casper-wallet-core'; import { ActionType, createAction } from 'typesafe-actions'; import { Erc20TokenActionResult, - ExtendedDeploy, TransferResult } from '@libs/services/account-activity-service/types'; import { AccountInfo } from '@libs/services/account-info/types'; @@ -68,12 +68,12 @@ export const serviceMessage = { 'FETCH_ERC20_TOKEN_ACTIVITY_RESPONSE' ), Meta>(), fetchExtendedDeploysInfoRequest: createAction('FETCH_EXTENDED_DEPLOYS_INFO')< - { deployHash: string }, + { deployHash: string; publicKey: string }, Meta >(), fetchExtendedDeploysInfoResponse: createAction( 'FETCH_EXTENDED_DEPLOYS_INFO_RESPONSE' - )(), + )(), fetchErc20TokensRequest: createAction('FETCH_ERC20_TOKENS')< { accountHash: string }, Meta @@ -88,13 +88,7 @@ export const serviceMessage = { >(), fetchAccountExtendedDeploysResponse: createAction( 'FETCH_ACCOUNT_DEPLOYS_RESPONSE' - ) | ErrorResponse, Meta>(), - fetchAccountCasperActivityRequest: createAction( - 'FETCH_ACCOUNT_CASPER_ACTIVITY' - )<{ accountHash: string; page: number }, Meta>(), - fetchAccountCasperActivityResponse: createAction( - 'FETCH_ACCOUNT_CASPER_ACTIVITY_RESPONSE' - ), Meta>(), + ) | ErrorResponse, Meta>(), fetchNftTokensRequest: createAction('FETCH_NFT_TOKENS')< { accountHash: string; page: number }, Meta diff --git a/src/background/wallet-repositories.ts b/src/background/wallet-repositories.ts new file mode 100644 index 000000000..8f5ad3557 --- /dev/null +++ b/src/background/wallet-repositories.ts @@ -0,0 +1,6 @@ +import { setupRepositories } from 'casper-wallet-core'; + +// TODO only deploysRepository usage for HRD. Other stuff later +const { deploysRepository } = setupRepositories(); + +export { deploysRepository }; diff --git a/src/constants.ts b/src/constants.ts index 3fe79094c..6205cc5af 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -27,6 +27,8 @@ export const STAKE_COST_MOTES = '2500000000'; // 2.5 CSPR export const DELEGATION_MIN_AMOUNT_MOTES = '500000000000'; // 500 CSPR export const MAX_DELEGATORS = 1200; +export const PENDING_DEPLOY_REFETCH_INTERVAL = 5 * 1000; + export const getBlockExplorerAccountUrl = (baseUrl: string, hash: string) => `${baseUrl}/account/${hash}`; @@ -96,65 +98,25 @@ export enum AuctionManagerContractHash { Testnet = '93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2' } -export enum ActivityType { - Sent = 'Sent', - Received = 'Received', - Unknown = 'Unknown', - Delegated = 'Delegated', - Undelegated = 'Undelegated', - Redelegated = 'Redelegated', - Mint = 'Mint', - Burn = 'Burn', - TransferNft = 'Transfer NFT' -} - -export const ActivityShortTypeName = { - [ActivityType.Sent]: 'Sent', - [ActivityType.Received]: 'Recv', - [ActivityType.Unknown]: 'Unk', - [ActivityType.Delegated]: 'Deleg', - [ActivityType.Undelegated]: 'Undeleg', - [ActivityType.Redelegated]: 'Redeleg', - [ActivityType.Mint]: 'Mint NFT', - [ActivityType.Burn]: 'Burn NFT', - [ActivityType.TransferNft]: 'Transfer NFT' -}; +export enum CSPRMarketContractHash { + Mainnet = '31cc023b17c903a963ec60eab96a60f1fa37cb74b4b3bafc91a441e0e9d70f97', + Testnet = '154ff59b5f9feec42d3a418058d66badcb2121dc3ffb2e3cf92596bf5aafbc88' +} -export const ActivityTypeName = { - [ActivityType.Sent]: 'Sent', - [ActivityType.Received]: 'Received', - [ActivityType.Unknown]: 'Unknown', - [ActivityType.Delegated]: 'Delegated', - [ActivityType.Undelegated]: 'Undelegated', - [ActivityType.Redelegated]: 'Redelegated', - [ActivityType.Mint]: 'Mint NFT', - [ActivityType.Burn]: 'Burn NFT', - [ActivityType.TransferNft]: 'Transfer NFT' -}; +export enum AssociatedKeysContractHash { + Mainnet = 'b2ec4f982efa8643c979cb3ab42ad1a18851c2e6f91804cd3e65c079679bdc59', + Testnet = '676794cbbb35ff5642d0ae9c35302e244a7236a614d7e9ef58d0fb2cba6be3ed' +} -export const ActivityTypeIcons = { - [ActivityType.Sent]: 'assets/icons/transfer.svg', - [ActivityType.Received]: 'assets/icons/receive.svg', - [ActivityType.Unknown]: 'assets/icons/info.svg', - [ActivityType.Delegated]: 'assets/icons/delegate.svg', - [ActivityType.Undelegated]: 'assets/icons/undelegate.svg', - [ActivityType.Redelegated]: 'assets/icons/undelegate.svg', - [ActivityType.Mint]: 'assets/icons/info.svg', - [ActivityType.Burn]: 'assets/icons/burn.svg', - [ActivityType.TransferNft]: 'assets/icons/transfer.svg' -}; +export enum CSPRStudioCep47ContractHash { + Mainnet = 'c4e5a03066ce3c6006f562939e48f7076c77de5d46cf8fe625c41e02c5e74814', + Testnet = '998af6825d77da15485baf4bb89aeef3f1dfb4a78841d149574b0be694ce4821' +} -export const ActivityTypeColors = { - [ActivityType.Sent]: 'contentAction', - [ActivityType.Received]: 'contentPositive', - [ActivityType.Unknown]: 'contentDisabled', - [ActivityType.Delegated]: 'contentAction', - [ActivityType.Undelegated]: 'contentAction', - [ActivityType.Redelegated]: 'contentAction', - [ActivityType.Mint]: 'contentDisabled', - [ActivityType.Burn]: 'contentActionCritical', - [ActivityType.TransferNft]: 'contentAction' -}; +export enum AuctionPoolContractHash { + Mainnet = '6174cf2e6f8fed1715c9a3bace9c50bfe572eecb763b0ed3f644532616452008', + Testnet = '6174cf2e6f8fed1715c9a3bace9c50bfe572eecb763b0ed3f644532616452008' +} export enum HomePageTabName { Tokens = 'Tokens', @@ -177,8 +139,149 @@ export enum AuctionManagerEntryPoint { redelegate = 'redelegate' } -export enum TokenEntryPoint { +export const ExecutionTypesMap: { [key in number]: string } = { + 1: 'WASM deploy', //"ModuleBytes" + 2: 'Contract call', //"StoredContractByHash" + 3: 'Contract call', //"StoredContractByName", + 4: 'Contract call', //"StoredVersionedContractByHash", + 5: 'Contract call', //"StoredVersionedContractByName", + 6: 'Transfer' +}; + +export enum DeployIcon { + Generic = 'assets/icons/generic.svg', + Auction = '/assets/icons/auction.svg', + NativeTransfer = '/assets/icons/casper.svg', + CSPRStudio = '/assets/icons/cspr-studio.svg', + CSPRMarket = '/assets/icons/cspr-market.svg', + AssociatedKeys = '/assets/icons/associated-keys.svg', + Cep18Default = '/assets/icons/cep-18-default.svg', + NFTDefault = 'assets/icons/nft-contract-icon.svg' +} + +export enum AuctionDeployEntryPoint { + delegate = 'delegate', + undelegate = 'undelegate', + redelegate = 'redelegate', + add = 'add_bid', + withdraw = 'withdraw_bid', + activate = 'activate_bid' +} + +export const AuctionDeployEntryPointNameMap = { + [AuctionDeployEntryPoint.add]: 'Add bid', + [AuctionDeployEntryPoint.withdraw]: 'Withdraw bid', + [AuctionDeployEntryPoint.activate]: 'Activate bid', + [AuctionDeployEntryPoint.delegate]: 'Delegate', + [AuctionDeployEntryPoint.undelegate]: 'Undelegate', + [AuctionDeployEntryPoint.redelegate]: 'Redelegate' +}; + +export const AuctionDeployActionName = { + [AuctionDeployEntryPoint.add]: 'Add bid', + [AuctionDeployEntryPoint.withdraw]: 'Withdraw bid', + [AuctionDeployEntryPoint.activate]: 'Activate bid', + [AuctionDeployEntryPoint.delegate]: 'Delegate', + [AuctionDeployEntryPoint.undelegate]: 'Undelegate', + [AuctionDeployEntryPoint.redelegate]: 'Redelegate' +}; + +export enum NftDeployEntryPoint { + approve = 'approve', + burn = 'burn', + mint = 'mint', + transfer = 'transfer', + update_token_meta = 'update_token_meta', + set_approval_for_all = 'set_approval_for_all' +} + +export const NftDeployEntryPointNameMap = { + [NftDeployEntryPoint.approve]: 'Approve transfer', + [NftDeployEntryPoint.burn]: 'Burn', + [NftDeployEntryPoint.mint]: 'Mint', + [NftDeployEntryPoint.transfer]: 'Transfer', + [NftDeployEntryPoint.update_token_meta]: 'Update metadata', + [NftDeployEntryPoint.set_approval_for_all]: 'Approve transfer' +}; + +export const NftDeployActionName = { + [NftDeployEntryPoint.approve]: 'Approve transfer rights', + [NftDeployEntryPoint.burn]: 'Burn', + [NftDeployEntryPoint.mint]: 'Mint', + [NftDeployEntryPoint.transfer]: 'Transfer', + [NftDeployEntryPoint.update_token_meta]: 'Update metadata', + [NftDeployEntryPoint.set_approval_for_all]: 'Approve transfer rights' +}; + +export const NftDeployResultName = { + [NftDeployEntryPoint.approve]: 'Granted transfer rights', + [NftDeployEntryPoint.burn]: 'Burned', + [NftDeployEntryPoint.mint]: 'Minted', + [NftDeployEntryPoint.transfer]: 'Transferred', + [NftDeployEntryPoint.update_token_meta]: 'Updated metadata', + [NftDeployEntryPoint.set_approval_for_all]: 'Granted transfer rights' +}; + +export enum Cep18DeployEntryPoint { + approve = 'approve', mint = 'mint', burn = 'burn', transfer = 'transfer' } + +export const Cep18DeployEntryPointNameMap = { + [Cep18DeployEntryPoint.approve]: 'Approve', + [Cep18DeployEntryPoint.burn]: 'Burn', + [Cep18DeployEntryPoint.mint]: 'Mint', + [Cep18DeployEntryPoint.transfer]: 'Transfer' +}; + +export const Cep18DeployActionName = { + [Cep18DeployEntryPoint.approve]: 'Approve transfer rights', + [Cep18DeployEntryPoint.burn]: 'Burn', + [Cep18DeployEntryPoint.mint]: 'Mint', + [Cep18DeployEntryPoint.transfer]: 'Transfer' +}; + +export const Cep18DeployResultName = { + [Cep18DeployEntryPoint.approve]: 'Granted transfer rights', + [Cep18DeployEntryPoint.burn]: 'Burned', + [Cep18DeployEntryPoint.mint]: 'Minted', + [Cep18DeployEntryPoint.transfer]: 'Transferred' +}; + +export enum CsprMarketDeployEntryPoint { + delist_token = 'delist_token', + list_token = 'list_token', + accept_offer = 'accept_offer', + cancel_offer = 'cancel_offer', + make_offer = 'make_offer' +} + +export const CsprMarketDeployEntryPointNameMap = { + [CsprMarketDeployEntryPoint.accept_offer]: 'Accept offer', + [CsprMarketDeployEntryPoint.cancel_offer]: 'Cancel offer', + [CsprMarketDeployEntryPoint.delist_token]: 'Delist', + [CsprMarketDeployEntryPoint.list_token]: 'List', + [CsprMarketDeployEntryPoint.make_offer]: 'Make offer' +}; + +export const DeployPlateEntryPointNameMap: { [key: string]: string } = { + ...AuctionDeployEntryPointNameMap, + ...CsprMarketDeployEntryPointNameMap, + ...Cep18DeployEntryPointNameMap, + ...NftDeployEntryPointNameMap +}; + +export const DeployActionEntryPointNameMap: { [key: string]: string } = { + ...Cep18DeployActionName, + ...NftDeployActionName, + ...AuctionDeployActionName, + ...CsprMarketDeployEntryPointNameMap +}; + +export const DeployResultEntryPointNameMap: { [key: string]: string } = { + ...Cep18DeployResultName, + ...NftDeployResultName, + ...CsprMarketDeployEntryPointNameMap +}; diff --git a/src/fixtures/initial-state-for-popup-tests.ts b/src/fixtures/initial-state-for-popup-tests.ts index 8da58cac4..1b8b6cd18 100644 --- a/src/fixtures/initial-state-for-popup-tests.ts +++ b/src/fixtures/initial-state-for-popup-tests.ts @@ -99,11 +99,14 @@ export const initialStateForPopupTests: RootState = { totalBalanceFiat: null }, currencyRate: null, - accountCasperActivity: [], - accountErc20TokensActivity: null, - pendingTransactions: [], + csprTransferDeploysData: { + pages: [], + pageParams: [] + }, + cep18TransferDeploysData: null, + pendingDeployHashes: [], erc20Tokens: [], - accountDeploys: [], + accountDeploysData: null, accountNftTokens: [], nftTokensCount: 0, accountDeploysCount: 0, diff --git a/src/hooks/use-fetch-account-deploys.ts b/src/hooks/use-fetch-account-deploys.ts deleted file mode 100644 index b413de32b..000000000 --- a/src/hooks/use-fetch-account-deploys.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; -import { useSelector } from 'react-redux'; - -import { ACCOUNT_CASPER_ACTIVITY_REFRESH_RATE } from '@src/constants'; - -import { useForceUpdate } from '@popup/hooks/use-force-update'; - -import { - accountDeploysAdded, - accountDeploysCountChanged, - accountDeploysUpdated -} from '@background/redux/account-info/actions'; -import { - selectAccountDeploys, - selectAccountDeploysCount -} from '@background/redux/account-info/selectors'; -import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; -import { dispatchToMainStore } from '@background/redux/utils'; -import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; - -import { dispatchFetchAccountExtendedDeploys } from '@libs/services/account-activity-service'; - -export const useFetchAccountDeploys = () => { - const [loading, setLoading] = useState(false); - const [accountDeploysPage, setAccountDeploysPage] = useState(2); - const [hasNextPage, setHasNextPage] = useState(false); - const [isFirstPageLoad, setIsFirstPageLoad] = useState(false); - - const activeAccount = useSelector(selectVaultActiveAccount); - const { casperClarityApiUrl } = useSelector( - selectApiConfigBasedOnActiveNetwork - ); - const accountDeploysList = useSelector(selectAccountDeploys); - const accountDeploysCount = useSelector(selectAccountDeploysCount); - - const effectTimeoutRef = useRef(); - const forceUpdate = useForceUpdate(); - - const handleError = (error: Error) => { - console.error('Account deploys request failed:', error); - }; - - useEffect(() => { - if (accountDeploysList && accountDeploysCount > accountDeploysList.length) { - setHasNextPage(true); - } - - if ( - (accountDeploysList == null || accountDeploysList.length === 0) && - accountDeploysCount === 0 - ) { - setAccountDeploysPage(2); - return; - } - }, [ - accountDeploysList, - accountDeploysList?.length, - accountDeploysCount, - accountDeploysPage - ]); - - useEffect(() => { - if (!activeAccount?.publicKey) return; - - // set loading to true only for the first time - if ( - (accountDeploysList == null || accountDeploysList.length === 0) && - !isFirstPageLoad - ) { - setLoading(true); - } - - dispatchFetchAccountExtendedDeploys(activeAccount?.publicKey, 1) - .then(({ payload }) => { - if ('data' in payload) { - const { data: deploysList, pageCount, itemCount } = payload; - - if ( - itemCount === accountDeploysList?.length || - itemCount === accountDeploysCount - ) { - return; - } - - const deploysListWithId = deploysList.map(deploy => ({ - ...deploy, - id: deploy.deployHash - })); - - dispatchToMainStore(accountDeploysAdded(deploysListWithId)); - dispatchToMainStore(accountDeploysCountChanged(itemCount)); - - if (pageCount > 1) { - setHasNextPage(true); - } - } else { - dispatchToMainStore(accountDeploysAdded(null)); - setHasNextPage(false); - } - }) - .catch(handleError) - .finally(() => { - setTimeout(() => { - setLoading(false); - }, 300); - setIsFirstPageLoad(true); - }); - - // will cause effect to run again after timeout - effectTimeoutRef.current = setTimeout(() => { - forceUpdate(); - }, ACCOUNT_CASPER_ACTIVITY_REFRESH_RATE + 1); - - return () => { - clearTimeout(effectTimeoutRef.current); - }; - }, [ - accountDeploysCount, - accountDeploysList, - accountDeploysList?.length, - activeAccount?.publicKey, - casperClarityApiUrl, - forceUpdate, - isFirstPageLoad, - setLoading, - setIsFirstPageLoad, - setHasNextPage - ]); - - const loadMoreDeploys = useCallback(() => { - if (!activeAccount?.publicKey) return; - - setLoading(true); - - dispatchFetchAccountExtendedDeploys( - activeAccount?.publicKey, - accountDeploysPage - ) - .then(({ payload }) => { - if ('data' in payload) { - const { data: deploysList, pageCount, itemCount } = payload; - - if (itemCount === accountDeploysList?.length) { - setHasNextPage(false); - return; - } - - const deploysListWithId = deploysList.map(deploy => ({ - ...deploy, - id: deploy.deployHash - })); - - dispatchToMainStore(accountDeploysUpdated(deploysListWithId)); - - if (accountDeploysPage + 1 <= pageCount) { - setAccountDeploysPage(accountDeploysPage + 1); - } - - if (accountDeploysCount !== itemCount) { - dispatchToMainStore(accountDeploysCountChanged(itemCount)); - } - if (accountDeploysPage >= pageCount) { - setHasNextPage(false); - } - } else { - dispatchToMainStore(accountDeploysAdded(null)); - setHasNextPage(false); - } - }) - .catch(handleError) - .finally(() => { - setLoading(false); - }); - }, [ - accountDeploysCount, - accountDeploysList?.length, - accountDeploysPage, - activeAccount?.publicKey, - setLoading, - setHasNextPage, - setAccountDeploysPage - ]); - - return { - loadMoreDeploys, - loading, - hasNextPage - }; -}; diff --git a/src/hooks/use-fetch-casper-token-account-activity.ts b/src/hooks/use-fetch-casper-token-account-activity.ts deleted file mode 100644 index ec79548f7..000000000 --- a/src/hooks/use-fetch-casper-token-account-activity.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; -import { useSelector } from 'react-redux'; - -import { ACCOUNT_CASPER_ACTIVITY_REFRESH_RATE } from '@src/constants'; - -import { useForceUpdate } from '@popup/hooks/use-force-update'; - -import { - accountCasperActivityChanged, - accountCasperActivityCountChanged, - accountCasperActivityUpdated -} from '@background/redux/account-info/actions'; -import { - selectAccountCasperActivity, - selectAccountCasperActivityCount -} from '@background/redux/account-info/selectors'; -import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; -import { dispatchToMainStore } from '@background/redux/utils'; -import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; - -import { getAccountHashFromPublicKey } from '@libs/entities/Account'; -import { dispatchFetchAccountCasperActivity } from '@libs/services/account-activity-service'; - -export const useFetchCasperTokenAccountActivity = () => { - const [loading, setLoading] = useState(false); - const [accountCasperActivityPage, setAccountCasperActivityPage] = useState(2); - const [hasNextPage, setHasNextPage] = useState(false); - const [isFirstPageLoad, setIsFirstPageLoad] = useState(false); - - const activeAccount = useSelector(selectVaultActiveAccount); - const { casperClarityApiUrl } = useSelector( - selectApiConfigBasedOnActiveNetwork - ); - const accountCasperActivityList = useSelector(selectAccountCasperActivity); - const casperTokenActivityCount = useSelector( - selectAccountCasperActivityCount - ); - - const effectTimeoutRef = useRef(); - const forceUpdate = useForceUpdate(); - - const activeAccountHash = activeAccount?.publicKey - ? getAccountHashFromPublicKey(activeAccount?.publicKey) - : null; - - const handleError = (error: Error) => { - console.error('Account casper token activity request failed:', error); - }; - - useEffect(() => { - if (casperTokenActivityCount > accountCasperActivityList.length) { - setHasNextPage(true); - } - - if ( - casperTokenActivityCount === 0 && - accountCasperActivityList.length === 0 - ) { - setAccountCasperActivityPage(2); - } - }, [ - activeAccountHash, - accountCasperActivityList.length, - accountCasperActivityPage, - casperTokenActivityCount - ]); - - useEffect(() => { - if (!activeAccountHash) return; - - // set loading to true only for the first time - if (accountCasperActivityList.length === 0 && !isFirstPageLoad) { - setLoading(true); - } - - dispatchFetchAccountCasperActivity(activeAccountHash, 1) - .then(({ payload }) => { - if (payload) { - const { - data: casperTokensActivityList, - pageCount, - itemCount - } = payload; - - if ( - itemCount === accountCasperActivityList?.length || - itemCount === casperTokenActivityCount - ) { - return; - } - - const transactions = - casperTokensActivityList?.map(transaction => ({ - ...transaction, - id: transaction.deployHash - })) || []; - - dispatchToMainStore(accountCasperActivityChanged(transactions)); - dispatchToMainStore(accountCasperActivityCountChanged(itemCount)); - - if (pageCount > 1) { - setHasNextPage(true); - } - } - }) - .catch(handleError) - .finally(() => { - setTimeout(() => { - setLoading(false); - }, 300); - setIsFirstPageLoad(true); - }); - - // will cause effect to run again after timeout - effectTimeoutRef.current = setTimeout(() => { - forceUpdate(); - }, ACCOUNT_CASPER_ACTIVITY_REFRESH_RATE + 1); - - return () => { - clearTimeout(effectTimeoutRef.current); - }; - }, [ - casperClarityApiUrl, - forceUpdate, - activeAccountHash, - accountCasperActivityList.length, - accountCasperActivityPage, - casperTokenActivityCount, - isFirstPageLoad - ]); - - const loadMoreAccountCasperActivity = useCallback(() => { - if (!activeAccountHash) return; - - setLoading(true); - - dispatchFetchAccountCasperActivity( - activeAccountHash, - accountCasperActivityPage - ) - .then(({ payload }) => { - if (payload) { - const { - data: casperTokensActivityList, - pageCount, - itemCount - } = payload; - - if (itemCount === accountCasperActivityList?.length) { - setHasNextPage(false); - return; - } - - const transactions = - casperTokensActivityList?.map(transaction => ({ - ...transaction, - id: transaction.deployHash - })) || []; - - dispatchToMainStore(accountCasperActivityUpdated(transactions)); - - if (accountCasperActivityPage + 1 <= pageCount) { - setAccountCasperActivityPage(accountCasperActivityPage + 1); - } - - if (casperTokenActivityCount !== itemCount) { - dispatchToMainStore(accountCasperActivityCountChanged(itemCount)); - } - - if (accountCasperActivityPage >= pageCount) { - setHasNextPage(false); - } - } - }) - .catch(handleError) - .finally(() => { - setLoading(false); - }); - }, [ - accountCasperActivityList?.length, - accountCasperActivityPage, - activeAccountHash, - casperTokenActivityCount - ]); - - return { - loading, - loadMoreAccountCasperActivity, - hasNextPage - }; -}; diff --git a/src/hooks/use-fetch-erc20-token-account-activity.ts b/src/hooks/use-fetch-erc20-token-account-activity.ts deleted file mode 100644 index d9ef20c52..000000000 --- a/src/hooks/use-fetch-erc20-token-account-activity.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; -import { useSelector } from 'react-redux'; - -import { ACCOUNT_CASPER_ACTIVITY_REFRESH_RATE } from '@src/constants'; - -import { useForceUpdate } from '@popup/hooks/use-force-update'; - -import { - accountErc20TokensActivityChanged, - accountErc20TokensActivityUpdated -} from '@background/redux/account-info/actions'; -import { selectAccountErc20TokensActivity } from '@background/redux/account-info/selectors'; -import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; -import { dispatchToMainStore } from '@background/redux/utils'; -import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; - -import { getAccountHashFromPublicKey } from '@libs/entities/Account'; -import { dispatchFetchErc20TokenActivity } from '@libs/services/account-activity-service/erc20-token-activity-service'; - -export const useFetchErc20TokenAccountActivity = ( - contractPackageHash: string -) => { - const [loading, setLoading] = useState(false); - const [accountErc20ActivityPage, setAccountErc20ActivityPage] = useState(2); - const [hasNextPage, setHasNextPage] = useState(false); - const [isFirstPageLoad, setIsFirstPageLoad] = useState(false); - - const erc20TokensActivityRecord = - useSelector(selectAccountErc20TokensActivity) || {}; - - const tokenActivity = erc20TokensActivityRecord[contractPackageHash || '']; - - const activeAccount = useSelector(selectVaultActiveAccount); - const { casperClarityApiUrl } = useSelector( - selectApiConfigBasedOnActiveNetwork - ); - - const effectTimeoutRef = useRef(); - const forceUpdate = useForceUpdate(); - - const activeAccountHash = activeAccount?.publicKey - ? getAccountHashFromPublicKey(activeAccount?.publicKey) - : null; - - const handleError = (error: Error) => { - console.error('Account erc20 token activity request failed:', error); - }; - - useEffect(() => { - if ( - tokenActivity?.tokenActivityCount > - tokenActivity?.tokenActivityList.length - ) { - setHasNextPage(true); - } - - if ( - tokenActivity?.tokenActivityCount === 0 && - tokenActivity?.tokenActivityList.length === 0 - ) { - setAccountErc20ActivityPage(2); - } - }, [ - tokenActivity?.tokenActivityCount, - tokenActivity?.tokenActivityList.length - ]); - - useEffect(() => { - if (!activeAccountHash) return; - - // set loading to true only for the first time - if ( - (tokenActivity?.tokenActivityList.length === 0 || - !tokenActivity?.tokenActivityList) && - !isFirstPageLoad - ) { - setLoading(true); - } - - dispatchFetchErc20TokenActivity(activeAccountHash, contractPackageHash, 1) - .then(({ payload }) => { - if (payload) { - const { - data: erc20TokensActivityList, - pageCount, - itemCount - } = payload; - - if ( - itemCount === tokenActivity?.tokenActivityList?.length || - itemCount === tokenActivity?.tokenActivityCount - ) { - return; - } - - dispatchToMainStore( - accountErc20TokensActivityChanged({ - contractPackageHash, - activityList: erc20TokensActivityList, - tokenActivityCount: itemCount - }) - ); - - if (pageCount > 1) { - setHasNextPage(true); - } - } - }) - .catch(handleError) - .finally(() => { - setTimeout(() => { - setLoading(false); - }, 300); - setIsFirstPageLoad(true); - }); - - // will cause effect to run again after timeout - effectTimeoutRef.current = setTimeout(() => { - forceUpdate(); - }, ACCOUNT_CASPER_ACTIVITY_REFRESH_RATE + 1); - - return () => { - clearTimeout(effectTimeoutRef.current); - }; - }, [ - activeAccountHash, - contractPackageHash, - tokenActivity?.tokenActivityCount, - tokenActivity?.tokenActivityList.length, - casperClarityApiUrl, - forceUpdate, - tokenActivity?.tokenActivityList, - isFirstPageLoad - ]); - - const loadMoreAccountErc20Activity = useCallback(() => { - if (!activeAccountHash) return; - - setLoading(true); - - dispatchFetchErc20TokenActivity( - activeAccountHash, - contractPackageHash, - accountErc20ActivityPage - ) - .then(({ payload }) => { - if (payload) { - const { - data: erc20TokensActivityList, - pageCount, - itemCount - } = payload; - - if (itemCount === tokenActivity?.tokenActivityList?.length) { - setHasNextPage(false); - return; - } - - dispatchToMainStore( - accountErc20TokensActivityUpdated({ - contractPackageHash, - tokenActivityCount: itemCount, - activityList: erc20TokensActivityList - }) - ); - - if (accountErc20ActivityPage + 1 <= pageCount) { - setAccountErc20ActivityPage(accountErc20ActivityPage + 1); - } - - if (accountErc20ActivityPage >= pageCount) { - setHasNextPage(false); - } - } - }) - .catch(handleError) - .finally(() => { - setLoading(false); - }); - }, [ - accountErc20ActivityPage, - activeAccountHash, - contractPackageHash, - tokenActivity?.tokenActivityList?.length - ]); - - return { - loading, - loadMoreAccountErc20Activity, - hasNextPage - }; -}; diff --git a/src/hooks/use-map-account-deploys-list-with-pending-transactions.ts b/src/hooks/use-map-account-deploys-list-with-pending-transactions.ts deleted file mode 100644 index 5fbba6d21..000000000 --- a/src/hooks/use-map-account-deploys-list-with-pending-transactions.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { useMemo } from 'react'; -import { useSelector } from 'react-redux'; - -import { accountPendingTransactionsRemove } from '@background/redux/account-info/actions'; -import { selectPendingTransactions } from '@background/redux/account-info/selectors'; -import { dispatchToMainStore } from '@background/redux/utils'; -import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; - -import { ExtendedDeployWithId } from '@libs/services/account-activity-service'; -import { getMappedPendingTransactions } from '@libs/ui/utils'; - -export const useMapAccountDeploysListWithPendingTransactions = ( - accountDeploys: ExtendedDeployWithId[] | null -) => { - const pendingTransactions = useSelector(selectPendingTransactions); - const activeAccount = useSelector(selectVaultActiveAccount); - - const mappedPendingTransactions = getMappedPendingTransactions( - pendingTransactions, - activeAccount?.publicKey || '' - ); - - // validated pending transactions - const filteredTransactions = useMemo(() => { - return mappedPendingTransactions?.filter(pendingTransaction => { - if (accountDeploys != null) { - const transaction = accountDeploys?.find( - deploy => deploy.deployHash === pendingTransaction.deployHash - ); - - if (transaction) { - dispatchToMainStore( - accountPendingTransactionsRemove(transaction?.deployHash) - ); - } - - return !transaction; - } - - return true; - }); - }, [accountDeploys, mappedPendingTransactions]); - - const accountDeploysListWithPendingTransactions = - accountDeploys != null - ? [...filteredTransactions, ...accountDeploys] - : mappedPendingTransactions.length > 0 - ? mappedPendingTransactions - : null; - - return { - accountDeploysListWithPendingTransactions - }; -}; diff --git a/src/libs/services/account-activity-service/account-activity-service.ts b/src/libs/services/account-activity-service/account-activity-service.ts deleted file mode 100644 index 7ecfe93b0..000000000 --- a/src/libs/services/account-activity-service/account-activity-service.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { ACCOUNT_CASPER_ACTIVITY_REFRESH_RATE } from '@src/constants'; - -import { dispatchToMainStore } from '@background/redux/utils'; -import { serviceMessage } from '@background/service-message'; - -import { TransferResult } from '@libs/services/account-activity-service/types'; -import { queryClient } from '@libs/services/query-client'; -import { PaginatedResponse, Payload } from '@libs/services/types'; -import { handleError, toJson } from '@libs/services/utils'; - -import { getAccountTransferLink } from './constants'; - -export const accountCasperActivityRequest = ( - casperClarityApiUrl: string, - accountHash: string, - page: number, - signal?: AbortSignal -): Promise> => - fetch(getAccountTransferLink(casperClarityApiUrl, accountHash, page), { - signal - }) - .then(toJson) - .catch(handleError); - -export const fetchAccountCasperActivity = ({ - casperClarityApiUrl, - accountHash, - page -}: { - casperClarityApiUrl: string; - accountHash: string; - page: number; -}) => - queryClient.fetchQuery( - ['accountCasperActivityRequest', casperClarityApiUrl, accountHash, page], - ({ signal }) => - accountCasperActivityRequest( - casperClarityApiUrl, - accountHash, - page, - signal - ), - { staleTime: ACCOUNT_CASPER_ACTIVITY_REFRESH_RATE } - ); - -export const dispatchFetchAccountCasperActivity = ( - accountHash: string, - page: number -): Promise>> => - dispatchToMainStore( - serviceMessage.fetchAccountCasperActivityRequest({ accountHash, page }) - ); diff --git a/src/libs/services/account-activity-service/constants.ts b/src/libs/services/account-activity-service/constants.ts index 9745a0c81..8a0eef350 100644 --- a/src/libs/services/account-activity-service/constants.ts +++ b/src/libs/services/account-activity-service/constants.ts @@ -1,17 +1,3 @@ -export const getAccountActivityLink = ( - casperClarityApiUrl: string, - publicKey: string, - page: number -) => - `${casperClarityApiUrl}/accounts/${publicKey}/ledgerlive-deploys?page=${page}&limit=10&execution_type_id=6`; - -export const getErc20AccountActivityLink = ( - casperClarityApiUrl: string, - account_hash: string, - page: number -) => - `${casperClarityApiUrl}/accounts/${account_hash}/erc20-token-actions?page=${page}&limit=10&fields=contract_package,deploy&with_amounts_in_currency_id=1`; - export const getErc20TokenActivityLink = ( casperClarityApiUrl: string, account_hash: string, @@ -19,23 +5,3 @@ export const getErc20TokenActivityLink = ( page: number ) => `${casperClarityApiUrl}/erc20-token-actions?contract_package_hash=${contract_package_hash}&account_hash=${account_hash}&page=${page}&limit=10&fields=contract_package,deploy&with_amounts_in_currency_id=1`; - -export const getExtendedDeploysHashLink = ( - casperClarityApiUrl: string, - deployHash: string -) => - `${casperClarityApiUrl}/extended-deploys/${deployHash}?fields=entry_point,contract_package&with_amounts_in_currency_id=1`; - -export const getAccountExtendedDeploysLink = ( - casperClarityApiUrl: string, - publicKey: string, - page: number -) => - `${casperClarityApiUrl}/accounts/${publicKey}/extended-deploys?page=${page}&limit=10&fields=entry_point,contract_package&with_amounts_in_currency_id=1`; - -export const getAccountTransferLink = ( - casperClarityApiUrl: string, - account_hash: string, - page: number -) => - `${casperClarityApiUrl}/accounts/${account_hash}/transfers?page=${page}&limit=10&with_extended_info=1&with_amounts_in_currency_id=1`; diff --git a/src/libs/services/account-activity-service/erc20-token-action-types.ts b/src/libs/services/account-activity-service/erc20-token-action-types.ts deleted file mode 100644 index bb2633496..000000000 --- a/src/libs/services/account-activity-service/erc20-token-action-types.ts +++ /dev/null @@ -1,18 +0,0 @@ -export class Erc20TokenActionType { - static byId: Record = [ - { id: 1, name: 'Mint' }, - { id: 2, name: 'Transfer' }, - { id: 3, name: 'Approve' }, - { id: 4, name: 'Burn' } - ].reduce( - (acc, item) => { - acc[item.id] = item.name; - return acc; - }, - {} as Record - ); - - static getActionNameById(id: number) { - return this.byId[id]; - } -} diff --git a/src/libs/services/account-activity-service/extended-deploys-service.ts b/src/libs/services/account-activity-service/extended-deploys-service.ts index e3ea4634d..b4c18e6b1 100644 --- a/src/libs/services/account-activity-service/extended-deploys-service.ts +++ b/src/libs/services/account-activity-service/extended-deploys-service.ts @@ -1,88 +1,71 @@ +import { CloudPaginatedResponse, IDeploy } from 'casper-wallet-core'; +import { CasperNetwork } from 'casper-wallet-core/src/domain/common/common'; + import { ACCOUNT_DEPLOY_REFRESH_RATE } from '@src/constants'; import { dispatchToMainStore } from '@background/redux/utils'; import { serviceMessage } from '@background/service-message'; +import { deploysRepository } from '@background/wallet-repositories'; import { queryClient } from '@libs/services/query-client'; -import { - ErrorResponse, - PaginatedResponse, - Payload -} from '@libs/services/types'; -import { handleError, toJson } from '@libs/services/utils'; - -import { - getAccountExtendedDeploysLink, - getExtendedDeploysHashLink -} from './constants'; -import { ExtendedDeploy, ExtendedDeployResult } from './types'; - -export const extendedDeploysRequest = ( - casperClarityApiUrl: string, - deployHash: string, - signal?: AbortSignal -): Promise => - fetch(getExtendedDeploysHashLink(casperClarityApiUrl, deployHash), { signal }) - .then(toJson) - .catch(handleError); +import { ErrorResponse, Payload } from '@libs/services/types'; export const fetchExtendedDeploysInfo = ({ casperClarityApiUrl, - deployHash + deployHash, + publicKey, + network }: { casperClarityApiUrl: string; deployHash: string; + publicKey: string; + network: CasperNetwork; }) => queryClient.fetchQuery( - ['accountTransactionsRequest', casperClarityApiUrl, deployHash], - ({ signal }) => - extendedDeploysRequest(casperClarityApiUrl, deployHash, signal) + ['getSingleDeploy', casperClarityApiUrl, deployHash, network], + () => + deploysRepository.getSingleDeploy({ + deployHash, + network, + activePublicKey: publicKey + }) ); export const dispatchFetchExtendedDeploysInfo = ( - deployHash: string -): Promise> => + deployHash: string, + publicKey: string +): Promise> => dispatchToMainStore( - serviceMessage.fetchExtendedDeploysInfoRequest({ deployHash }) + serviceMessage.fetchExtendedDeploysInfoRequest({ deployHash, publicKey }) ); -export const accountExtendedDeploysRequest = ( - casperClarityApiUrl: string, - publicKey: string, - page: number, - signal?: AbortSignal -): Promise> => - fetch(getAccountExtendedDeploysLink(casperClarityApiUrl, publicKey, page), { - signal - }) - .then(toJson) - .catch(handleError); - +// TODO just a quick example. Errors handling required export const fetchAccountExtendedDeploys = ({ casperClarityApiUrl, publicKey, - page + page, + network }: { casperClarityApiUrl: string; publicKey: string; page: number; -}): Promise | ErrorResponse> => + network: CasperNetwork; +}): Promise> => queryClient.fetchQuery( - ['accountDeploysRequest', casperClarityApiUrl, publicKey, page], - ({ signal }) => - accountExtendedDeploysRequest( - casperClarityApiUrl, - publicKey, + ['getDeploys', casperClarityApiUrl, publicKey, page, network], + () => + deploysRepository.getDeploys({ page, - signal - ), + activePublicKey: publicKey, + network + }), { staleTime: ACCOUNT_DEPLOY_REFRESH_RATE } ); export const dispatchFetchAccountExtendedDeploys = ( publicKey: string, page: number -): Promise | ErrorResponse>> => +): Promise | ErrorResponse>> => dispatchToMainStore( serviceMessage.fetchAccountExtendedDeploysRequest({ publicKey, page }) ); diff --git a/src/libs/services/account-activity-service/index.ts b/src/libs/services/account-activity-service/index.ts index f4e47aa03..5d11231ed 100644 --- a/src/libs/services/account-activity-service/index.ts +++ b/src/libs/services/account-activity-service/index.ts @@ -1,4 +1,3 @@ export * from './constants'; export * from './types'; -export * from './account-activity-service'; export * from './extended-deploys-service'; diff --git a/src/libs/services/account-activity-service/types.ts b/src/libs/services/account-activity-service/types.ts index 1b02c6011..42d8d9d85 100644 --- a/src/libs/services/account-activity-service/types.ts +++ b/src/libs/services/account-activity-service/types.ts @@ -1,6 +1,3 @@ -import { ErrorResponse, PaginatedResponse } from '@libs/services/types'; -import { CLTypeParsedResult, CLTypeTypeResult } from '@libs/types/cl'; - export interface TransferResult { amount: string; blockHash: string; @@ -19,137 +16,6 @@ export interface TransferResultWithId extends TransferResult { id: string; } -export interface MappedPendingTransaction extends ExtendedDeployWithId { - fromAccountPublicKey: string; - toAccountPublicKey: string; - amount: string; -} - -export type ExtendedDeployClTypeResult = { - cl_type: CLTypeTypeResult; - parsed: CLTypeParsedResult | string | null; -}; - -export type ExtendedDeployArgsResult = { - amount?: ExtendedDeployClTypeResult; - spender?: ExtendedDeployClTypeResult; - bsc_recipient_address?: ExtendedDeployClTypeResult; - contract_hash_str?: ExtendedDeployClTypeResult; - recipient?: ExtendedDeployClTypeResult; - token_id?: ExtendedDeployClTypeResult; - token_ids?: ExtendedDeployClTypeResult; - token_meta?: ExtendedDeployClTypeResult; - id?: ExtendedDeployClTypeResult; - target?: ExtendedDeployClTypeResult; - contract_name?: ExtendedDeployClTypeResult; - decimals?: ExtendedDeployClTypeResult; - initial_supply?: ExtendedDeployClTypeResult; - name?: ExtendedDeployClTypeResult; - symbol?: ExtendedDeployClTypeResult; - amount_in?: ExtendedDeployClTypeResult; - amount_out_min?: ExtendedDeployClTypeResult; - deadline?: ExtendedDeployClTypeResult; - path?: ExtendedDeployClTypeResult; - to?: ExtendedDeployClTypeResult; - validator?: ExtendedDeployClTypeResult; - new_validator?: ExtendedDeployClTypeResult; - delegator?: ExtendedDeployClTypeResult; -}; - -export interface ExtendedDeployResult { - // means it's a pending deploy - pending?: boolean; - amount: string | null; - args: ExtendedDeployArgsResult; - block_hash: string | null; - caller_public_key: string; - contract_hash: string | null; - contract_package_hash: string | null; - cost: string; - currency_cost: number; - deploy_hash: string; - error_message: string | null; - payment_amount: string | null; - status: string; - timestamp: string; - entry_point?: ExtendedDeployEntryPointResult; - contract_package?: ExtendedDeployContractPackageResult; - execution_type_id: 1 | 2 | 3 | 4 | 5 | 6; - rate: number; - error?: { message: string }; -} - -export interface ExtendedDeploy { - // means it's a pending deploy - pending?: boolean; - amount: string | null; - args: ExtendedDeployArgsResult; - blockHash: string | null; - callerPublicKey: string; - contractHash: string | null; - contractPackageHash: string | null; - cost: string; - deployHash: string; - errorMessage: string | null; - paymentAmount: string | null; - status: string; - timestamp: string; - entryPoint?: ExtendedDeployEntryPointResult; - contractPackage?: ExtendedDeployContractPackageResult; - executionTypeId: 1 | 2 | 3 | 4 | 5 | 6; - rate: number; - currencyCost: number; -} - -export interface ExtendedDeployWithId extends ExtendedDeploy { - id: string; -} - -export const MapExtendedDeploy = ({ - deploy_hash, - block_hash, - caller_public_key, - contract_hash, - contract_package_hash, - error_message, - payment_amount, - entry_point, - contract_package, - execution_type_id, - currency_cost, - rate, - ...rest -}: ExtendedDeployResult): ExtendedDeploy => ({ - ...rest, - deployHash: deploy_hash, - blockHash: block_hash, - callerPublicKey: caller_public_key, - contractHash: contract_hash, - contractPackageHash: contract_package_hash, - errorMessage: error_message, - paymentAmount: payment_amount, - entryPoint: entry_point, - contractPackage: contract_package, - executionTypeId: execution_type_id, - currencyCost: currency_cost, - rate: rate -}); - -export const MapPaginatedExtendedDeploys = ( - response: PaginatedResponse | ErrorResponse -): PaginatedResponse | ErrorResponse => { - if ('data' in response) { - return { - ...response, - data: response.data ? response.data.map(MapExtendedDeploy) : [] - }; - } - - return { - ...response - }; -}; - export type ExtendedDeployContractPackageMetadata = { symbol: string; decimals: number; @@ -179,14 +45,6 @@ export type ExtendedDeployContractPackageResult = { icon_url?: string; }; -export type ExtendedDeployEntryPointResult = { - action_type_id: null; - contract_hash: string | null; - contract_package_hash: string | null; - id: string | null; - name: string | null; -}; - export interface Erc20TokenActionResult { deploy_hash: string; contract_package_hash: string; @@ -239,21 +97,3 @@ export interface Metadata { balances_uref: string; total_supply_uref: string; } - -export type Erc20TransferWithId = { - id: string; - amount?: string; - deployHash: string; - callerPublicKey: string; - timestamp: string; - args: ExtendedDeployArgsResult; - status: string; - errorMessage: string | null; - decimals?: number; - symbol?: string; - toPublicKey?: string; - fromPublicKey?: string | null; - contractPackage?: ContractPackage | null; - toHash: string | null; - toType: string | null; -}; diff --git a/src/libs/services/deploys/index.ts b/src/libs/services/deploys/index.ts new file mode 100644 index 000000000..28a7cb361 --- /dev/null +++ b/src/libs/services/deploys/index.ts @@ -0,0 +1,3 @@ +export * from './use-fetch-cspr-transfer-deploys'; +export * from './use-fetch-cep18-transfer-deploys'; +export * from './use-fetch-deploys'; diff --git a/src/libs/services/deploys/use-fetch-cep18-transfer-deploys.ts b/src/libs/services/deploys/use-fetch-cep18-transfer-deploys.ts new file mode 100644 index 000000000..445f0e41b --- /dev/null +++ b/src/libs/services/deploys/use-fetch-cep18-transfer-deploys.ts @@ -0,0 +1,84 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; +import { CasperNetwork } from 'casper-wallet-core/src/domain/common/common'; +import { useEffect, useMemo } from 'react'; +import { useSelector } from 'react-redux'; + +import { accountCep18TransferDeploysDataChanged } from '@background/redux/account-info/actions'; +import { selectAccountCep18TransferDeploysData } from '@background/redux/account-info/selectors'; +import { selectActiveNetworkSetting } from '@background/redux/settings/selectors'; +import { dispatchToMainStore } from '@background/redux/utils'; +import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; +import { deploysRepository } from '@background/wallet-repositories'; + +export const useFetchCep18TransferDeploys = (contractPackageHash: string) => { + const cep18DeploysDataRecord = useSelector( + selectAccountCep18TransferDeploysData + ); + + const cep18DeploysData = cep18DeploysDataRecord + ? cep18DeploysDataRecord[contractPackageHash || ''] + : null; + + const activeAccount = useSelector(selectVaultActiveAccount); + const network = useSelector(selectActiveNetworkSetting); + + const { + data: cep18TransferDeploysData, + isLoading: isCep18TransferDeploysLoading, + fetchNextPage: fetchCep18TransferDeploysNextPage, + hasNextPage: hasCep18TransferDeploysNextPage = false + } = useInfiniteQuery({ + queryKey: [ + 'CEP18_TRANSFER_DEPLOYS', + network, + activeAccount?.publicKey, + contractPackageHash + ], + enabled: Boolean(activeAccount?.publicKey), + queryFn: ({ pageParam }) => + deploysRepository.getCep18TransferDeploys({ + network: network.toLowerCase() as CasperNetwork, + activePublicKey: activeAccount?.publicKey ?? '', + contractPackageHash, + page: pageParam + }), + getNextPageParam: (lastPage, _, lastPageParam) => { + const nextPage = + (cep18DeploysData?.pageParams.length || lastPageParam) + 1; + + return nextPage <= lastPage.pageCount ? nextPage : undefined; + }, + initialPageParam: 1 + }); + + const cep18TransferDeploys = useMemo( + () => + cep18DeploysData?.pages + ?.flat() + ?.map(t => t.data) + ?.flat() ?? [], + [cep18DeploysData?.pages] + ); + + useEffect(() => { + if (isCep18TransferDeploysLoading) return; + + dispatchToMainStore( + accountCep18TransferDeploysDataChanged({ + cep18TransferDeploysData, + contractPackageHash + }) + ); + }, [ + cep18TransferDeploysData, + contractPackageHash, + isCep18TransferDeploysLoading + ]); + + return { + cep18TransferDeploys, + isCep18TransferDeploysLoading, + hasCep18TransferDeploysNextPage, + fetchCep18TransferDeploysNextPage + }; +}; diff --git a/src/libs/services/deploys/use-fetch-cspr-transfer-deploys.ts b/src/libs/services/deploys/use-fetch-cspr-transfer-deploys.ts new file mode 100644 index 000000000..363c8f008 --- /dev/null +++ b/src/libs/services/deploys/use-fetch-cspr-transfer-deploys.ts @@ -0,0 +1,66 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; +import { CasperNetwork } from 'casper-wallet-core/src/domain/common/common'; +import { useEffect, useMemo } from 'react'; +import { useSelector } from 'react-redux'; + +import { accountCsprTransferDeploysDataChanged } from '@background/redux/account-info/actions'; +import { selectAccountCsprTransferDeploysData } from '@background/redux/account-info/selectors'; +import { selectActiveNetworkSetting } from '@background/redux/settings/selectors'; +import { dispatchToMainStore } from '@background/redux/utils'; +import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; +import { deploysRepository } from '@background/wallet-repositories'; + +export const useFetchCsprTransferDeploys = () => { + const csprDeploysData = useSelector(selectAccountCsprTransferDeploysData); + + const activeAccount = useSelector(selectVaultActiveAccount); + const network = useSelector(selectActiveNetworkSetting); + + const { + data: csprTransferDeploysData, + isLoading: isCsprTransferDeploysLoading, + isFetchingNextPage: isFetchingCsprTransferDeploysNextPage, + fetchNextPage: fetchCsprTransferDeploysNextPage, + hasNextPage: hasCsprTransferDeploysNextPage = false + } = useInfiniteQuery({ + enabled: Boolean(activeAccount?.publicKey), + queryKey: ['CSPR_TRANSFER_DEPLOYS', network, activeAccount?.publicKey], + queryFn: ({ pageParam }) => + deploysRepository.getCsprTransferDeploys({ + page: pageParam, + activePublicKey: activeAccount?.publicKey ?? '', + network: network.toLowerCase() as CasperNetwork + }), + getNextPageParam: (lastPage, _, lastPageParam) => { + const nextPage = + (csprDeploysData?.pageParams.length || lastPageParam) + 1; + + return nextPage <= lastPage.pageCount ? nextPage : undefined; + }, + initialPageParam: 1 + }); + + const csprTransferDeploys = useMemo( + () => + csprDeploysData?.pages + ?.flat() + ?.map(t => t.data) + ?.flat() ?? [], + [csprDeploysData?.pages] + ); + + useEffect(() => { + if (isCsprTransferDeploysLoading) return; + dispatchToMainStore( + accountCsprTransferDeploysDataChanged(csprTransferDeploysData) + ); + }, [csprTransferDeploysData, isCsprTransferDeploysLoading]); + + return { + csprTransferDeploys, + isCsprTransferDeploysLoading, + isFetchingCsprTransferDeploysNextPage, + fetchCsprTransferDeploysNextPage, + hasCsprTransferDeploysNextPage + }; +}; diff --git a/src/libs/services/deploys/use-fetch-deploys.tsx b/src/libs/services/deploys/use-fetch-deploys.tsx new file mode 100644 index 000000000..609a08d97 --- /dev/null +++ b/src/libs/services/deploys/use-fetch-deploys.tsx @@ -0,0 +1,128 @@ +import { useInfiniteQuery, useQuery } from '@tanstack/react-query'; +import { IDeploy } from 'casper-wallet-core'; +import { CasperNetwork } from 'casper-wallet-core/src/domain/common/common'; +import { useEffect, useMemo } from 'react'; +import { useSelector } from 'react-redux'; + +import { PENDING_DEPLOY_REFETCH_INTERVAL } from '@src/constants'; + +import { + accountDeploysDataChanged, + accountPendingDeployHashesRemove +} from '@background/redux/account-info/actions'; +import { + selectAccountDeploysData, + selectPendingDeployHashes +} from '@background/redux/account-info/selectors'; +import { selectActiveNetworkSetting } from '@background/redux/settings/selectors'; +import { dispatchToMainStore } from '@background/redux/utils'; +import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; +import { deploysRepository } from '@background/wallet-repositories'; + +export const useFetchDeploys = () => { + const deploysDataFromStore = useSelector(selectAccountDeploysData); + const pendingDeployHashes = useSelector(selectPendingDeployHashes); + const activeAccount = useSelector(selectVaultActiveAccount); + const network = useSelector(selectActiveNetworkSetting); + + const hasPendingDeploys = Boolean(pendingDeployHashes.length); + + const { + data: deploysData, + isLoading: isDeploysLoading, + refetch: refetchDeploys, + fetchNextPage: fetchDeploysNextPage, + hasNextPage: hasDeploysNextPage = false + } = useInfiniteQuery({ + queryKey: ['DEPLOYS', network, activeAccount?.publicKey], + enabled: Boolean(activeAccount?.publicKey), + queryFn: ({ pageParam }) => + deploysRepository.getDeploys({ + activePublicKey: activeAccount?.publicKey ?? '', + network: network.toLowerCase() as CasperNetwork, + page: pageParam + }), + getNextPageParam: (lastPage, _, lastPageParam) => { + const nextPage = + (deploysDataFromStore?.pageParams.length || lastPageParam) + 1; + + return nextPage <= lastPage.page_count ? nextPage : undefined; + }, + initialPageParam: 1 + }); + + const { data: pendingDeploys = [], isLoading: isPendingDeploysLoading } = + useQuery({ + queryKey: [ + 'PENDING_DEPLOYS', + network, + activeAccount?.publicKey, + pendingDeployHashes + ], + enabled: Boolean(activeAccount?.publicKey && hasPendingDeploys), + queryFn: async (): Promise => { + const promises = pendingDeployHashes.map(hash => + deploysRepository.getSingleDeploy({ + deployHash: hash, + activePublicKey: activeAccount?.publicKey ?? '', + network: network.toLowerCase() as CasperNetwork + }) + ); + + const deploys = await Promise.all(promises); + + return deploys.filter((d): d is IDeploy => Boolean(d)); + }, + staleTime: PENDING_DEPLOY_REFETCH_INTERVAL, + gcTime: PENDING_DEPLOY_REFETCH_INTERVAL, + refetchInterval: PENDING_DEPLOY_REFETCH_INTERVAL, + retry: 3 + }); + + const flattenedDeploys = useMemo( + () => + deploysDataFromStore?.pages + ?.flat() + ?.map(t => t.data) + ?.flat() ?? [], + [deploysDataFromStore?.pages] + ); + + const deploys = useMemo(() => { + return [ + // pending deploys fetched separately due to api restriction + ...pendingDeploys, + ...flattenedDeploys.filter( + d => + !pendingDeploys + .map(pd => pd.deployHash.toLowerCase()) + .includes(d.deployHash.toLowerCase()) + ) + ]; + }, [pendingDeploys, flattenedDeploys]); + + useEffect(() => { + if (isDeploysLoading) return; + dispatchToMainStore(accountDeploysDataChanged(deploysData)); + }, [deploysData, isDeploysLoading]); + + useEffect(() => { + if (isPendingDeploysLoading) return; + const notPendingDeploys = pendingDeploys.filter( + d => d.status !== 'pending' + ); + + notPendingDeploys.forEach(deploy => { + dispatchToMainStore( + accountPendingDeployHashesRemove(deploy.deployHash) + ).finally(refetchDeploys); + }); + }, [isPendingDeploysLoading, pendingDeploys, refetchDeploys]); + + return { + deploys, + isDeploysLoading: isDeploysLoading || isPendingDeploysLoading, + fetchDeploysNextPage, + hasDeploysNextPage + }; +}; diff --git a/src/libs/types/cl.ts b/src/libs/types/cl.ts deleted file mode 100644 index fc50e4906..000000000 --- a/src/libs/types/cl.ts +++ /dev/null @@ -1,30 +0,0 @@ -type CLTypeMapResult = { - Map: { - key: string; - value: string; - }; -}; - -type CLTypeMapParsedResult = { - key: string; - value: string; -}; - -type CLTypeOptionResult = { - Option: string; -}; - -export type CLTypeParsedAccountResult = { - Account: string; -}; - -export type CLTypeParsedListResult = (CLTypeMapParsedResult | string)[]; - -export type CLTypeTypeResult = CLTypeMapResult | CLTypeOptionResult | string; - -export type CLTypeParsedResult = - | CLTypeParsedListResult - | CLTypeParsedAccountResult - | CLTypeMapParsedResult - | string - | number; diff --git a/src/libs/ui/components/account-activity-plate/account-activity-plate.tsx b/src/libs/ui/components/account-activity-plate/account-activity-plate.tsx deleted file mode 100644 index 525f9d85f..000000000 --- a/src/libs/ui/components/account-activity-plate/account-activity-plate.tsx +++ /dev/null @@ -1,308 +0,0 @@ -import React, { forwardRef, useEffect, useState } from 'react'; -import { Trans, useTranslation } from 'react-i18next'; -import { useSelector } from 'react-redux'; -import styled from 'styled-components'; - -import { - ActivityShortTypeName, - ActivityType, - ActivityTypeColors, - ActivityTypeIcons, - ActivityTypeName, - AuctionManagerEntryPoint, - TokenEntryPoint -} from '@src/constants'; - -import { RouterPath, useTypedNavigate } from '@popup/router'; - -import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; - -import { getAccountHashFromPublicKey } from '@libs/entities/Account'; -import { - AccountActivityPlateContainer, - ActivityPlateContentContainer, - ActivityPlateDivider, - ActivityPlateIconCircleContainer, - AlignedFlexRow, - AlignedSpaceBetweenFlexRow, - RightAlignedCenteredFlexRow, - SpacingSize -} from '@libs/layout'; -import { - Erc20TransferWithId, - ExtendedDeployWithId -} from '@libs/services/account-activity-service'; -import { - DeployStatus, - Hash, - HashVariant, - SvgIcon, - Tooltip, - Typography -} from '@libs/ui/components'; -import { - ContentColor, - getRecipientAddressFromTransaction -} from '@libs/ui/utils'; -import { - divideErc20Balance, - formatNumber, - formatTimestamp, - formatTimestampAge, - motesToCSPR -} from '@libs/ui/utils/formatters'; - -const SymbolContainer = styled(RightAlignedCenteredFlexRow)` - max-width: 80px; -`; - -const AmountContainer = styled(RightAlignedCenteredFlexRow)` - max-width: 120px; -`; - -interface AccountActivityPlateProps { - transactionInfo: Erc20TransferWithId | ExtendedDeployWithId; - onClick?: () => void; - isDeploysList?: boolean; -} - -type Ref = HTMLDivElement; - -export const AccountActivityPlate = forwardRef( - ({ transactionInfo, onClick, isDeploysList }, ref) => { - const [type, setType] = useState(null); - const [fromAccount, setFromAccount] = useState( - undefined - ); - const [toAccount, setToAccount] = useState(undefined); - - const navigate = useTypedNavigate(); - const { t } = useTranslation(); - - const activeAccount = useSelector(selectVaultActiveAccount); - - const activeAccountHash = getAccountHashFromPublicKey( - activeAccount?.publicKey - ); - - const { deployHash, callerPublicKey, timestamp, args } = transactionInfo; - let decimals: number | undefined; - let symbol: string | undefined; - let amount: string | null = null; - - if ('contractPackage' in transactionInfo) { - decimals = transactionInfo?.contractPackage?.metadata?.decimals; - symbol = transactionInfo?.contractPackage?.metadata?.symbol; - } - - const { recipientAddress } = getRecipientAddressFromTransaction( - transactionInfo, - activeAccount?.publicKey || '' - ); - - const fromAccountPublicKey = - 'fromPublicKey' in transactionInfo && transactionInfo.fromPublicKey - ? transactionInfo.fromPublicKey - : callerPublicKey; - - try { - if (transactionInfo.amount) { - amount = - Number.isInteger(decimals) && decimals !== undefined - ? divideErc20Balance(transactionInfo.amount, decimals) - : motesToCSPR(transactionInfo.amount); - } else { - const parsedAmount = - ((typeof args?.amount?.parsed === 'string' || - typeof args?.amount?.parsed === 'number') && - args?.amount?.parsed) || - '-'; - - if (parsedAmount !== '-') { - const stringAmount = - typeof parsedAmount === 'number' - ? parsedAmount.toString() - : parsedAmount; - - amount = - Number.isInteger(decimals) && decimals !== undefined - ? divideErc20Balance(stringAmount, decimals) - : motesToCSPR(stringAmount); - } - } - } catch (error) { - console.error(error); - } - - const formattedAmount = amount - ? formatNumber(amount, { - precision: { min: 5 } - }) - : '-'; - - useEffect(() => { - if ('entryPoint' in transactionInfo) { - switch (transactionInfo.entryPoint?.name) { - case AuctionManagerEntryPoint.undelegate: { - setType(ActivityType.Undelegated); - setFromAccount(transactionInfo.args.validator?.parsed as string); - setToAccount(transactionInfo.args.delegator?.parsed as string); - return; - } - case AuctionManagerEntryPoint.delegate: { - setType(ActivityType.Delegated); - setFromAccount(transactionInfo.args.delegator?.parsed as string); - setToAccount(transactionInfo.args.validator?.parsed as string); - return; - } - case AuctionManagerEntryPoint.redelegate: { - setType(ActivityType.Redelegated); - setFromAccount(transactionInfo.args.validator?.parsed as string); - setToAccount(transactionInfo.args.new_validator?.parsed as string); - return; - } - case TokenEntryPoint.mint: { - setType(ActivityType.Mint); - setFromAccount(transactionInfo.callerPublicKey); - setToAccount(recipientAddress); - return; - } - case TokenEntryPoint.burn: { - setType(ActivityType.Burn); - setFromAccount(transactionInfo.callerPublicKey); - setToAccount(undefined); - return; - } - case TokenEntryPoint.transfer: { - if ( - transactionInfo?.args?.token_ids || - transactionInfo?.args?.token_id - ) { - setType(ActivityType.TransferNft); - setFromAccount(transactionInfo.callerPublicKey); - setToAccount(recipientAddress); - return; - } - } - } - } - - if (fromAccountPublicKey === activeAccount?.publicKey) { - setType(ActivityType.Sent); - } else if ( - recipientAddress === activeAccount?.publicKey || - recipientAddress === activeAccountHash - ) { - setType(ActivityType.Received); - } else { - setType(ActivityType.Unknown); - } - }, [ - fromAccountPublicKey, - activeAccount?.publicKey, - recipientAddress, - activeAccountHash, - transactionInfo - ]); - - return ( - { - navigate(RouterPath.ActivityDetails, { - state: { - activityDetailsData: { - fromAccount: fromAccount || fromAccountPublicKey, - toAccount: toAccount || recipientAddress, - deployHash, - type, - amount: formattedAmount, - symbol: symbol || '', - isDeploysList: isDeploysList - } - } - }); - if (onClick) { - onClick(); - } - }} - > - - {type != null && ( - - )} - - - - - - - {type != null && - (formattedAmount.length >= 13 - ? ActivityShortTypeName[type] - : ActivityTypeName[type])} - - - - - 11 ? formattedAmount : undefined} - > - - - {formattedAmount === '-' ? null : ( - <> - {type === ActivityType.Sent || - type === ActivityType.Delegated - ? '-' - : ''} - {formattedAmount} - - )} - - - - - - - - - - - {formatTimestampAge(timestamp)} - - - - {formattedAmount !== '-' && ( - 8 ? symbol : undefined}> - - - {symbol || 'CSPR'} - - - - )} - - - - - ); - } -); diff --git a/src/libs/ui/components/account-casper-activity-plate/account-casper-activity-plate.tsx b/src/libs/ui/components/account-casper-activity-plate/account-casper-activity-plate.tsx deleted file mode 100644 index f15f87b27..000000000 --- a/src/libs/ui/components/account-casper-activity-plate/account-casper-activity-plate.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React, { forwardRef, useEffect, useState } from 'react'; -import { Trans, useTranslation } from 'react-i18next'; -import { useSelector } from 'react-redux'; - -import { - ActivityShortTypeName, - ActivityType, - ActivityTypeColors, - ActivityTypeIcons, - ActivityTypeName -} from '@src/constants'; - -import { RouterPath, useTypedNavigate } from '@popup/router'; - -import { selectVaultActiveAccount } from '@background/redux/vault/selectors'; - -import { getAccountHashFromPublicKey } from '@libs/entities/Account'; -import { - AccountActivityPlateContainer, - ActivityPlateContentContainer, - ActivityPlateDivider, - ActivityPlateIconCircleContainer, - AlignedFlexRow, - AlignedSpaceBetweenFlexRow, - SpacingSize -} from '@libs/layout'; -import { TransferResultWithId } from '@libs/services/account-activity-service'; -import { - Hash, - HashVariant, - SvgIcon, - Tooltip, - Typography -} from '@libs/ui/components'; -import { - ContentColor, - formatNumber, - formatTimestamp, - formatTimestampAge, - motesToCSPR -} from '@libs/ui/utils'; - -type Ref = HTMLDivElement; - -interface AccountCasperActivityPlateProps { - transactionInfo: TransferResultWithId; - onClick?: () => void; -} -export const AccountCasperActivityPlate = forwardRef< - Ref, - AccountCasperActivityPlateProps ->(({ transactionInfo, onClick }, ref) => { - const [type, setType] = useState(null); - - const navigate = useTypedNavigate(); - const { t } = useTranslation(); - - const activeAccount = useSelector(selectVaultActiveAccount); - const activeAccountHash = getAccountHashFromPublicKey( - activeAccount?.publicKey - ); - - const { - deployHash, - fromAccountPublicKey, - timestamp, - amount, - toAccountPublicKey, - toAccount, - fromAccount, - targetPurse - } = transactionInfo; - - const formattedAmount = formatNumber(motesToCSPR(amount), { - precision: { min: 5 } - }); - - useEffect(() => { - if ( - fromAccountPublicKey === activeAccount?.publicKey || - fromAccount === activeAccountHash - ) { - setType(ActivityType.Sent); - } else if ( - toAccountPublicKey === activeAccount?.publicKey || - toAccount === activeAccountHash - ) { - setType(ActivityType.Received); - } else { - setType(ActivityType.Unknown); - } - }, [ - fromAccountPublicKey, - activeAccount?.publicKey, - toAccountPublicKey, - fromAccount, - activeAccountHash, - toAccount - ]); - - return ( - { - navigate(RouterPath.ActivityDetails, { - state: { - activityDetailsData: { - fromAccount: fromAccountPublicKey, - toAccount: toAccountPublicKey || toAccount || targetPurse, - deployHash, - type - } - } - }); - - if (onClick) { - onClick(); - } - }} - > - - {type != null && ( - - )} - - - - - - - {type != null && - (formattedAmount.length >= 13 - ? ActivityShortTypeName[type] - : ActivityTypeName[type])} - - - - - {type === ActivityType.Sent ? '-' : ''} - {formattedAmount} - - - - - - - - - {formatTimestampAge(timestamp)} - - - - - CSPR - - - - - - ); -}); diff --git a/src/libs/ui/components/account-info-icon/account-info-icon.tsx b/src/libs/ui/components/account-info-icon/account-info-icon.tsx new file mode 100644 index 000000000..03f20d67e --- /dev/null +++ b/src/libs/ui/components/account-info-icon/account-info-icon.tsx @@ -0,0 +1,81 @@ +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React from 'react'; +import { useSelector } from 'react-redux'; +import styled from 'styled-components'; + +import { DeployIcon } from '@src/constants'; +import { isEqualCaseInsensitive, isPublicKeyHash } from '@src/utils'; + +import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; + +import { Avatar, SvgIcon } from '@libs/ui/components'; + +interface AccountInfoIconProps { + iconUrl?: Maybe; + accountName?: Maybe; + publicKey: Maybe; + size?: number; + defaultSvg?: string; +} + +const LogoImg = styled.img<{ size: number }>` + width: ${({ size }) => size}px; + height: ${({ size }) => size}px; +`; + +export const AccountInfoIcon = ({ + iconUrl, + accountName, + publicKey, + size = 16, + defaultSvg +}: AccountInfoIconProps) => { + const { + auctionPoolContractHash, + associatedKeysContractHash, + csprStudioCep47ContractHash, + csprMarketContractHash + } = useSelector(selectApiConfigBasedOnActiveNetwork); + + if (publicKey && isEqualCaseInsensitive(publicKey, auctionPoolContractHash)) { + return ; + } else if ( + publicKey && + isEqualCaseInsensitive(publicKey, associatedKeysContractHash) + ) { + return ; + } else if ( + publicKey && + isEqualCaseInsensitive(publicKey, csprStudioCep47ContractHash) + ) { + return ; + } else if ( + publicKey && + isEqualCaseInsensitive(publicKey, csprMarketContractHash) + ) { + return ; + } + + if (iconUrl) { + return iconUrl.endsWith('.svg') ? ( + + ) : ( + + ); + } + + if (defaultSvg && !isPublicKeyHash(publicKey)) { + return ; + } + + if (publicKey?.startsWith('uref')) { + return null; + } + + return ; +}; diff --git a/src/libs/ui/components/account-info-row/account-info-row.tsx b/src/libs/ui/components/account-info-row/account-info-row.tsx new file mode 100644 index 000000000..2c05469fd --- /dev/null +++ b/src/libs/ui/components/account-info-row/account-info-row.tsx @@ -0,0 +1,151 @@ +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React, { useCallback, useMemo } from 'react'; +import { Trans, useTranslation } from 'react-i18next'; +import { useSelector } from 'react-redux'; +import styled from 'styled-components'; + +import { getBlockExplorerAccountUrl } from '@src/constants'; +import { isEqualCaseInsensitive } from '@src/utils'; + +import { selectAllContacts } from '@background/redux/contacts/selectors'; +import { selectApiConfigBasedOnActiveNetwork } from '@background/redux/settings/selectors'; +import { selectVaultAccounts } from '@background/redux/vault/selectors'; + +import { AlignedFlexRow } from '@libs/layout'; +import { Hash, HashVariant, Link, Typography } from '@libs/ui/components'; +import { AccountInfoIcon } from '@libs/ui/components/account-info-icon/account-info-icon'; + +interface AccountInfoRowProps { + publicKey: Maybe; + label?: string; + accountName?: string; + imgLogo?: Maybe; + children?: React.ReactNode; + iconSize?: number; + isAction?: boolean; +} + +const AccountInfoContainer = styled(AlignedFlexRow)` + column-gap: 8px; + flex-wrap: wrap; +`; + +const AccountInfoNameContainer = styled(AlignedFlexRow)` + column-gap: 8px; + flex-wrap: wrap; +`; + +export const AccountInfoRow = ({ + publicKey, + label, + accountName, + imgLogo, + children, + iconSize = 16, + isAction = false +}: AccountInfoRowProps) => { + const { t } = useTranslation(); + + const accounts = useSelector(selectVaultAccounts); + const contacts = useSelector(selectAllContacts); + const { + casperLiveUrl, + auctionPoolContractHash, + csprStudioCep47ContractHash, + csprMarketContractHash + } = useSelector(selectApiConfigBasedOnActiveNetwork); + + const link = getBlockExplorerAccountUrl(casperLiveUrl, publicKey || ''); + + const accountLabel = useMemo( + () => accounts.find(acc => acc.publicKey === publicKey)?.name, + [publicKey, accounts] + ); + const contactName = useMemo( + () => contacts.find(contact => contact.publicKey === publicKey)?.name, + [publicKey, contacts] + ); + + const name = accountLabel || accountName || contactName || ''; + + const getContractName = useCallback(() => { + if ( + publicKey && + isEqualCaseInsensitive(publicKey, auctionPoolContractHash) + ) { + return 'Auction Pool'; + } else if ( + publicKey && + isEqualCaseInsensitive(publicKey, csprStudioCep47ContractHash) + ) { + return 'CSPR.studio'; + } else if ( + publicKey && + isEqualCaseInsensitive(publicKey, csprMarketContractHash) + ) { + return 'CSPR.market'; + } + }, [ + auctionPoolContractHash, + csprMarketContractHash, + csprStudioCep47ContractHash, + publicKey + ]); + + const contractName = getContractName(); + + return ( + + {children} + {publicKey && ( + <> + + + {label && ( + + {label} + + )} + + {contractName ? ( + + {contractName} + + ) : ( + <> + + {name && ( + + {name} + + )} + + )} + + + + )} + + ); +}; diff --git a/src/libs/ui/components/avatar/avatar.tsx b/src/libs/ui/components/avatar/avatar.tsx index 64fd0d180..6f2045038 100644 --- a/src/libs/ui/components/avatar/avatar.tsx +++ b/src/libs/ui/components/avatar/avatar.tsx @@ -1,3 +1,4 @@ +import { Maybe } from 'casper-wallet-core/src/typings/common'; import React from 'react'; import styled, { DefaultTheme, useTheme } from 'styled-components'; @@ -61,7 +62,7 @@ const ConnectIcon = styled(SvgIcon)<{ `; interface AvatarTypes { - publicKey: string; + publicKey: Maybe; size: number; top?: SpacingSize; withConnectedStatus?: boolean; @@ -98,7 +99,7 @@ export const Avatar = ({ { - const accountCasperActivityList = useSelector(selectAccountCasperActivity); - - const { loading, loadMoreAccountCasperActivity, hasNextPage } = - useFetchCasperTokenAccountActivity(); - const [sentryRef] = useInfiniteScroll({ - loading, - hasNextPage, - onLoadMore: loadMoreAccountCasperActivity, - delayInMs: 0 - }); - useEffect(() => { - const container = document.querySelector('#ms-container'); - - const position = localStorage.getItem('casperTokenYPosition'); - - if (position) { - container?.scrollTo(0, Number(position)); - localStorage.removeItem('casperTokenYPosition'); - } - }, []); - - const setCasperTokenYPosition = () => { - const container = document.querySelector('#ms-container'); - - localStorage.setItem( - 'casperTokenYPosition', - container?.scrollTop.toString() || '' - ); - }; - - return ( - <> - {accountCasperActivityList != null && - accountCasperActivityList.length > 0 && ( - ( - - )} - marginLeftForItemSeparatorLine={54} - /> - )} - - {(loading || hasNextPage) && } - - {accountCasperActivityList == null || - (accountCasperActivityList.length === 0 && !loading && ( - - ))} - - ); -}; diff --git a/src/libs/ui/components/casper-token-transfer-deploys-list/casper-token-transfer-deploys-list.tsx b/src/libs/ui/components/casper-token-transfer-deploys-list/casper-token-transfer-deploys-list.tsx new file mode 100644 index 000000000..c3d5102e3 --- /dev/null +++ b/src/libs/ui/components/casper-token-transfer-deploys-list/casper-token-transfer-deploys-list.tsx @@ -0,0 +1,66 @@ +import React, { useEffect } from 'react'; +import useInfiniteScroll from 'react-infinite-scroll-hook'; + +import { SpacingSize } from '@libs/layout'; +import { useFetchCsprTransferDeploys } from '@libs/services/deploys'; +import { List, LoadingActivityView, NoActivityView } from '@libs/ui/components'; +import { DeployPlate } from '@libs/ui/components/deploy-plate/deploy-plate'; + +export const CasperTokenTransferDeploysList = () => { + const { + csprTransferDeploys, + isCsprTransferDeploysLoading, + hasCsprTransferDeploysNextPage, + fetchCsprTransferDeploysNextPage + } = useFetchCsprTransferDeploys(); + const [sentryRef] = useInfiniteScroll({ + loading: isCsprTransferDeploysLoading, + hasNextPage: hasCsprTransferDeploysNextPage, + onLoadMore: fetchCsprTransferDeploysNextPage, + delayInMs: 0 + }); + + useEffect(() => { + const container = document.querySelector('#ms-container'); + + const position = localStorage.getItem('casperTokenYPosition'); + + if (position) { + container?.scrollTo(0, Number(position)); + localStorage.removeItem('casperTokenYPosition'); + } + }, []); + + const setCasperTokenYPosition = () => { + const container = document.querySelector('#ms-container'); + + localStorage.setItem( + 'casperTokenYPosition', + container?.scrollTop.toString() || '' + ); + }; + + return ( + <> + {csprTransferDeploys != null && csprTransferDeploys.length > 0 && ( + ( + + )} + marginLeftForItemSeparatorLine={54} + /> + )} + + {(isCsprTransferDeploysLoading || hasCsprTransferDeploysNextPage) && ( + + )} + + {csprTransferDeploys == null || + (csprTransferDeploys.length === 0 && !isCsprTransferDeploysLoading && ( + + ))} + + ); +}; diff --git a/src/libs/ui/components/cep18-token-deploys-list/cep18-token-deploys-list.tsx b/src/libs/ui/components/cep18-token-deploys-list/cep18-token-deploys-list.tsx new file mode 100644 index 000000000..be58689c2 --- /dev/null +++ b/src/libs/ui/components/cep18-token-deploys-list/cep18-token-deploys-list.tsx @@ -0,0 +1,72 @@ +import React, { useEffect } from 'react'; +import useInfiniteScroll from 'react-infinite-scroll-hook'; +import { useParams } from 'react-router-dom'; + +import { SpacingSize } from '@libs/layout'; +import { useFetchCep18TransferDeploys } from '@libs/services/deploys'; +import { List, LoadingActivityView, NoActivityView } from '@libs/ui/components'; +import { DeployPlate } from '@libs/ui/components/deploy-plate/deploy-plate'; + +export const Cep18TokenDeploysList = () => { + const { tokenName } = useParams(); + + const { + cep18TransferDeploys, + isCep18TransferDeploysLoading, + hasCep18TransferDeploysNextPage, + fetchCep18TransferDeploysNextPage + } = useFetchCep18TransferDeploys(tokenName || ''); + + const [sentryRef] = useInfiniteScroll({ + loading: isCep18TransferDeploysLoading, + hasNextPage: hasCep18TransferDeploysNextPage, + onLoadMore: fetchCep18TransferDeploysNextPage, + delayInMs: 0 + }); + + useEffect(() => { + const container = document.querySelector('#ms-container'); + + const position = localStorage.getItem('Erc20TokenYPosition'); + + if (position) { + container?.scrollTo(0, Number(position)); + localStorage.removeItem('Erc20TokenYPosition'); + } + }, []); + + const setCep18TokenYPosition = () => { + const container = document.querySelector('#ms-container'); + + localStorage.setItem( + 'Erc20TokenYPosition', + container?.scrollTop.toString() || '' + ); + }; + + const noActivityForErc20 = + cep18TransferDeploys == null || cep18TransferDeploys.length === 0; + + return ( + <> + {cep18TransferDeploys.length > 0 && ( + ( + + )} + marginLeftForItemSeparatorLine={54} + /> + )} + + {(isCep18TransferDeploysLoading || hasCep18TransferDeploysNextPage) && ( + + )} + + {noActivityForErc20 && !isCep18TransferDeploysLoading && ( + + )} + + ); +}; diff --git a/src/libs/ui/components/deploy-plate/components/associated-deploy-rows.tsx b/src/libs/ui/components/deploy-plate/components/associated-deploy-rows.tsx new file mode 100644 index 000000000..59e0c7499 --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/associated-deploy-rows.tsx @@ -0,0 +1,31 @@ +import { IAssociatedKeysDeploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { DeployIcon } from '@src/constants'; + +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { ContractRow } from '@libs/ui/components/deploy-plate/components/common'; +import { DeployContainer } from '@libs/ui/components/deploy-plate/components/deploy-container'; + +interface AssociatedDeployRowsProps { + deploy: IAssociatedKeysDeploy; +} + +export const AssociatedDeployRows = ({ deploy }: AssociatedDeployRowsProps) => { + const title = getEntryPointName(deploy); + + return ( + + + + ); +}; diff --git a/src/libs/ui/components/deploy-plate/components/auction-deploy-rows.tsx b/src/libs/ui/components/deploy-plate/components/auction-deploy-rows.tsx new file mode 100644 index 000000000..cb9048f1c --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/auction-deploy-rows.tsx @@ -0,0 +1,193 @@ +import { IAccountInfo } from 'casper-wallet-core/src/domain/accountInfo'; +import { + AuctionEntryPointType, + IAuctionDeploy +} from 'casper-wallet-core/src/domain/deploys/entities'; +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React from 'react'; +import { Trans, useTranslation } from 'react-i18next'; + +import { AuctionDeployEntryPoint, DeployIcon } from '@src/constants'; + +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { Typography } from '@libs/ui/components'; +import { AccountInfoIcon } from '@libs/ui/components/account-info-icon/account-info-icon'; +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; +import { DeployContainer } from '@libs/ui/components/deploy-plate/components/deploy-container'; + +interface AuctionDeployRowsProps { + deploy: IAuctionDeploy; +} + +const ValidatorAccountInfo = ({ + publicKey, + label, + withHash, + imgLogo, + accountName +}: { + publicKey: Maybe; + label: string; + withHash?: boolean; + imgLogo?: Maybe; + accountName?: string; +}) => { + const { t } = useTranslation(); + + if (withHash) { + return ( + + ); + } + + return ( + <> + + {label} + + + + ); +}; + +const ManageAuctionBidAction = ({ amount }: { amount: string }) => ( + + {amount} + + CSPR + + +); + +const DelegationAuctionAction = ({ + amount, + entryPoint, + toValidator, + fromValidator, + toValidatorAccountInfo, + fromValidatorAccountInfo +}: { + amount: string; + entryPoint: AuctionEntryPointType; + toValidator: Maybe; + fromValidator: Maybe; + toValidatorAccountInfo: Maybe; + fromValidatorAccountInfo: Maybe; +}) => { + const isDelegate = entryPoint === AuctionDeployEntryPoint.delegate; + const isUndelegate = entryPoint === AuctionDeployEntryPoint.undelegate; + const isRedelegate = entryPoint === AuctionDeployEntryPoint.redelegate; + + return ( + <> + + {amount} + + CSPR + + + + {(isDelegate || isUndelegate) && ( + + )} + {isRedelegate && ( + <> + + + + )} + + + ); +}; + +export const AuctionDeployRows = ({ deploy }: AuctionDeployRowsProps) => { + const { entryPoint, formattedDecimalAmount } = deploy; + const isManageAuctionBidDeploy = + entryPoint === AuctionDeployEntryPoint.activate || + entryPoint === AuctionDeployEntryPoint.withdraw || + entryPoint === AuctionDeployEntryPoint.add; + + const isDelegationDeploy = + entryPoint === AuctionDeployEntryPoint.delegate || + entryPoint === AuctionDeployEntryPoint.undelegate || + entryPoint === AuctionDeployEntryPoint.redelegate; + + const title = getEntryPointName(deploy); + + if (isManageAuctionBidDeploy) { + return ( + + + + ); + } + + if (isDelegationDeploy) { + return ( + + + + ); + } + + return null; +}; diff --git a/src/libs/ui/components/deploy-plate/components/cep18-deploy-rows.tsx b/src/libs/ui/components/deploy-plate/components/cep18-deploy-rows.tsx new file mode 100644 index 000000000..c470b3560 --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/cep18-deploy-rows.tsx @@ -0,0 +1,63 @@ +import { ICep18Deploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { Cep18DeployEntryPoint, DeployIcon } from '@src/constants'; + +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { Typography } from '@libs/ui/components'; +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; +import { DeployContainer } from '@libs/ui/components/deploy-plate/components/deploy-container'; + +interface Erc20DeployRowsProps { + deploy: ICep18Deploy; +} + +export const Cep18DeployRows = ({ deploy }: Erc20DeployRowsProps) => { + const { entryPoint } = deploy; + const isTransfer = entryPoint === Cep18DeployEntryPoint.transfer; + const title = getEntryPointName(deploy); + + return ( + + + + {deploy.formattedDecimalAmount} + + + {deploy.symbol} + + + {isTransfer ? ( + + + {deploy.contractName} + + + ) : ( + + + {deploy.contractName} + + + )} + + ); +}; diff --git a/src/libs/ui/components/deploy-plate/components/common.tsx b/src/libs/ui/components/deploy-plate/components/common.tsx new file mode 100644 index 000000000..fbcc37991 --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/common.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { Trans, useTranslation } from 'react-i18next'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { Typography } from '@libs/ui/components'; + +export const ContractRow = ({ + label, + contractName +}: { + label: string; + contractName: string; +}) => { + const { t } = useTranslation(); + + return ( + + + {label} + + + {contractName} + + + ); +}; diff --git a/src/libs/ui/components/deploy-plate/components/cspr-market-deploy-rows.tsx b/src/libs/ui/components/deploy-plate/components/cspr-market-deploy-rows.tsx new file mode 100644 index 000000000..86b24cf84 --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/cspr-market-deploy-rows.tsx @@ -0,0 +1,72 @@ +import { ICasperMarketDeploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { CsprMarketDeployEntryPoint, DeployIcon } from '@src/constants'; + +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { Typography } from '@libs/ui/components'; +import { ContractRow } from '@libs/ui/components/deploy-plate/components/common'; +import { DefaultDeployRows } from '@libs/ui/components/deploy-plate/components/default-deploy-rows'; +import { DeployContainer } from '@libs/ui/components/deploy-plate/components/deploy-container'; + +interface CSPRMarketDeployRowsProps { + deploy: ICasperMarketDeploy; +} + +export const CSPRMarketDeployRows = ({ deploy }: CSPRMarketDeployRowsProps) => { + const { entryPoint } = deploy; + + const isDelist = entryPoint === CsprMarketDeployEntryPoint.delist_token; + const isListAction = + entryPoint === CsprMarketDeployEntryPoint.delist_token || + entryPoint === CsprMarketDeployEntryPoint.list_token; + const isOfferAction = + entryPoint === CsprMarketDeployEntryPoint.accept_offer || + entryPoint === CsprMarketDeployEntryPoint.make_offer || + entryPoint === CsprMarketDeployEntryPoint.cancel_offer; + + const title = getEntryPointName(deploy); + + if (isListAction) { + return ( + + + {deploy.amountOfNFTs} + NFT(s) + + + + ); + } + + if (isOfferAction) { + return ( + + + + ); + } + + return ; +}; diff --git a/src/libs/ui/components/deploy-plate/components/default-deploy-rows.tsx b/src/libs/ui/components/deploy-plate/components/default-deploy-rows.tsx new file mode 100644 index 000000000..8dd8d88e3 --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/default-deploy-rows.tsx @@ -0,0 +1,33 @@ +import { IDeploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { DeployIcon } from '@src/constants'; + +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { ContractRow } from '@libs/ui/components/deploy-plate/components/common'; +import { DeployContainer } from '@libs/ui/components/deploy-plate/components/deploy-container'; + +interface DefaultDeployRowsProps { + deploy: IDeploy; +} + +export const DefaultDeployRows = ({ deploy }: DefaultDeployRowsProps) => { + const title = getEntryPointName(deploy); + + return ( + + {deploy.contractName && ( + + )} + + ); +}; diff --git a/src/libs/ui/components/deploy-plate/components/deploy-container.tsx b/src/libs/ui/components/deploy-plate/components/deploy-container.tsx new file mode 100644 index 000000000..89bc66039 --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/deploy-container.tsx @@ -0,0 +1,59 @@ +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React from 'react'; +import styled from 'styled-components'; + +import { AlignedFlexRow, FlexColumn, SpacingSize } from '@libs/layout'; +import { DeployStatus, SvgIcon, Typography } from '@libs/ui/components'; +import { formatTimestampAge } from '@libs/ui/utils'; + +interface DeployContainerProps { + children?: React.ReactNode; + iconUrl: string; + title: Maybe; + timestamp: string; + deployStatus: { status: string; errorMessage: string | null }; +} + +const Dot = styled.div` + height: 2px; + width: 2px; + background-color: ${props => props.theme.color.contentSecondary}; + border-radius: 50%; + display: inline-block; +`; + +const LogoImg = styled.img` + width: 24px; + height: 24px; +`; + +export const DeployContainer = ({ + children, + iconUrl, + title, + timestamp, + deployStatus +}: DeployContainerProps) => { + return ( + + {iconUrl.endsWith('.svg') ? ( + + ) : ( + + )} + + + + {title} + + + + + {formatTimestampAge(timestamp)} + + + {children} + + + ); +}; diff --git a/src/libs/ui/components/deploy-plate/components/native-transfer-deploy-rows.tsx b/src/libs/ui/components/deploy-plate/components/native-transfer-deploy-rows.tsx new file mode 100644 index 000000000..2217fd638 --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/native-transfer-deploy-rows.tsx @@ -0,0 +1,53 @@ +import { INativeCsprDeploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import React from 'react'; + +import { DeployIcon } from '@src/constants'; + +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { Typography } from '@libs/ui/components'; +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; +import { DeployContainer } from '@libs/ui/components/deploy-plate/components/deploy-container'; + +interface NativeTransferDeployRowsProps { + deploy: INativeCsprDeploy; +} + +export const NativeTransferDeployRows = ({ + deploy +}: NativeTransferDeployRowsProps) => { + const title = getEntryPointName(deploy); + + return ( + + + + {deploy.formattedDecimalAmount} + + + CSPR + + + + + ); +}; diff --git a/src/libs/ui/components/deploy-plate/components/nft-deploy-rows.tsx b/src/libs/ui/components/deploy-plate/components/nft-deploy-rows.tsx new file mode 100644 index 000000000..7025f7cb3 --- /dev/null +++ b/src/libs/ui/components/deploy-plate/components/nft-deploy-rows.tsx @@ -0,0 +1,91 @@ +import { INftDeploy } from 'casper-wallet-core/src/domain/deploys/entities'; +import { Maybe } from 'casper-wallet-core/src/typings/common'; +import React from 'react'; + +import { DeployIcon, NftDeployEntryPoint } from '@src/constants'; + +import { getEntryPointName } from '@popup/pages/deploy-details/utils'; + +import { AlignedFlexRow, SpacingSize } from '@libs/layout'; +import { Typography } from '@libs/ui/components'; +import { AccountInfoRow } from '@libs/ui/components/account-info-row/account-info-row'; +import { ContractRow } from '@libs/ui/components/deploy-plate/components/common'; +import { DeployContainer } from '@libs/ui/components/deploy-plate/components/deploy-container'; + +interface NftDeployRowsProps { + deploy: INftDeploy; +} + +const NftAmount = ({ amountOfNFTs }: { amountOfNFTs: Maybe }) => ( + + {amountOfNFTs} + NFT(s) + +); + +export const NftDeployRows = ({ deploy }: NftDeployRowsProps) => { + const { entryPoint } = deploy; + const isBurn = entryPoint === NftDeployEntryPoint.burn; + const isMint = entryPoint === NftDeployEntryPoint.mint; + const isTransfer = entryPoint === NftDeployEntryPoint.transfer; + const isApprove = + entryPoint === NftDeployEntryPoint.approve || + entryPoint === NftDeployEntryPoint.set_approval_for_all; + + const title = getEntryPointName(deploy); + + return ( + + {isBurn && ( + <> + + + + )} + {isApprove && ( + <> + + + + + + )} + {(isMint || isTransfer) && ( + <> + + + + + + )} + {!(isBurn || isMint || isTransfer || isApprove) && ( + + )} + + ); +}; diff --git a/src/libs/ui/components/deploy-plate/deploy-plate.tsx b/src/libs/ui/components/deploy-plate/deploy-plate.tsx new file mode 100644 index 000000000..79694de0e --- /dev/null +++ b/src/libs/ui/components/deploy-plate/deploy-plate.tsx @@ -0,0 +1,192 @@ +import { IDeploy } from 'casper-wallet-core'; +import { + isAssociatedKeysDeploy, + isAuctionDeploy, + isCasperMarketDeploy, + isCep18Deploy, + isNativeCsprDeploy, + isNftDeploy, + isWasmDeployExecutionType +} from 'casper-wallet-core/src/utils/deploy'; +import React from 'react'; +import styled from 'styled-components'; + +import { RouterPath, useTypedNavigate } from '@popup/router'; + +import { AlignedSpaceBetweenFlexRow } from '@libs/layout'; +import { SvgIcon } from '@libs/ui/components'; +import { AssociatedDeployRows } from '@libs/ui/components/deploy-plate/components/associated-deploy-rows'; +import { AuctionDeployRows } from '@libs/ui/components/deploy-plate/components/auction-deploy-rows'; +import { Cep18DeployRows } from '@libs/ui/components/deploy-plate/components/cep18-deploy-rows'; +import { CSPRMarketDeployRows } from '@libs/ui/components/deploy-plate/components/cspr-market-deploy-rows'; +import { DefaultDeployRows } from '@libs/ui/components/deploy-plate/components/default-deploy-rows'; +import { NativeTransferDeployRows } from '@libs/ui/components/deploy-plate/components/native-transfer-deploy-rows'; +import { NftDeployRows } from '@libs/ui/components/deploy-plate/components/nft-deploy-rows'; + +const Container = styled(AlignedSpaceBetweenFlexRow)` + padding: 16px 12px 16px; + + background: ${props => props.theme.color.backgroundPrimary}; + + cursor: pointer; +`; + +interface DeployPlateProps { + deploy: IDeploy; + onClick?: () => void; + navigateHome?: boolean; +} + +export const DeployPlate = ({ + deploy, + onClick, + navigateHome = false +}: DeployPlateProps) => { + const navigate = useTypedNavigate(); + + if (isNativeCsprDeploy(deploy)) { + return ( + { + navigate(RouterPath.DeployDetails, { + state: { + deploy, + navigateHome + } + }); + + if (onClick) { + onClick(); + } + }} + > + + + + ); + } + + if (isWasmDeployExecutionType(deploy)) { + return ( + { + navigate(RouterPath.DeployDetails, { + state: { + deploy, + navigateHome + } + }); + }} + > + + + + ); + } + + if (isAuctionDeploy(deploy)) { + return ( + { + navigate(RouterPath.DeployDetails, { + state: { + deploy, + navigateHome + } + }); + }} + > + + + + ); + } + + if (isAssociatedKeysDeploy(deploy)) { + return ( + { + navigate(RouterPath.DeployDetails, { + state: { + deploy, + navigateHome + } + }); + }} + > + + + + ); + } + + if (isCasperMarketDeploy(deploy)) { + return ( + { + navigate(RouterPath.DeployDetails, { + state: { + deploy, + navigateHome + } + }); + }} + > + + + + ); + } + // + if (isCep18Deploy(deploy)) { + return ( + { + navigate(RouterPath.DeployDetails, { + state: { + deploy, + navigateHome + } + }); + }} + > + + + + ); + } + + if (isNftDeploy(deploy)) { + return ( + { + navigate(RouterPath.DeployDetails, { + state: { + deploy, + navigateHome + } + }); + }} + > + + + + ); + } + + return ( + { + navigate(RouterPath.DeployDetails, { + state: { + deploy, + navigateHome + } + }); + }} + > + + + + ); +}; diff --git a/src/libs/ui/components/deploy-status/deploy-status.tsx b/src/libs/ui/components/deploy-status/deploy-status.tsx index 03034bb6a..6562909f8 100644 --- a/src/libs/ui/components/deploy-status/deploy-status.tsx +++ b/src/libs/ui/components/deploy-status/deploy-status.tsx @@ -8,15 +8,18 @@ import { ContentColor } from '@libs/ui/utils'; export enum Status { Success = 'success', + Processed = 'processed', Error = 'error', + /** @deprecated Became 'Processed' */ Executed = 'executed', Pending = 'pending', Expired = 'expired' } const StatusIcons = { - [Status.Success]: 'assets/icons/tick-in-circle.svg', - [Status.Executed]: 'assets/icons/tick-in-circle.svg', + [Status.Success]: 'assets/icons/clock.svg', + [Status.Executed]: 'assets/icons/clock.svg', + [Status.Processed]: 'assets/icons/clock.svg', [Status.Pending]: 'assets/icons/clock.svg', [Status.Error]: 'assets/icons/error.svg', [Status.Expired]: 'assets/icons/error.svg' @@ -25,6 +28,7 @@ const StatusIcons = { const StatusColors = { [Status.Success]: 'contentPositive', [Status.Executed]: 'contentPositive', + [Status.Processed]: 'contentPositive', [Status.Pending]: 'contentLightBlue', [Status.Error]: 'contentActionCritical', [Status.Expired]: 'contentActionCritical' @@ -34,17 +38,19 @@ const StatusColors = { const StatusBackgroundColors = { [Status.Success]: 'rgba(119, 255, 190, 0.12)', [Status.Executed]: 'rgba(119, 255, 190, 0.12)', + [Status.Processed]: 'rgba(119, 255, 190, 0.12)', [Status.Pending]: 'rgba(116, 144, 255, 0.12)', [Status.Error]: 'rgba(204, 0, 15, 0.08)', [Status.Expired]: 'rgba(204, 0, 15, 0.08)' }; -const getDeployStatus = ( +export const getDeployStatus = ( deployResult?: { status: string; errorMessage: string | null } | null ): Status => { if ( deployResult && deployResult?.status && + deployResult?.status !== Status.Processed && deployResult?.status !== Status.Executed ) { return deployResult?.status as Status; @@ -67,7 +73,7 @@ export interface DeployStatusProps { const StatusContainer = styled(AlignedFlexRow)<{ status: Status }>( ({ theme, status }) => ({ - padding: '4px 8px', + padding: '2px 8px', backgroundColor: StatusBackgroundColors[status], borderRadius: theme.borderRadius.hundred @@ -86,6 +92,7 @@ export const DeployStatus = ({ [Status.Success]: t('Success'), [Status.Error]: t('Error'), [Status.Executed]: t('Executed'), + [Status.Processed]: t('Processed'), [Status.Pending]: t('Pending'), [Status.Expired]: t('Expired') }; @@ -100,11 +107,12 @@ export const DeployStatus = ({ {StatusLabel[status]} @@ -113,18 +121,17 @@ export const DeployStatus = ({ ); } - if (status === Status.Success) { - return null; + if (status === Status.Error || status === Status.Pending) { + return ( + + + + ); } - return ( - - - {StatusLabel[status]} - - - ); + return null; }; diff --git a/src/libs/ui/components/erc20-token-activity-list/erc20-token-activity-list.tsx b/src/libs/ui/components/erc20-token-activity-list/erc20-token-activity-list.tsx deleted file mode 100644 index f0d6ca1e4..000000000 --- a/src/libs/ui/components/erc20-token-activity-list/erc20-token-activity-list.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import React, { useEffect } from 'react'; -import useInfiniteScroll from 'react-infinite-scroll-hook'; -import { useSelector } from 'react-redux'; -import { useParams } from 'react-router-dom'; - -import { selectAccountErc20TokensActivity } from '@background/redux/account-info/selectors'; - -import { useFetchErc20TokenAccountActivity } from '@hooks/use-fetch-erc20-token-account-activity'; - -import { SpacingSize } from '@libs/layout'; -import { Erc20TransferWithId } from '@libs/services/account-activity-service'; -import { - AccountActivityPlate, - List, - LoadingActivityView, - NoActivityView -} from '@libs/ui/components'; - -export const Erc20TokenActivityList = () => { - const erc20TokensActivityRecord = - useSelector(selectAccountErc20TokensActivity) || {}; - - const { tokenName } = useParams(); - - const tokenActivity = erc20TokensActivityRecord[tokenName || ''] || {}; - - const { loading, loadMoreAccountErc20Activity, hasNextPage } = - useFetchErc20TokenAccountActivity(tokenName || ''); - const [sentryRef] = useInfiniteScroll({ - loading, - hasNextPage, - onLoadMore: loadMoreAccountErc20Activity, - delayInMs: 0 - }); - - useEffect(() => { - const container = document.querySelector('#ms-container'); - - const position = localStorage.getItem('Erc20TokenYPosition'); - - if (position) { - container?.scrollTo(0, Number(position)); - localStorage.removeItem('Erc20TokenYPosition'); - } - }, []); - - const setErc20TokenYPosition = () => { - const container = document.querySelector('#ms-container'); - - localStorage.setItem( - 'Erc20TokenYPosition', - container?.scrollTop.toString() || '' - ); - }; - - const erc20Transactions: Erc20TransferWithId[] = - tokenActivity?.tokenActivityList?.map((transaction, index) => { - return { - id: String(index), - amount: transaction.amount, - deployHash: transaction.deploy_hash, - callerPublicKey: transaction.deploy?.caller_public_key || '-', - timestamp: transaction.deploy?.timestamp || '-', - args: transaction.deploy?.args || '-', - status: transaction.deploy?.status || '-', - errorMessage: transaction.deploy?.error_message || null, - decimals: transaction.contract_package?.metadata?.decimals, - symbol: transaction.contract_package?.metadata?.symbol, - toPublicKey: transaction?.to_public_key, - fromPublicKey: transaction?.from_public_key || null, - contractPackage: transaction?.contract_package, - toHash: transaction?.to_hash, - toType: transaction?.to_type - }; - }) || []; - - const noActivityForErc20 = - tokenActivity?.tokenActivityList == null || - tokenActivity?.tokenActivityList?.length === 0; - - return ( - <> - {erc20Transactions.length > 0 && true && ( - ( - - )} - marginLeftForItemSeparatorLine={54} - /> - )} - - {(loading || hasNextPage) && } - - {noActivityForErc20 && !loading && ( - - )} - - ); -}; diff --git a/src/libs/ui/components/hash/hash.tsx b/src/libs/ui/components/hash/hash.tsx index 351ae6bd2..7dd9979b2 100644 --- a/src/libs/ui/components/hash/hash.tsx +++ b/src/libs/ui/components/hash/hash.tsx @@ -1,3 +1,4 @@ +import { Maybe } from 'casper-wallet-core/src/typings/common'; import React, { useMemo } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import styled from 'styled-components'; @@ -32,7 +33,7 @@ const HashContainer = styled(CenteredFlexRow)` `; interface HashProps { - value: string; + value: Maybe; variant: HashVariant; truncated?: boolean; truncatedSize?: TruncateKeySize; @@ -42,6 +43,7 @@ interface HashProps { isLedger?: boolean; placement?: Placement; withoutTooltip?: boolean; + withCopyIcon?: boolean; } export function Hash({ @@ -54,7 +56,8 @@ export function Hash({ truncatedSize, placement, withoutTooltip = false, - isLedger + isLedger, + withCopyIcon }: HashProps) { const { t } = useTranslation(); const isDarkMode = useIsDarkMode(); @@ -72,7 +75,9 @@ export function Hash({ wordBreak={!truncated} color={color || 'contentSecondary'} > - {truncated ? truncateKey(value, { size: truncatedSize }) : value} + {truncated + ? truncateKey(value || '', { size: truncatedSize }) + : value} {isImported && ( @@ -92,10 +97,10 @@ export function Hash({ size={20} /> )} + {withCopyIcon && } ), [ - isDarkMode, truncated, withoutTooltip, value, @@ -104,11 +109,13 @@ export function Hash({ color, truncatedSize, isImported, - isLedger + isLedger, + isDarkMode, + withCopyIcon ] ); - if (withCopyOnSelfClick) { + if (withCopyOnSelfClick || withCopyIcon) { return ( ( @@ -124,7 +131,7 @@ export function Hash({ )} )} - valueToCopy={value} + valueToCopy={value || ''} /> ); } diff --git a/src/libs/ui/components/index.ts b/src/libs/ui/components/index.ts index 6a133fd89..a18bb9e1f 100644 --- a/src/libs/ui/components/index.ts +++ b/src/libs/ui/components/index.ts @@ -23,9 +23,8 @@ export * from './secret-phrase-words-view'; export * from './text-list/text-list'; export * from './avatar/avatar'; export * from './tooltip/tooltip'; -export * from './account-activity-plate/account-activity-plate'; export * from './account-popover/account-popover'; -export * from './erc20-token-activity-list/erc20-token-activity-list'; +export * from './cep18-token-deploys-list/cep18-token-deploys-list'; export * from './tabs/tabs'; export * from './token-plate/token-plate'; export * from './deploy-status/deploy-status'; @@ -33,12 +32,11 @@ export * from './modal/modal'; export * from './modal/modal-switcher'; export * from './active-account-plate/active-account-plate'; export * from './recipient-plate/recipient-plate'; -export * from './account-casper-activity-plate/account-casper-activity-plate'; export * from './no-activity-view/no-activity-view'; export * from './nft-media-placeholder/nft-media-placeholder'; export * from './account-list/account-list'; export * from './connection-status-badge/connection-status-badge'; -export * from './casper-token-activity-list/casper-token-activity-list'; +export * from './casper-token-transfer-deploys-list/casper-token-transfer-deploys-list'; export * from './loading-activity-view/loading-activity-view'; export * from './recipient-dropdown-input/recipient-dropdown-input'; export * from './transfer-success-screen/transfer-succeess-screen'; diff --git a/src/libs/ui/components/no-activity-view/no-activity-view.tsx b/src/libs/ui/components/no-activity-view/no-activity-view.tsx index 99a488193..e597d208a 100644 --- a/src/libs/ui/components/no-activity-view/no-activity-view.tsx +++ b/src/libs/ui/components/no-activity-view/no-activity-view.tsx @@ -1,3 +1,4 @@ +import { IDeploy } from 'casper-wallet-core'; import React from 'react'; import { Trans, useTranslation } from 'react-i18next'; import styled from 'styled-components'; @@ -9,7 +10,6 @@ import { } from '@libs/layout'; import { Erc20TokenActionResult, - ExtendedDeployWithId, TransferResultWithId } from '@libs/services/account-activity-service'; import { Tile, Typography } from '@libs/ui/components'; @@ -23,7 +23,7 @@ export const NoActivityView = ({ top }: { activityList: - | (TransferResultWithId | Erc20TokenActionResult | ExtendedDeployWithId)[] + | (TransferResultWithId | Erc20TokenActionResult | IDeploy)[] | null; top?: SpacingSize; loading?: boolean; diff --git a/src/libs/ui/utils/index.ts b/src/libs/ui/utils/index.ts index 135a3f07a..a3a5420f3 100644 --- a/src/libs/ui/utils/index.ts +++ b/src/libs/ui/utils/index.ts @@ -1,5 +1,4 @@ export * from './get-color-from-theme'; -export * from './utils'; export * from './formatters'; export * from './get-linear-gradient-color'; export * from './hex-to-rgba'; diff --git a/src/libs/ui/utils/utils.ts b/src/libs/ui/utils/utils.ts deleted file mode 100644 index e30f0b3af..000000000 --- a/src/libs/ui/utils/utils.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { deriveSplitDataFromNamedKeyValue } from '@src/utils'; - -import { getAccountHashFromPublicKey } from '@libs/entities/Account'; -import { - Erc20TransferWithId, - ExtendedDeployArgsResult, - ExtendedDeployClTypeResult, - ExtendedDeployWithId, - MappedPendingTransaction -} from '@libs/services/account-activity-service'; - -export const getPublicKeyFormTarget = ( - target?: ExtendedDeployClTypeResult, - publicKey?: string -) => { - let toAccountPublicKey = ''; - - if (target && target.cl_type === 'PublicKey') { - toAccountPublicKey = target.parsed as string; - } else if (publicKey && target) { - const activeAccountHash = getAccountHashFromPublicKey(publicKey); - - toAccountPublicKey = - activeAccountHash === (target?.parsed as string) - ? publicKey - : (target?.parsed as string); - } - - return toAccountPublicKey; -}; - -export const getPublicKeyFormRecipient = ( - recipient: ExtendedDeployClTypeResult, - publicKey?: string -) => { - let toAccountPublicKey = ''; - - if (recipient.cl_type === 'Key' && publicKey) { - // @ts-ignore - const accountHash = recipient.parsed?.Account; - const activeAccountHash = getAccountHashFromPublicKey(publicKey); - let { hash } = deriveSplitDataFromNamedKeyValue(accountHash); - - toAccountPublicKey = activeAccountHash === hash ? publicKey : hash; - } - - return toAccountPublicKey; -}; - -const getRecipientAddressFromDeployArgs = ( - args: ExtendedDeployArgsResult, - activePublicKey: string -) => { - if (args?.target) { - return getPublicKeyFormTarget(args.target, activePublicKey); - } else if (args?.recipient) { - return getPublicKeyFormRecipient(args.recipient, activePublicKey); - } else if (args?.new_validator) { - return args?.new_validator.cl_type === 'PublicKey' - ? (args?.new_validator.parsed as string) - : ''; - } else if (args?.validator) { - return args?.validator.cl_type === 'PublicKey' - ? (args?.validator.parsed as string) - : ''; - } else { - return 'N/A'; - } -}; - -export const getRecipientAddressFromTransaction = ( - transaction: ExtendedDeployWithId | Erc20TransferWithId, - activePublicKey: string -) => { - let toAccountPublicKey = ''; - let toAccountHash = ''; - - // check if the transaction is an erc20 transfer - if ('toPublicKey' in transaction) { - if (transaction?.toPublicKey != null) { - toAccountPublicKey = transaction?.toPublicKey; - } else if (transaction?.toType === 'account-hash' && transaction?.toHash) { - toAccountHash = transaction.toHash; - } - } else { - toAccountPublicKey = getRecipientAddressFromDeployArgs( - transaction?.args, - activePublicKey - ); - } - - return { - recipientAddress: toAccountPublicKey || toAccountHash - }; -}; - -export const getMappedPendingTransactions = ( - pendingTransactions: ExtendedDeployWithId[], - publicKey: string -): MappedPendingTransaction[] => - pendingTransactions?.map(transaction => { - const parsedAmount = (transaction?.args?.amount?.parsed as string) || ''; - - const fromAccountPublicKey = transaction.callerPublicKey; - const toAccountPublicKey = getPublicKeyFormTarget( - transaction?.args?.target, - publicKey - ); - - return { - ...transaction, - amount: parsedAmount, - fromAccountPublicKey, - toAccountPublicKey - }; - }); diff --git a/src/utils.ts b/src/utils.ts index a1b0afefb..198cf4b94 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,13 +1,10 @@ import Big from 'big.js'; import { CLPublicKey, Keys, decodeBase16 } from 'casper-js-sdk'; +import { Maybe } from 'casper-wallet-core/src/typings/common'; import { runtime } from 'webextension-polyfill'; import { Browser, NFT_TOKENS_REFRESH_RATE } from '@src/constants'; -import { accountPendingTransactionsChanged } from '@background/redux/account-info/actions'; -import { dispatchToMainStore } from '@background/redux/utils'; - -import { dispatchFetchExtendedDeploysInfo } from '@libs/services/account-activity-service'; import { NFTTokenMetadata, NFTTokenMetadataEntry, @@ -379,28 +376,11 @@ export const setCSPForSafari = () => { } }; -export const fetchAndDispatchExtendedDeployInfo = (deployHash: string) => { - let triesLeft = 10; - - const interval = setInterval(async () => { - const { payload: extendedDeployInfo } = - await dispatchFetchExtendedDeploysInfo(deployHash); - - if (extendedDeployInfo) { - dispatchToMainStore( - accountPendingTransactionsChanged(extendedDeployInfo) - ); - clearInterval(interval); - } else if (triesLeft === 0) { - clearInterval(interval); - } - - triesLeft--; - // Note: this timeout is needed because the deploy is not immediately visible in the explorer - }, 2000); -}; - export const getErrorMessageForIncorrectPassword = (attemptsLeft: number) => attemptsLeft === 1 ? 'Password is incorrect. You’ve got last attempt, after that you’ll have to wait for 5 mins' : `Password is incorrect. You’ve got ${attemptsLeft} attempts, after that you’ll have to wait for 5 mins`; + +export const isPublicKeyHash = (hash?: Maybe) => { + return hash?.startsWith('01') || hash?.startsWith('02'); +}; diff --git a/webpack.config.js b/webpack.config.js index d3306dbfc..0523409bc 100755 --- a/webpack.config.js +++ b/webpack.config.js @@ -153,7 +153,8 @@ const options = { { test: /\.tsx?$/, loader: 'ts-loader', - exclude: /node_modules/ + exclude: /node_modules\/(?!(casper-wallet-core)\/).*/, + options: { allowTsInNodeModules: true } }, { test: /\.(js|jsx)$/,