diff --git a/.storybook/main.ts b/.storybook/main.ts index d6461f0a..4bfba977 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -1,8 +1,16 @@ import type { StorybookConfig } from '@storybook/react-vite'; import remarkGfm from 'remark-gfm'; + +async function filterStories(list): Promise { + console.log(list) + return ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'] +} + const config: StorybookConfig = { - stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], + stories: async (list: StoriesEntry[]) => [ + ...(await filterStories(list)), + ], addons: [ { name: '@storybook/addon-docs', diff --git a/package-lock.json b/package-lock.json index 0dddd345..ee204122 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@formatjs/intl": "^3.1.6", "big.js": "^7.0.1", + "casper-js-sdk": "^5.0.3", "copy-to-clipboard": "^3.3.3", "date-fns": "^4.1.0", "downshift": "^9.0.4", @@ -872,6 +873,77 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@ethersproject/bignumber": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, "node_modules/@formatjs/ecma402-abstract": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz", @@ -1226,6 +1298,53 @@ "resolve": "~1.22.2" } }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/ed25519": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.5.tgz", + "integrity": "sha512-xuS0nwRMQBvSxDa7UxMb61xTiH3MxTgUfhyPUALVIe0FlOAz4sjELwyDRyUvqeEYfRSG9qNjFIycqLZppg4RSA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.2.tgz", + "integrity": "sha512-/qzwYl5eFLH8OWIecQWM31qld2g1NfjgylK+TNhqtaUKP37Nm+Y+z30Fjhw0Ct8p9yCQEm2N3W/AckdIb3SMcQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1264,6 +1383,37 @@ "node": ">= 8" } }, + "node_modules/@open-rpc/client-js": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@open-rpc/client-js/-/client-js-1.8.1.tgz", + "integrity": "sha512-vV+Hetl688nY/oWI9IFY0iKDrWuLdYhf7OIKI6U1DcnJV7r4gAgwRJjEr1QVYszUc0gjkHoQJzqevmXMGLyA0g==", + "dependencies": { + "isomorphic-fetch": "^3.0.0", + "isomorphic-ws": "^5.0.0", + "strict-event-emitter-types": "^2.0.0", + "ws": "^7.0.0" + } + }, + "node_modules/@open-rpc/client-js/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -1732,6 +1882,39 @@ "string-argv": "~0.3.1" } }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -2386,7 +2569,6 @@ "version": "24.2.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.0.tgz", "integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.10.0" @@ -2463,6 +2645,14 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", @@ -2977,6 +3167,22 @@ "node": ">= 0.4" } }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==" + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -3000,6 +3206,21 @@ "node": ">=4" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-plugin-named-exports-order": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/babel-plugin-named-exports-order/-/babel-plugin-named-exports-order-0.0.2.tgz", @@ -3050,7 +3271,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/better-opn": { @@ -3079,6 +3299,11 @@ "url": "https://opencollective.com/bigjs" } }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==" + }, "node_modules/body-scroll-lock": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz", @@ -3108,6 +3333,11 @@ "node": ">=8" } }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, "node_modules/browserslist": { "version": "4.25.1", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", @@ -3141,6 +3371,18 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -3194,6 +3436,76 @@ ], "license": "CC-BY-4.0" }, + "node_modules/casper-js-sdk": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/casper-js-sdk/-/casper-js-sdk-5.0.6.tgz", + "integrity": "sha512-JomiNjcOk1GchBfG8pTGGeOhWCRjdZMDiYWR0NI6UeJMliUb0xfxMmQ5D6/bIQ6dqPxeNluGI/YjY7t5Rh6hLA==", + "dependencies": { + "@ethersproject/bignumber": "^5.0.8", + "@ethersproject/bytes": "^5.0.5", + "@ethersproject/constants": "^5.0.5", + "@noble/curves": "^1.1.0", + "@noble/ed25519": "^1.7.3", + "@noble/hashes": "^1.2.0", + "@noble/secp256k1": "^1.7.1", + "@open-rpc/client-js": "^1.8.1", + "@scure/bip32": "^1.1.5", + "@scure/bip39": "^1.2.0", + "@types/ws": "^8.2.2", + "asn1.js": "^5.4.1", + "axios": "^1.8.4", + "bn.js": "^5.2.1", + "elliptic": "6.6.1", + "eventsource": "^2.0.2", + "glob": "^7.1.6", + "humanize-duration": "^3.24.0", + "lodash": "^4.17.21", + "node-fetch": "2.6.13", + "reflect-metadata": "^0.1.13", + "ts-results": "npm:@casperlabs/ts-results@^3.3.4", + "typedjson": "^1.6.0-rc2" + } + }, + "node_modules/casper-js-sdk/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/casper-js-sdk/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/casper-js-sdk/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -3296,6 +3608,17 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/compare-versions": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", @@ -3309,6 +3632,11 @@ "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==", "license": "MIT" }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, "node_modules/confbox": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", @@ -3482,6 +3810,14 @@ "node": ">=8" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3563,6 +3899,19 @@ "react": ">=16.12.0" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -3577,6 +3926,25 @@ "dev": true, "license": "ISC" }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==" + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -3617,6 +3985,47 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.8", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", @@ -3753,6 +4162,14 @@ "node": ">=0.10.0" } }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -3975,6 +4392,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -3992,6 +4428,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs-extra": { "version": "11.3.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", @@ -4007,6 +4458,11 @@ "node": ">=14.14" } }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4026,7 +4482,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4042,6 +4497,41 @@ "node": ">=6.9.0" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -4089,6 +4579,17 @@ "node": ">= 6" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -4106,11 +4607,44 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -4129,6 +4663,16 @@ "he": "bin/he" } }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -4144,6 +4688,14 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "node_modules/humanize-duration": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.33.1.tgz", + "integrity": "sha512-hwzSCymnRdFx9YdRkQQ0OYequXiVAV6ZGQA2uzocwB0F4309Ke6pO8dg0P8LHhRQJyVjGteRTAA/zNfEcpXn8A==", + "funding": { + "url": "https://github.com/sponsors/EvanHahn" + } + }, "node_modules/i18next": { "version": "25.3.2", "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.3.2.tgz", @@ -4212,6 +4764,21 @@ "node": ">=8" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, "node_modules/interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", @@ -4359,6 +4926,23 @@ "dev": true, "license": "ISC" }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -4679,6 +5263,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", @@ -5520,6 +6112,25 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/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==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -5530,6 +6141,16 @@ "node": ">=4" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -5648,6 +6269,25 @@ "tslib": "^2.0.3" } }, + "node_modules/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", @@ -5691,7 +6331,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -5813,6 +6452,14 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -6008,6 +6655,11 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, + "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/pump": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", @@ -6302,6 +6954,11 @@ "node": ">=8" } }, + "node_modules/reflect-metadata": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==" + }, "node_modules/remark-gfm": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", @@ -6470,6 +7127,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/scheduler": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", @@ -6675,6 +7337,11 @@ "node": ">=10" } }, + "node_modules/strict-event-emitter-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz", + "integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==" + }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -6978,6 +7645,11 @@ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", "license": "MIT" }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/trough": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", @@ -7012,6 +7684,15 @@ "node": ">=6.10" } }, + "node_modules/ts-results": { + "name": "@casperlabs/ts-results", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@casperlabs/ts-results/-/ts-results-3.3.5.tgz", + "integrity": "sha512-ymSQqqb4mOSet592li02u1Gd28LoOFJUm6R3jkdNQ+nqsnbHvN+izBigtP4aYmNwh6gFyCwDgjYporEJgDT4eA==", + "dependencies": { + "tslib": "^2.4.1" + } + }, "node_modules/tsconfig-paths": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", @@ -7033,6 +7714,14 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/typedjson": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/typedjson/-/typedjson-1.8.0.tgz", + "integrity": "sha512-taVJVGebQDagEmVc3Cu6vVVLkWLnxqPcTrkVgbpAsI02ZDDrnHy5zvt1JVqXv4/yztBgZAX1oR07+bkiusGJLQ==", + "dependencies": { + "tslib": "^2.0.1" + } + }, "node_modules/typescript": { "version": "5.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", @@ -7058,7 +7747,6 @@ "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", - "dev": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -7387,6 +8075,11 @@ "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", "license": "Apache-2.0" }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", @@ -7394,6 +8087,20 @@ "dev": true, "license": "MIT" }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -7499,7 +8206,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/ws": { diff --git a/package.json b/package.json index d6c9327e..0523d140 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "dependencies": { "@formatjs/intl": "^3.1.6", "big.js": "^7.0.1", + "casper-js-sdk": "^5.0.3", "copy-to-clipboard": "^3.3.3", "date-fns": "^4.1.0", "downshift": "^9.0.4", diff --git a/src/lib/assets/icons/ic-clock.svg b/src/lib/assets/icons/ic-clock.svg index 5261148b..73d78698 100644 --- a/src/lib/assets/icons/ic-clock.svg +++ b/src/lib/assets/icons/ic-clock.svg @@ -1,4 +1,4 @@ - +ErrorIcon diff --git a/src/lib/components/activity-feed-item/activity-feed-item-stories.tsx b/src/lib/components/activity-feed-item/activity-feed-item-stories.tsx new file mode 100644 index 00000000..01eaeb6d --- /dev/null +++ b/src/lib/components/activity-feed-item/activity-feed-item-stories.tsx @@ -0,0 +1,118 @@ +import React from 'react'; +import { Meta, StoryFn } from '@storybook/react'; +import { MapDeploy } from '../deploy-actions/utils/deploy-action-helpers'; +import { + associatedKeysDeploy, + auctionDeploy, + cep18Deploy, + csprFunDeploy, + csprMarketDeploy, + defaultDeploy, + mockedAccountInfos, + mockedContractInfos, + mockedContractPackageInfos, + nftDeploy, + transferDeploy, +} from '../deploy-actions/storybook/mockedDeploys'; +import { ActivityFeedItem } from './activity-feed-item'; +import FlexColumn from '../flex-column/flex-column'; +import FlexRow from '../flex-row/flex-row'; +import BodyText from '../body-text/body-text'; + +export default { + renderComponent: (args) => ActivityFeedItem, + title: 'Composites/Deploy/ActivityFeedItem', + args: { + deploy: MapDeploy(defaultDeploy), + loading: false, + actionIdentificationHashes: { + native_transfer_contract_hash: 'native_transfer_contract_hash', + auction_manager_contract_hash: 'auction_manager_contract_hash', + associated_keys_contract_hash: 'associated_keys_contract_hash', + cspr_market_contract_package_hash: 'cspr_market_contract_package_hash', + }, + getAccountInfo: (hash) => + mockedAccountInfos.filter( + (account) => + account.public_key === hash || account.account_hash === hash, + )[0], + getContractPackageInfoByHash: (hash) => + mockedContractPackageInfos.filter( + (contract_package) => contract_package.contract_package_hash === hash, + )[0], + getContractInfoByHash: (hash) => + mockedContractInfos.filter( + (contract) => contract.contract_hash === hash, + )[0], + }, +} as Meta; + +const exampleComponents = [ + { + templateLabel: 'Default action feed item:', + renderComponent: (args) => , + }, + { + templateLabel: 'Transfer action feed item:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Cspr.fun action feed item:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Auction action feed item:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Associated keys action feed item:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Cspr market action feed item:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'CEP-18 action feed item:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Nft action feed item:', + renderComponent: (args) => ( + + ), + }, +]; + +const TemplateActivityFeedItems: StoryFn = (args) => { + return ( + + {exampleComponents.map((example) => ( + + + + {example.templateLabel} + + + + {example.renderComponent(args)} + + + ))} + + ); +}; + +export const ActivityFeedItems = TemplateActivityFeedItems.bind({}); diff --git a/src/lib/components/activity-feed-item/activity-feed-item.tsx b/src/lib/components/activity-feed-item/activity-feed-item.tsx new file mode 100644 index 00000000..48bc7bcd --- /dev/null +++ b/src/lib/components/activity-feed-item/activity-feed-item.tsx @@ -0,0 +1,442 @@ +import React from 'react'; +import styled from 'styled-components'; +import Big from 'big.js'; +import { deriveAccountInfo } from '../../utils/account'; +import { isValidPublicKey } from 'casper-js-sdk'; +import TooltipWithExtendedInfo from '../../components/tooltip-with-extended-info/tooltip-with-extended-info'; +import { PrecisionCase } from '../../utils/currency'; +import CsprAmount from '../cspr-amount/cspr-amount'; +import { + DeployResultRow, + ResultRowVariation, +} from '../deploy-actions/deploy-result-row'; +import { + ActionIdentificationHashesType, + DeployActionRow, +} from '../deploy-actions/deploy-action-row'; +import PageTile from '../page-tile/page-tile'; +import FlexColumn from '../flex-column/flex-column'; +import FlexRow from '../flex-row/flex-row'; +import { + AccountInfoResult, + ContractResult, + Deploy, + DeployContractPackageResult, +} from '../../types/types'; +import BodyText from '../body-text/body-text'; +import Link from '../link/link'; +import { + formatHash, + formatNumber, + formatTimestampAge, + HashLength, +} from '../../utils/formatters'; +import Tooltip from '../tooltip/tooltip'; +import Avatar from '../avatar/avatar'; +import TruncateBox from '../truncate-box/truncate-box'; +import { isWASMProxyTransaction } from '../deploy-actions/utils/contract'; +import { useMatchMedia } from '../../utils/match-media'; +import { DeployStatus, DeployStatusSize } from '../deploy-status/deploy-status'; +import { WasmProxyBadge } from './wasm-proxy-badge'; +import Address from '../address/address'; + +const StyledPageTile = styled(PageTile)(() => ({ + marginBottom: 8, + height: 'auto', +})); + +const DesktopFeedItemContainer = styled(FlexColumn)(({ theme }) => + theme.withMedia({ + boxSizing: 'border-box', + padding: '20px', + width: '100%', + '> * + *': { + width: '100%', + }, + }), +); + +const MobileFeedItemContainer = styled(DesktopFeedItemContainer)(({ theme }) => + theme.withMedia({ + padding: '16px', + '> * + *': { + marginTop: [16, 0], + paddingTop: 16, + }, + '> div:not(:first-child)': { + position: 'relative', + flexWrap: 'wrap', + }, + '>div:not(:first-child):after': { + content: "''", + position: 'absolute', + left: 0, + right: 0, + top: 0, + borderBottom: theme.border.tableRowSeparator, + }, + }), +); + +const CommonDataContainer = styled(FlexRow)(({ theme }) => ({ + width: '100%', + justifyContent: 'space-between', + position: 'relative', + paddingBottom: 12, + ':after': { + content: "''", + position: 'absolute', + left: 0, + right: 0, + bottom: 0, + borderBottom: theme.border.tableRowSeparator, + }, +})); + +const WrappedContainer = styled(FlexRow)(({ theme }) => ({ + '> div': { + flexWrap: 'wrap', + }, + flexWrap: 'wrap', +})); + +const StyledFlexColumn = styled(FlexColumn)(({ theme }) => + theme.withMedia({ + width: '100%', + }), +); + +const BlockFeedInfo = ({ deploy, path }: { deploy: Deploy; path: string }) => ( + + + Block: + + + {deploy.blockHash == null ? ( + 'N/A' + ) : ( + + {formatNumber(deploy.blockHeight)} + + )} + + + · + + + {formatTimestampAge(deploy.timestamp)} + + +); + +interface ActivityFeedItemProps { + deploy: Deploy; + loading: boolean; + actionIdentificationHashes: ActionIdentificationHashesType; + csprLiveDomainPath: string; + getAccountInfo: ( + publicKey: string, + ) => T | null | undefined; + getContractInfoByHash: ( + contractHash: string, + ) => ContractResult | null | undefined; + getContractPackageInfoByHash?: ( + contractPackageHash: string, + ) => DeployContractPackageResult | null | undefined; +} + +export const ActivityFeedItem = ({ + deploy, + loading, + actionIdentificationHashes, + getAccountInfo, + getContractPackageInfoByHash, + getContractInfoByHash, + csprLiveDomainPath, +}: ActivityFeedItemProps) => { + const { + callerPublicKey, + callerHash, + deployHash, + paymentAmount, + refundAmount, + callerCsprName, + } = deploy; + + const accountInfo = getAccountInfo( + callerPublicKey || callerHash, + ); + + const accountInfoDetails = deriveAccountInfo( + accountInfo?.account_info || accountInfo?.centralized_account_info, + ); + + const logo = accountInfoDetails && accountInfoDetails?.logo; + const name = accountInfoDetails?.name; + const csprName = accountInfo?.cspr_name || deploy.callerCsprName; + + const keyTooltipCaption = isValidPublicKey(callerPublicKey) + ? 'Public Key' + : 'Account hash'; + + const chargedAmount = Big(paymentAmount || '0') + .minus(refundAmount || '0') + .toString(); + + const onAbove = ( + + + + + + + + {formatHash(deployHash, HashLength.TINY)} + + + + + + + {formatTimestampAge(deploy.timestamp)} + + + · + + + Block: + + + {deploy.blockHash == null ? ( + 'N/A' + ) : ( + + {formatNumber(deploy.blockHeight)} + + )} + + + · + + + + + Charge: + + + + + + + + + + {logo ? ( + + ) : ( + + )} + + + + + + + + {csprName || formatHash(callerPublicKey, HashLength.TINY)} + + + + + + + + {name} + + + + + + + + {isWASMProxyTransaction(deploy.executionTypeId) && ( + + )} + + + + + + + + + + + + ); + + const onMobile = ( + + + + + + + + {formatHash(deployHash, HashLength.TINY)} + + + + + + + Charge: + + + + + + + +
+ + + {isWASMProxyTransaction(deploy.executionTypeId) && ( + + )} + + + + + + +
+ + + + +
+ ); + const responsiveFeedItem = useMatchMedia( + [onMobile, onAbove, onAbove, onAbove], + [deploy, accountInfo], + ); + + return {responsiveFeedItem}; +}; diff --git a/src/lib/components/activity-feed-item/wasm-proxy-badge.tsx b/src/lib/components/activity-feed-item/wasm-proxy-badge.tsx new file mode 100644 index 00000000..a7966dec --- /dev/null +++ b/src/lib/components/activity-feed-item/wasm-proxy-badge.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { useTheme } from 'styled-components'; +import { BadgeProps } from '@make-software/cspr.design'; +import Tooltip from '../tooltip/tooltip'; +import FlexRow from '../flex-row/flex-row'; +import Badge from '../badge/badge'; + +export const WasmProxyBadge = ({ + lineHeight, +}: { + lineHeight?: Pick['lineHeight']; +}) => { + const theme = useTheme(); + + return ( + + + + + + ); +}; diff --git a/src/lib/components/address/address.tsx b/src/lib/components/address/address.tsx index a0ae4f49..8b8f5961 100644 --- a/src/lib/components/address/address.tsx +++ b/src/lib/components/address/address.tsx @@ -16,6 +16,8 @@ import { import { Size } from '../../types.ts'; import TruncateBox from '../truncate-box/truncate-box.tsx'; import Copy from '../copy/copy.tsx'; +import TooltipWithExtendedInfo from '../tooltip-with-extended-info/tooltip-with-extended-info'; +import { isValidPublicKey } from 'casper-js-sdk'; interface AddressProps { hash: string | null | undefined; @@ -77,7 +79,12 @@ const AddressContent = ({ return ( - + {truncatedCsprName || formattedHash} @@ -142,7 +149,6 @@ export const Address = React.forwardRef(function Address( minifiedCopyNotification, navigateToPath, tooltipCaption, - additionalTooltipBlock, hashFontSize, nameTruncateSize = 5, avatarSize = 'default', @@ -167,7 +173,7 @@ export const Address = React.forwardRef(function Address( - + {hash} @@ -178,6 +184,12 @@ export const Address = React.forwardRef(function Address( ); } + const keyTooltipCaption = tooltipCaption + ? tooltipCaption + : isValidPublicKey(hash) + ? 'Public Key' + : 'Account hash'; + return ( {logo ? ( @@ -191,10 +203,10 @@ export const Address = React.forwardRef(function Address( )} - {name ? ( @@ -212,7 +224,13 @@ export const Address = React.forwardRef(function Address( /> - + {name} @@ -230,7 +248,7 @@ export const Address = React.forwardRef(function Address( /> )} - + ); }); diff --git a/src/lib/components/cep18-formatted-amount/cep18-formatted-amount.tsx b/src/lib/components/cep18-formatted-amount/cep18-formatted-amount.tsx new file mode 100644 index 00000000..d79d5ba4 --- /dev/null +++ b/src/lib/components/cep18-formatted-amount/cep18-formatted-amount.tsx @@ -0,0 +1,54 @@ +import React from 'react'; + +import { currencyPrecisionByCase, PrecisionCase } from '../../utils/currency'; +import TokenAmount from '../token-amount/token-amount'; +import { DeployContractPackageResult } from '../../types/types'; +import { deriveFtTokenData } from '../../utils/derive-ft-token-data-service'; +import FlexRow from '../flex-row/flex-row'; +import { DEFAULT_AMOUNT_PRECISION } from '../../utils/formatters'; + +export interface Cep18Props { + symbol?: string; + amount?: string | null; + precisionCase?: PrecisionCase; + contractPackage: DeployContractPackageResult; +} + +export function Cep18FormattedAmount({ + amount, + symbol, + contractPackage, + precisionCase, +}: Cep18Props) { + if (!amount) { + return <>{'-'}; + } + + const ftTokenData = deriveFtTokenData( + contractPackage + ? { + contractPackageInfo: contractPackage, + } + : null, + ); + + return ( + + + + + + ); +} + +export default Cep18FormattedAmount; diff --git a/src/lib/components/cep18-token/cep18-token.tsx b/src/lib/components/cep18-token/cep18-token.tsx index 3e8fadd2..e6c63752 100644 --- a/src/lib/components/cep18-token/cep18-token.tsx +++ b/src/lib/components/cep18-token/cep18-token.tsx @@ -14,7 +14,13 @@ export interface CEP18TokenProps { } /** @deprecated */ -export function CEP18Token({ motes, precision, decimals, ticker, hideCurrency }: CEP18TokenProps) { +export function CEP18Token({ + motes, + precision, + decimals, + ticker, + hideCurrency, +}: CEP18TokenProps) { if (motes == null) { return <>{'N/A'}; } diff --git a/src/lib/components/contract-icon/contract-icon.tsx b/src/lib/components/contract-icon/contract-icon.tsx new file mode 100644 index 00000000..379fb59c --- /dev/null +++ b/src/lib/components/contract-icon/contract-icon.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import Avatar, { AvatarProps } from '../avatar/avatar'; +import { ContractTypeId } from '../../types/types'; +import { + DefiContractIcon, + GenericContractIcon, + NftContractIcon, + TokenContractIcon, +} from '../../icons-index'; + +export interface ContractIconProps { + src?: string | null; + size?: AvatarProps['size']; + loading?: boolean; + contractTypeId: number | undefined | null; +} + +const ContractIconsPath = { + [ContractTypeId.Cep18]: TokenContractIcon, + [ContractTypeId.CustomCep18]: TokenContractIcon, + [ContractTypeId.CEP47Nft]: NftContractIcon, + [ContractTypeId.CustomCEP47Nft]: NftContractIcon, + [ContractTypeId.CEP78Nft]: NftContractIcon, + [ContractTypeId.CustomCEP78Nft]: NftContractIcon, + [ContractTypeId.CEP95Nft]: NftContractIcon, + [ContractTypeId.DeFi]: DefiContractIcon, +}; + +const genericIconPath = GenericContractIcon; + +export const ContractIcon = ({ + src, + size = 'default', + loading, + contractTypeId, +}: ContractIconProps) => { + const contractTypeDefaultLogo = contractTypeId + ? ContractIconsPath[contractTypeId] + : null; + const contractLogoSrc = contractTypeDefaultLogo || genericIconPath; + + if (src) { + return ( + + ); + } + return ; +}; + +export default ContractIcon; diff --git a/src/lib/components/contract-identifier/contract-identifier-with-name.tsx b/src/lib/components/contract-identifier/contract-identifier-with-name.tsx new file mode 100644 index 00000000..f65f1c74 --- /dev/null +++ b/src/lib/components/contract-identifier/contract-identifier-with-name.tsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { HashLink } from '../hash-link/hash-link'; +import ContractIcon from '../contract-icon/contract-icon'; +import { AvatarProps } from '../avatar/avatar'; +import TooltipWithExtendedInfo from '../tooltip-with-extended-info/tooltip-with-extended-info'; +import { DeployContractPackageResult } from '../../types/types'; +import { HashLength } from '../../utils/formatters.ts'; +import { HashFontSize } from './default-contract-identifier'; +import { + SHORTENED_CONTRACT_NAME_LENGTH, + truncateName, +} from '../../utils/truncate-hash'; +import FlexRow from '../flex-row/flex-row'; +import FlexColumn from '../flex-column/flex-column'; +import BodyText from '../body-text/body-text'; +import TruncateBox from '../truncate-box/truncate-box'; + +interface ContractIdentifierWithNameProps { + hash: string; + contractPackage: DeployContractPackageResult; + hashLength?: HashLength; + avatarSize?: AvatarProps['size']; + hashFontSize?: HashFontSize; + loading?: boolean; + path: string; +} + +export const ContractIdentifierWithName = ({ + hash, + contractPackage, + avatarSize = 'default', + hashLength = HashLength.TINY, + loading, + path, +}: ContractIdentifierWithNameProps) => { + const { latest_version_contract_type_id, icon_url, name, contract_name } = + contractPackage; + + const contractName = name || contract_name; + const truncatedContractName = + contractName && hashLength === HashLength.TINY + ? truncateName(contractName, SHORTENED_CONTRACT_NAME_LENGTH) + : contractName; + + return ( + + + + + {truncatedContractName ? ( + <> + + + + + + {truncatedContractName} + + + + ) : ( + + + + )} + + + + ); +}; diff --git a/src/lib/components/contract-identifier/contract-identifier.tsx b/src/lib/components/contract-identifier/contract-identifier.tsx new file mode 100644 index 00000000..b6e119a8 --- /dev/null +++ b/src/lib/components/contract-identifier/contract-identifier.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { ContractIdentifierWithName } from './contract-identifier-with-name'; +import { + DefaultContractIdentifier, + UnknownContractInfo, +} from './default-contract-identifier'; +import { AvatarProps } from '../avatar/avatar'; +import { DeployContractPackageResult } from '../../types/types'; +import { HashLength, HashFontSize } from '../../utils/formatters'; + +interface ContractIdentifierProps { + hash: string; + withName?: boolean; + contractPackage?: DeployContractPackageResult; + hideContractType?: boolean; + hashLength?: HashLength; + avatarSize?: AvatarProps['size']; + hashFontSize?: HashFontSize; + loading?: boolean; + path: string; +} + +export const ContractIdentifier = ({ + withName = false, + ...props +}: ContractIdentifierProps) => { + if (!props.contractPackage) { + return ( + + ); + } + + if (withName) { + return ; + } + + return ; +}; diff --git a/src/lib/components/contract-identifier/default-contract-identifier.tsx b/src/lib/components/contract-identifier/default-contract-identifier.tsx new file mode 100644 index 00000000..d5b489f6 --- /dev/null +++ b/src/lib/components/contract-identifier/default-contract-identifier.tsx @@ -0,0 +1,162 @@ +import { + ContractTypeName, + contractTypes, +} from '../contract-type/contract-type-name'; +import React from 'react'; +import { AvatarProps } from '../avatar/avatar'; +import ContractIcon from '../contract-icon/contract-icon'; +import FlexRow from '../flex-row/flex-row'; +import { DeployContractPackageResult } from '../../types/types'; +import TooltipWithExtendedInfo from '../tooltip-with-extended-info/tooltip-with-extended-info'; +import BodyText, { BodyTextProps } from '../body-text/body-text'; +import Tooltip from '../tooltip/tooltip'; +import { + SHORTENED_CONTRACT_NAME_LENGTH, + truncateName, +} from '../../utils/truncate-hash'; +import Copy from '../copy/copy'; +import Link from '../link/link'; +import { formatHash, HashLength } from '../../utils/formatters.ts'; + +export enum HashFontSize { + 'default' = 'default', + 'big' = 'big', +} +const mapScaleByHashFontSize: Record = { + [HashFontSize.default]: 'xs', + [HashFontSize.big]: 'sm', +}; + +export const UnknownContractInfo = ({ + hash, + iconSize = 'small', + hashFontSize = HashFontSize.big, + hashLength, + path, +}: { + hash: string | null; + iconSize?: AvatarProps['size']; + hashFontSize?: HashFontSize; + hashLength?: HashLength; + path: string; +}) => { + const itemsSpacing = iconSize === 'default' ? 12 : 4; + if (!hash) { + return null; + } + + return ( + + + + + + {formatHash(hash, hashLength)} + + + + + + ); +}; + +interface DefaultContractIdentifierProps { + hash: string; + contractPackage?: DeployContractPackageResult; + hashLength?: HashLength; + avatarSize?: AvatarProps['size']; + hashFontSize?: HashFontSize; + hideContractType?: boolean; + loading?: boolean; + path: string; +} + +export const DefaultContractIdentifier = ({ + hash, + contractPackage, + hideContractType = false, + hashLength = HashLength.TINY, + avatarSize = 'tiny', + hashFontSize = HashFontSize.default, + loading, + path, +}: DefaultContractIdentifierProps) => { + const { latest_version_contract_type_id, icon_url, name, contract_name } = + contractPackage; + + const contractName = truncateName( + name || contract_name, + SHORTENED_CONTRACT_NAME_LENGTH, + ); + + const contractTypeName = latest_version_contract_type_id + ? contractTypes[latest_version_contract_type_id] + : ''; + const contractIdentifier = name ? contractName : formatHash(hash, hashLength); + + const showContractType = + !hideContractType && + contractIdentifier.length + contractTypeName.length < + SHORTENED_CONTRACT_NAME_LENGTH; + + const itemsSpacing = avatarSize === 'default' ? 12 : 4; + + return ( + + + + + + + {contractIdentifier} + + + + + {showContractType && ( + + + + )} + + ); +}; diff --git a/src/lib/components/contract-type/contract-type-name.tsx b/src/lib/components/contract-type/contract-type-name.tsx new file mode 100644 index 00000000..96f1e397 --- /dev/null +++ b/src/lib/components/contract-type/contract-type-name.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import {ContractTypeId} from "../../types/types"; + +export const contractTypes = { + [ContractTypeId.System]: 'System Contract', + [ContractTypeId.Cep18]: 'CEP-18 Token', + [ContractTypeId.CustomCep18]: 'CEP-18 Token', + [ContractTypeId.CEP47Nft]: 'CEP-47 NFT', + [ContractTypeId.CustomCEP47Nft]: 'CEP-47 NFT', + [ContractTypeId.DeFi]: 'DeFi', + [ContractTypeId.CEP78Nft]: 'CEP-78 NFT', + [ContractTypeId.CustomCEP78Nft]: 'CEP-78 NFT', + [ContractTypeId.NFTMarketplace]: 'NFT Marketplace', + [ContractTypeId.CEP95Nft]: 'CEP-95 NFT', +}; + +export const ContractTypeName = ({ + contractTypeId, +}: { + contractTypeId: number | null; +}) => { + return ( + <> + {contractTypeId ? ( + contractTypes[contractTypeId] + ) : null} + + ); +}; diff --git a/src/lib/components/cspr-amount/cspr-amount.tsx b/src/lib/components/cspr-amount/cspr-amount.tsx new file mode 100644 index 00000000..36abcc85 --- /dev/null +++ b/src/lib/components/cspr-amount/cspr-amount.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { + CSPR_DECIMALS, + currencyPrecisionByCase, + PrecisionCase, +} from '../../utils/currency'; +import TokenAmount from '../token-amount/token-amount'; + +export interface CsprProps { + motes?: string | number | null; + precisionCase?: PrecisionCase; + hideCsprCurrency?: boolean; +} + +export function CsprAmount({ + motes, + precisionCase, + hideCsprCurrency, +}: CsprProps) { + const precision = currencyPrecisionByCase(precisionCase); + + return ( + + ); +} + +export default CsprAmount; diff --git a/src/lib/components/deploy-actions/components/Cep18ActionRow.tsx b/src/lib/components/deploy-actions/components/Cep18ActionRow.tsx new file mode 100644 index 00000000..bb4da0f8 --- /dev/null +++ b/src/lib/components/deploy-actions/components/Cep18ActionRow.tsx @@ -0,0 +1,132 @@ +import React from 'react'; +import { PrecisionCase } from '../../../utils/currency'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import { + AccountInfoResult, + DeployContractPackageResult, + TransactorHashType, +} from '../../../types/types'; +import FlexRow from '../../flex-row/flex-row'; +import BodyText from '../../body-text/body-text'; +import { HashFontSize } from '../../../utils/formatters'; +import { ContractIdentifier } from '../../contract-identifier/contract-identifier'; +import Cep18FormattedAmount from '../../cep18-formatted-amount/cep18-formatted-amount'; +import TransactorInfo from '../../transactor-info/transactor-info'; + +interface Cep18ActionRowProps { + actionName: string | undefined; + prefix?: string | null; + senderPrefix?: string | null; + amount?: string; + contractPackage: DeployContractPackageResult; + from_hash?: string; + from_public_key?: string | null; + from_type?: TransactorHashType; + to_hash?: string; + to_public_key?: string | null; + to_type?: TransactorHashType; +} + +export const Cep18ActionRow = ({ + amount, + contractPackage, + from_public_key, + from_hash, + from_type, + to_hash, + to_type, + to_public_key, + actionName, + prefix, + senderPrefix, +}: Cep18ActionRowProps) => { + const { getAccountInfo, getContractPackageInfoByHash, csprLiveDomainPath } = + useDeployActionDataContext(); + const fromAccountInfo = getAccountInfo( + from_public_key || from_hash || '', + ); + const toAccountInfo = getAccountInfo( + to_public_key || to_hash || '', + ); + + return ( + + + {actionName} + + {prefix && ( + + {prefix} + + )} + {amount && ( + + + + )} + + + ( + + + + ) token(s) + + + + {from_hash && ( + <> + + {senderPrefix} + + + + )} + {to_hash && ( + <> + + to + + + + )} + + ); +}; diff --git a/src/lib/components/deploy-actions/components/DeployActionAssociatedKeys.tsx b/src/lib/components/deploy-actions/components/DeployActionAssociatedKeys.tsx new file mode 100644 index 00000000..123a7710 --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployActionAssociatedKeys.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import { deriveAccountInfo } from '../../../utils/account'; +import { deriveUpdatedAssociatedKey } from '../utils/deploy-action-helpers'; +import { DataResponse, Deploy, GetDeployResult } from '../../../types/types'; +import { deriveSplitDataFromNamedKeyValue } from '../../../utils/named-key'; +import FlexRow from '../../flex-row/flex-row'; +import BodyText from '../../body-text/body-text'; +import { ContractIdentifier } from '../../contract-identifier/contract-identifier'; +import { HashFontSize } from '../../../utils/formatters'; +import Address from '../../address/address'; + +interface DeployAssociatedKeysActionProps { + deploy: Deploy; + deployRawData: DataResponse | null; + renderAsResultAction?: boolean; +} + +const DeployActionAssociatedKeys = ({ + deploy, + deployRawData, + renderAsResultAction = false, +}: DeployAssociatedKeysActionProps) => { + const { contractPackage } = deploy; + + const updatedMasterKey = deriveUpdatedAssociatedKey(deployRawData?.data); + const { hash } = deriveSplitDataFromNamedKeyValue(updatedMasterKey || ''); + + const { getAccountInfo, getPublicKeyAccountHash, csprLiveDomainPath } = + useDeployActionDataContext(); + const publicKey = getPublicKeyAccountHash(hash); + const accountInfo = getAccountInfo(hash); + const accountInfoData = deriveAccountInfo( + accountInfo?.account_info || accountInfo?.centralized_account_info, + ); + const logo = accountInfoData?.logo; + const name = accountInfo?.name; + const csprName = accountInfo?.cspr_name; + + const deployActionText = renderAsResultAction + ? 'Updated account' + : 'Update account'; + + return ( + + + {deployActionText} + {' '} + {(publicKey || !!hash) && ( +
+ )} + {!renderAsResultAction && ( + + + with + + + + )} +
+ ); +}; +export default DeployActionAssociatedKeys; diff --git a/src/lib/components/deploy-actions/components/DeployActionAuction.tsx b/src/lib/components/deploy-actions/components/DeployActionAuction.tsx new file mode 100644 index 00000000..0f979cab --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployActionAuction.tsx @@ -0,0 +1,181 @@ +import React from 'react'; +import { AuctionManagerEntryPoint } from 'casper-js-sdk'; +import { deriveAccountInfo } from '../../../utils/account.tsx'; +import { useMatchMedia } from '../../../utils/match-media'; +import DeployFiatAmount from './DeployFiatAmount'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import AuctionContractIcon from '../../../assets/icons/ic-auction-contract.svg'; +import FlexRow from '../../flex-row/flex-row'; +import Avatar from '../../avatar/avatar'; +import BodyText from '../../body-text/body-text'; +import Link from '../../link/link'; +import { AccountInfoResult, Deploy } from '../../../types/types'; +import Address from '../../address/address'; + +const auctionActionNameMap = { + [AuctionManagerEntryPoint.add]: 'Add', + [AuctionManagerEntryPoint.withdraw]: 'Withdraw', + [AuctionManagerEntryPoint.activate]: 'Activate', + [AuctionManagerEntryPoint.delegate]: 'Delegate', + [AuctionManagerEntryPoint.undelegate]: 'Undelegate', + [AuctionManagerEntryPoint.redelegate]: 'Redelegate', +}; + +const AuctionContractIdentifier = ({ + identifier, + contract_package_hash, +}: { + identifier: string; + contract_package_hash: string | undefined; +}) => { + const { csprLiveDomainPath } = useDeployActionDataContext(); + return ( + + + + + {identifier} + + + + ); +}; + +const ValidatorAccountInfo = ({ publicKey, prefix }) => { + const { getAccountInfo, csprLiveDomainPath } = useDeployActionDataContext(); + const avatarSize = useMatchMedia(['small', 'default'], []); + + const accountInfo = getAccountInfo(publicKey); + const validatorLogo = deriveAccountInfo( + accountInfo?.account_info || accountInfo?.centralized_account_info, + ); + const validatorName = accountInfo?.account_info?.info?.owner?.name; + + return publicKey ? ( + <> + + {prefix} + +
+ + ) : null; +}; + +const DefaultAuctionAction = ({ deploy }: { deploy: Deploy }) => ( + + + {deploy.entryPoint?.name} + + + with + + + +); + +const ManageAuctionBidAction = ({ deploy }: { deploy: Deploy }) => { + const { args, timeTransactionCurrencyRate, contractPackage, entryPoint } = + deploy; + const amount = args.amount?.parsed as string; + + return ( + + + {auctionActionNameMap[entryPoint?.name || '']} + + + + bid + + {amount && ( + <> + + of + + + + )} + + ); +}; + +const DelegationAuctionAction = ({ deploy }: { deploy: Deploy }) => { + const { timeTransactionCurrencyRate, entryPoint, args } = deploy; + + const amount = args.amount?.parsed as string; + const initialValidatorPrefix = + entryPoint?.name === AuctionManagerEntryPoint.delegate ? 'to' : 'from'; + + return ( + + + {auctionActionNameMap[entryPoint?.name || '']} + + {amount && ( + + )} + + + + ); +}; + +const DeployActionAuction = ({ deploy }: { deploy: Deploy }) => { + const { entryPoint } = deploy; + + const entryPointName = entryPoint?.name || ''; + + const isManageAuctionBidAction = + entryPointName === AuctionManagerEntryPoint.activate || + entryPointName === AuctionManagerEntryPoint.withdraw || + entryPointName === AuctionManagerEntryPoint.add; + + const isDelegationAction = + entryPointName === AuctionManagerEntryPoint.delegate || + entryPointName === AuctionManagerEntryPoint.undelegate || + entryPointName === AuctionManagerEntryPoint.redelegate; + + if (isDelegationAction) { + return ; + } + + if (isManageAuctionBidAction) { + return ; + } + + return ; +}; + +export default DeployActionAuction; diff --git a/src/lib/components/deploy-actions/components/DeployActionCep18.tsx b/src/lib/components/deploy-actions/components/DeployActionCep18.tsx new file mode 100644 index 00000000..6868ad26 --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployActionCep18.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import DeployActionDefault from './DeployActionDefault'; +import { Cep18ActionRow } from './Cep18ActionRow'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import { Deploy } from '../../../types/types'; +import { + prepareActionMessageDataForDeployDetails, + prepareFtActionMessageDataForDeployDetails, +} from '../utils/prepare-action-messages'; + +interface DeployActionCep18Props { + deploy: Deploy; +} + +export const DeployActionCep18 = ({ deploy }: DeployActionCep18Props) => { + const { getPublicKeyAccountHash } = useDeployActionDataContext(); + const message = prepareFtActionMessageDataForDeployDetails( + deploy, + getPublicKeyAccountHash, + ); + + if (!message) { + return ; + } + + const { amount, actionName, contractPrefix, account1, prefix1, account2 } = + message; + + return ( + + ); +}; diff --git a/src/lib/components/deploy-actions/components/DeployActionCsprFun.tsx b/src/lib/components/deploy-actions/components/DeployActionCsprFun.tsx new file mode 100644 index 00000000..108a20cb --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployActionCsprFun.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import { deriveSplitDataFromNamedKeyValue } from '../../../utils/named-key'; +import { HashFontSize } from '../../../utils/formatters'; +import FlexRow from '../../flex-row/flex-row'; +import BodyText from '../../body-text/body-text'; +import { ContractIdentifier } from '../../contract-identifier/contract-identifier'; + +const DeployActionCsprFun = ({ deploy }) => { + const contractHash = deploy.args.token_to_trade_contract_hash_key.parsed; + const { hash } = deriveSplitDataFromNamedKeyValue(contractHash); + const { getContractInfoByHash, csprLiveDomainPath } = + useDeployActionDataContext(); + + const contractInfo = getContractInfoByHash(hash); + const contractPackageInfo = contractInfo?.contract_package; + return ( + + + CSPR.fun trade + + + {contractPackageInfo ? ( + <> + + with + + + + + + + ) : null} + + ); +}; + +export default DeployActionCsprFun; diff --git a/src/lib/components/deploy-actions/components/DeployActionDefault.tsx b/src/lib/components/deploy-actions/components/DeployActionDefault.tsx new file mode 100644 index 00000000..fc7a8261 --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployActionDefault.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import FlexRow from '../../flex-row/flex-row'; +import BodyText from '../../body-text/body-text'; +import { Deploy } from '../../../types/types'; +import { HashFontSize } from '../../contract-identifier/default-contract-identifier'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import { ContractIdentifier } from '../../contract-identifier/contract-identifier'; + +const DeployActionDefault = ({ deploy }: { deploy: Deploy }) => { + const { csprLiveDomainPath } = useDeployActionDataContext(); + return ( + + + {deploy.entryPoint?.name} + + + with + + + + ); +}; + +export default DeployActionDefault; diff --git a/src/lib/components/deploy-actions/components/DeployActionMarket.tsx b/src/lib/components/deploy-actions/components/DeployActionMarket.tsx new file mode 100644 index 00000000..9495a6dd --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployActionMarket.tsx @@ -0,0 +1,280 @@ +import React from 'react'; +import ContractIcon from '../../../components/contract-icon/contract-icon'; +import { deriveAccountInfo } from '../../../utils/account.tsx'; +import DeployFiatAmount from './DeployFiatAmount'; +import { NftCollectionIdentifier } from './NftCollectionIdentifier'; +import { NftTokenIds } from './NftTokenIds'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import { CsprMarketEntryPoint } from '../../../types/NFTToken'; +import { isNonNullable } from '../../../utils/guards'; +import { Deploy, DeployContractPackageResult } from '../../../types/types'; +import FlexRow from '../../flex-row/flex-row'; +import BodyText from '../../body-text/body-text'; +import Link from '../../link/link'; +import { guardedDeriveSplitDataFromArguments } from '../../../utils/deploy-args'; +import Address from '../../address/address'; + +const marketActionNameMap = { + [CsprMarketEntryPoint.delist_token]: 'Delist', + [CsprMarketEntryPoint.list_token]: 'List', + [CsprMarketEntryPoint.accept_offer]: 'Accept offer', + [CsprMarketEntryPoint.cancel_offer]: 'Cancel offer', + [CsprMarketEntryPoint.make_offer]: 'Make offer', +}; + +const getNftTokenIdsFromArguments = (args) => { + const hasTokens = args.tokens?.parsed || args.token_id?.parsed; + if (hasTokens) { + const tokens = args.tokens?.parsed + ? args.tokens.parsed.map((token) => + typeof token === 'string' ? token : token.key, + ) + : []; + const ids = [...tokens, args.token_id?.parsed].filter(isNonNullable); + + return [...new Set(ids)]; + } + return null; +}; + +const MarketContractIdentifier = ({ + contractPackage, + path, +}: { + contractPackage: DeployContractPackageResult; + path: string; +}) => { + const { + latest_version_contract_type_id, + icon_url, + contract_package_hash, + name, + } = contractPackage; + return ( + + + + {contract_package_hash && ( + + {name} + + )} + + + ); +}; + +const OfferMarketAction = ({ + deploy, + collectionHash, + nftTokenIds, +}: { + deploy: Deploy; + collectionHash: string; + nftTokenIds: string[] | null; +}) => { + const { + amount, + entryPoint, + args, + timeTransactionCurrencyRate, + contractPackage, + } = deploy; + + const offererHash = guardedDeriveSplitDataFromArguments( + args.offerer, + 'Account', + ); + + const { + getAccountInfo, + getPublicKeyAccountHash, + getContractPackageInfoByHash, + csprLiveDomainPath, + } = useDeployActionDataContext(); + + const accountInfo = offererHash && getAccountInfo(offererHash?.hash); + const publicKey = offererHash && getPublicKeyAccountHash(offererHash?.hash); + const accountInfoDetails = deriveAccountInfo( + accountInfo?.account_info || accountInfo?.centralized_account_info, + ); + const logo = accountInfoDetails && accountInfoDetails.logo; + const name = accountInfoDetails?.name; + const csprName = accountInfo?.cspr_name; + + return ( + + + {marketActionNameMap[entryPoint?.name || '']} + + {amount && ( + <> + + of + + + + )} + {collectionHash && ( + <> + + for + + + + )} + + {offererHash && ( + + + from + +
+
+ )} + + on + + +
+ ); +}; + +const ListMarketAction = ({ + deploy, + collectionHash, + nftTokenIds, +}: { + deploy: Deploy; + collectionHash: string; + nftTokenIds: string[] | null; +}) => { + const { entryPoint, contractPackage } = deploy; + const { csprLiveDomainPath, getContractPackageInfoByHash } = + useDeployActionDataContext(); + const contractIdentifierPrefix = + entryPoint?.name === CsprMarketEntryPoint.delist_token ? 'from' : 'on'; + + return ( + + + {marketActionNameMap[entryPoint?.name || '']} + + {collectionHash && ( + + )} + + + {contractIdentifierPrefix} + + + + ); +}; + +const DefaultMarketAction = ({ deploy }: { deploy: Deploy }) => { + const { entryPoint, contractPackage } = deploy; + const { csprLiveDomainPath } = useDeployActionDataContext(); + return ( + + + {entryPoint?.name} + + + with + + + + ); +}; + +const DeployActionMarket = ({ deploy }: { deploy: Deploy }) => { + const { entryPoint, args } = deploy; + + const entryPointName = entryPoint?.name || ''; + + const collectionHash = guardedDeriveSplitDataFromArguments( + args.collection, + 'Hash', + ); + + const isOfferAction = + entryPointName === CsprMarketEntryPoint.accept_offer || + entryPointName === CsprMarketEntryPoint.make_offer || + entryPointName === CsprMarketEntryPoint.cancel_offer; + + const isListAction = + entryPointName === CsprMarketEntryPoint.delist_token || + entryPointName === CsprMarketEntryPoint.list_token; + + const nftTokenIds = getNftTokenIdsFromArguments(deploy.args); + + if (isOfferAction && collectionHash) { + return ( + + ); + } + + if (isListAction && collectionHash) { + return ( + + ); + } + + return ; +}; + +export default DeployActionMarket; diff --git a/src/lib/components/deploy-actions/components/DeployActionNft.tsx b/src/lib/components/deploy-actions/components/DeployActionNft.tsx new file mode 100644 index 00000000..cd64398a --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployActionNft.tsx @@ -0,0 +1,110 @@ +import React from 'react'; +import { NftCollectionIdentifier } from './NftCollectionIdentifier'; +import { NftActionRow, UpdateMetadataNFTAction } from './NftActionRow'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import { prepareNftActionMessageDataForDeployDetails } from '../utils/prepare-action-messages'; +import { Deploy } from '../../../types/types'; +import { guardedDeriveSplitDataFromArguments } from '../../../utils/deploy-args'; +import FlexRow from '../../flex-row/flex-row'; +import BodyText from '../../body-text/body-text'; +import { ContractIdentifier } from '../../contract-identifier/contract-identifier'; +import { HashFontSize } from '../../../utils/formatters'; +import DeployActionDefault from './DeployActionDefault'; +import { NftTokenEntryPoint } from '../../../types/NFTToken'; + +const SetAllApprovalsNFTAction = ({ deploy }: { deploy: Deploy }) => { + const { contractPackage, args } = deploy; + const { csprLiveDomainPath, getContractPackageInfoByHash } = + useDeployActionDataContext(); + const operatorHash = + args.operator && guardedDeriveSplitDataFromArguments(args.operator, 'Hash'); + + return ( + + + Approve transfer rights + + + of + + + all + + + + {operatorHash && ( + <> + + to + + + + )} + + ); +}; + +interface DeployNftActionProps { + deploy: Deploy; +} + +export const DeployActionNft = ({ deploy }: DeployNftActionProps) => { + const { getPublicKeyAccountHash } = useDeployActionDataContext(); + const message = prepareNftActionMessageDataForDeployDetails( + deploy, + getPublicKeyAccountHash, + ); + + if (!message) { + return ; + } + + const { + entryPointName, + actionName, + nftTokenIds, + contractPrefix, + account1, + account2, + prefix1, + } = message; + + if (entryPointName === NftTokenEntryPoint.set_approval_for_all) { + return ; + } + + if (entryPointName === NftTokenEntryPoint.update_token_meta) { + return ( + + ); + } + + return ( + + ); +}; diff --git a/src/lib/components/deploy-actions/components/DeployFiatAmount.tsx b/src/lib/components/deploy-actions/components/DeployFiatAmount.tsx new file mode 100644 index 00000000..23a0ca59 --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployFiatAmount.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import Big from 'big.js'; +import BodyText from '../../body-text/body-text'; +import { motesToCSPR, PrecisionCase } from '../../../utils/currency'; +import { formatCurrency, SMALL_PRECISION } from '../../../utils/formatters'; +import CsprAmount from '../../cspr-amount/cspr-amount'; + +interface DeployFiatAmountProps { + amount: string | null; + rate: number; +} + +const DeployFiatAmount = ({ amount, rate }: DeployFiatAmountProps) => { + const csprAmount = amount ? motesToCSPR(amount) : 0; + const currencyAmount = + rate && csprAmount ? Big(csprAmount).mul(rate).toString() : null; + + return ( + <> + + + + + ({formatCurrency(currencyAmount, 'USD', SMALL_PRECISION)}) + + + ); +}; + +export default DeployFiatAmount; diff --git a/src/lib/components/deploy-actions/components/DeployResultCep18.tsx b/src/lib/components/deploy-actions/components/DeployResultCep18.tsx new file mode 100644 index 00000000..41c5624e --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployResultCep18.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +import { Cep18ActionRow } from './Cep18ActionRow'; +import { FTActionTypeEnum } from '../../../types/FTToken'; + +const ftResultActionNameMap = { + [FTActionTypeEnum.Approve]: 'Granted transfer rights', + [FTActionTypeEnum.Transfer]: 'Transferred', + [FTActionTypeEnum.Burn]: 'Burned', + [FTActionTypeEnum.Mint]: 'Minted', +}; + +const ftResultActionSenderPrefixesMap = { + [FTActionTypeEnum.Transfer]: 'from', + [FTActionTypeEnum.Approve]: 'to', + [FTActionTypeEnum.Burn]: 'owned by', +}; + +export const DeployResultCep18 = ({ ftAction }) => { + const actionName = ftResultActionNameMap[ftAction.ft_action_type_id]; + const prefix = + ftAction.ft_action_type_id === FTActionTypeEnum.Approve ? 'for' : null; + const senderPrefix = + ftResultActionSenderPrefixesMap[ftAction.ft_action_type_id]; + + return ( + + ); +}; diff --git a/src/lib/components/deploy-actions/components/DeployResultNft.tsx b/src/lib/components/deploy-actions/components/DeployResultNft.tsx new file mode 100644 index 00000000..c322c6b9 --- /dev/null +++ b/src/lib/components/deploy-actions/components/DeployResultNft.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { NftActionRow, UpdateMetadataNFTAction } from './NftActionRow'; +import { NftActivityTypeEnum } from '../../../types/NFTToken'; + +const nftResultActionNameMap = { + [NftActivityTypeEnum.Approve]: 'Granted transfer rights', + [NftActivityTypeEnum.Burn]: 'Burned', + [NftActivityTypeEnum.Mint]: 'Minted', + [NftActivityTypeEnum.Transfer]: 'Transferred', + [NftActivityTypeEnum.Metadata]: 'Updated metadata', +}; + +const nftActionSenderPrefixesMap = { + [NftActivityTypeEnum.Transfer]: 'from', + [NftActivityTypeEnum.Burn]: 'owned by', +}; + +export const DeployResultNft = ({ nftAction }) => { + const { token_id, nft_action_id, from_hash, contract_package } = nftAction; + + const actionName = nftResultActionNameMap[nft_action_id]; + const contractPrefix = + nft_action_id === NftActivityTypeEnum.Approve ? 'for' : null; + const senderPrefix = nftActionSenderPrefixesMap[nft_action_id]; + + if (!contract_package) return null; + + if (nft_action_id === NftActivityTypeEnum.Metadata) { + return ( + + ); + } + + const senderHash = + nft_action_id === NftActivityTypeEnum.Transfer || + nft_action_id === NftActivityTypeEnum.Burn + ? from_hash + : null; + + return ( + + ); +}; diff --git a/src/lib/components/deploy-actions/components/NftActionRow.tsx b/src/lib/components/deploy-actions/components/NftActionRow.tsx new file mode 100644 index 00000000..4808dad9 --- /dev/null +++ b/src/lib/components/deploy-actions/components/NftActionRow.tsx @@ -0,0 +1,145 @@ +import React from 'react'; +import { NftCollectionIdentifier } from './NftCollectionIdentifier'; +import { NftTokenIds } from './NftTokenIds'; +import TransactorInfo from '../../../components/transactor-info/transactor-info'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import BodyText from '../../body-text/body-text'; +import FlexRow from '../../flex-row/flex-row'; +import { + AccountInfoResult, + DeployContractPackageResult, + TransactorHashType, +} from '../../../types/types'; + +export const UpdateMetadataNFTAction = ({ + actionName, + nftTokenIds, + contractPackage, +}) => { + const { csprLiveDomainPath } = useDeployActionDataContext(); + return ( + + + {actionName} + + + for + + + + + ); +}; + +interface NftActionRowProps { + actionName: string | undefined; + contractPrefix?: string | null; + senderPrefix?: string | null; + nftTokenIds?: string[] | null; + contract_package: DeployContractPackageResult; + from_hash?: string | null; + from_public_key?: string | null; + from_type?: TransactorHashType | null; + to_hash?: string; + to_public_key?: string | null; + to_type?: TransactorHashType | null; +} + +export const NftActionRow = ({ + actionName, + contractPrefix, + senderPrefix, + nftTokenIds, + contract_package, + from_public_key, + from_hash, + from_type, + to_hash, + to_public_key, + to_type, +}: NftActionRowProps) => { + const { getAccountInfo, getContractPackageInfoByHash, csprLiveDomainPath } = + useDeployActionDataContext(); + const fromAccountInfo = getAccountInfo( + from_public_key || from_hash || '', + ); + const toAccountInfo = getAccountInfo( + to_public_key || to_hash || '', + ); + + return ( + + + {actionName} + + {contractPrefix && ( + + {contractPrefix} + + )} + + + + {from_hash && ( + <> + {senderPrefix && ( + + {senderPrefix} + + )} + + + )} + {to_hash && ( + <> + + to + + + + )} + + ); +}; diff --git a/src/lib/components/deploy-actions/components/NftCollectionIdentifier.tsx b/src/lib/components/deploy-actions/components/NftCollectionIdentifier.tsx new file mode 100644 index 00000000..2f9cece8 --- /dev/null +++ b/src/lib/components/deploy-actions/components/NftCollectionIdentifier.tsx @@ -0,0 +1,35 @@ +import ContractIcon from '../../../components/contract-icon/contract-icon'; +import React from 'react'; +import { DeployContractPackageResult } from '../../../types/types'; +import BodyText from '../../body-text/body-text'; +import Link from '../../link/link'; + +export const NftCollectionIdentifier = ({ + path, + contractPackage, +}: { + path: string; + contractPackage: DeployContractPackageResult | undefined | null; +}) => { + return contractPackage ? ( + <> + + + + {contractPackage.name} + + + + NFT(s) + + + ) : null; +}; diff --git a/src/lib/components/deploy-actions/components/NftTokenIds.tsx b/src/lib/components/deploy-actions/components/NftTokenIds.tsx new file mode 100644 index 00000000..f8ca6733 --- /dev/null +++ b/src/lib/components/deploy-actions/components/NftTokenIds.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import styled from 'styled-components'; +import { HashLength, formatHash } from '../../../utils/formatters'; +import Link from '../../link/link'; +import Tooltip from '../../tooltip/tooltip'; +import BodyText from '../../body-text/body-text'; + +const TokenWrapper = styled.div(({ theme }) => ({ + padding: '2px 8px', + borderRadius: '4px', + backgroundColor: theme.styleguideColors.fillSecondary, +})); + +const MIN_TRUNCATE_HASH_LENGTH = HashLength.TINY * 2 + 3; + +export const NftTokenId = ({ token_id, path }) => { + const tokenIdContent = ( + + + + {formatHash(token_id.toString(), HashLength.LITTLE)} + + + + ); + + return token_id.length > MIN_TRUNCATE_HASH_LENGTH ? ( + + {tokenIdContent} + + ) : ( + tokenIdContent + ); +}; + +export const NftTokenIds = ({ + nftTokenIds, + collectionHash, + csprLiveDomainPath, +}: { + nftTokenIds: string[] | undefined | null; + collectionHash: string; + csprLiveDomainPath: string; +}) => { + return ( + <> + {nftTokenIds + ? nftTokenIds.map((nftId) => ( + + )) + : null} + + ); +}; diff --git a/src/lib/components/deploy-actions/components/TransferActionRow.tsx b/src/lib/components/deploy-actions/components/TransferActionRow.tsx new file mode 100644 index 00000000..ade80f31 --- /dev/null +++ b/src/lib/components/deploy-actions/components/TransferActionRow.tsx @@ -0,0 +1,182 @@ +import React from 'react'; +import Skeleton from 'react-loading-skeleton'; +import Avatar from '../../../components/avatar/avatar'; +import DeployFiatAmount from './DeployFiatAmount'; +import { useDeployActionDataContext } from '../services/deploy-action-context'; +import { + AccountCentralizedInfo, + AccountInfoResult, + DeployTransferResult, +} from '../../../types/types'; +import { AccountModel, deriveAccountInfo } from '../../../utils/account'; +import FlexRow from '../../flex-row/flex-row'; +import BodyText from '../../body-text/body-text'; +import Address from '../../address/address'; +import { TableDataNamedKey } from '../../table-data-named-key/table-data-named-key'; +import Link from '../../link/link'; +import AuctionContractIcon from '../../../assets/icons/ic-auction-contract.svg'; + +interface TransferActionAccountProps { + publicKey?: string | null; + accountHash?: string | null; + loading: boolean; + purse: string; + renderAsResultAction: boolean; + actionPoolAccountHash?: string; + purseAccountInfoFromTransfer?: + | AccountInfoResult + | AccountCentralizedInfo + | null; +} + +const TransferActionAccount = ({ + publicKey, + accountHash, + loading, + purse, + renderAsResultAction, + actionPoolAccountHash, + purseAccountInfoFromTransfer, +}: TransferActionAccountProps) => { + const { getAccountInfo, csprLiveDomainPath } = useDeployActionDataContext(); + + const accountInfo = getAccountInfo( + publicKey || accountHash || '', + ); + const accountInfoDetails = deriveAccountInfo( + accountInfo?.account_info || + accountInfo?.centralized_account_info || + purseAccountInfoFromTransfer, + ); + + const logo = accountInfoDetails && accountInfoDetails?.logo; + const name = accountInfoDetails?.name; + const csprName = accountInfo?.cspr_name; + + const isAuctionPoolAccount = accountHash === actionPoolAccountHash; + + if (isAuctionPoolAccount && renderAsResultAction) { + return ( + + + + Auction Pool + + + ); + } + + return publicKey || accountHash ? ( +
+ ) : ( + + ); +}; + +interface TransferActionRowProps { + timeTransactionCurrencyRate: number; + transfer: DeployTransferResult; + loading: boolean; + actionPoolAccountHash: string | undefined; + renderAsResultAction?: boolean; +} + +const TransferActionRow = ({ + timeTransactionCurrencyRate, + transfer, + loading, + actionPoolAccountHash, + renderAsResultAction = false, +}: TransferActionRowProps) => { + const fromAccountHash = transfer.from_purse_public_key + ? AccountModel({ + publicKeyHex: transfer.from_purse_public_key, + }).getAccountHash() + : ''; + + if (loading) { + return ( + + + + ); + } + + const deployActionText = renderAsResultAction ? 'Transferred' : 'Transfer'; + + return ( + + + {deployActionText} + {' '} + + {renderAsResultAction && ( + <> + + from + + + + + + )} + + to + + + + + + ); +}; +export default TransferActionRow; diff --git a/src/lib/components/deploy-actions/deploy-action-row.tsx b/src/lib/components/deploy-actions/deploy-action-row.tsx new file mode 100644 index 00000000..bfd3366a --- /dev/null +++ b/src/lib/components/deploy-actions/deploy-action-row.tsx @@ -0,0 +1,213 @@ +import React from 'react'; +import Skeleton from 'react-loading-skeleton'; +import { + ExecutionTypesMap, + isTransferDeploy, + isWASMProxyTransaction, + isWASMTransaction, +} from './utils/contract'; +import TransferActionRow from './components/TransferActionRow'; +import DeployActionCsprFun from './components/DeployActionCsprFun'; +import DeployActionAuction from './components/DeployActionAuction'; +import DeployActionAssociatedKeys from './components/DeployActionAssociatedKeys'; +import DeployActionMarket from './components/DeployActionMarket'; +import { DeployActionCep18 } from './components/DeployActionCep18'; +import { DeployActionNft } from './components/DeployActionNft'; +import DeployActionDefault from './components/DeployActionDefault'; +import { DeployActionDataProvider } from './services/deploy-action-context'; +import BodyText from '../body-text/body-text'; +import { + ContractResult, + ContractTypeId, + DataResponse, + Deploy, + DeployContractPackageResult, + GetDeployResult, +} from '../../types/types'; +import { Transaction } from 'casper-js-sdk'; +import { getWasmProxyArgumentsFromRawData } from './utils/deploy-action-helpers'; + +export type ActionIdentificationHashesType = { + auction_manager_contract_hash?: string; + associated_keys_contract_hash?: string; + cspr_market_contract_package_hash?: string; + auction_pool_account_hash?: string; + native_transfer_contract_hash?: string; +}; + +interface DeployActionRowComponentProps { + deploy: Deploy; + deployRawData?: DataResponse | null; + loading: boolean; + actionIdentificationHashes: ActionIdentificationHashesType; +} + +export const DeployActionRowComponent = ({ + deploy, + deployRawData, + loading, + actionIdentificationHashes, +}: DeployActionRowComponentProps) => { + const { + executionTypeId, + entryPoint, + contractPackage, + contractHash, + contractPackageHash, + } = deploy; + + const isWASMProxy = isWASMProxyTransaction(executionTypeId); + const convertedArgs = + isWASMProxy && deployRawData?.data + ? getWasmProxyArgumentsFromRawData( + Transaction.fromJSON(deployRawData?.data), + ) + : null; + + const deployWithConvertedArgs = { + ...deploy, + args: { + ...deploy.args, + ...(convertedArgs ? convertedArgs : null), + }, + }; + + const deployType = ExecutionTypesMap[executionTypeId]; + const isTransfer = isTransferDeploy( + contractHash, + entryPoint?.name, + actionIdentificationHashes?.native_transfer_contract_hash, + ); + const isWasm = isWASMTransaction(executionTypeId); // deployType !== WASM_DEPLOY; + const isCSPRFun = + deployWithConvertedArgs.args?.csprfun_contract_hash_key && + deployWithConvertedArgs?.args?.token_to_trade_contract_hash_key; + + if (loading) { + return ( + + + + ); + } + + if (isTransfer && deployWithConvertedArgs.transfers) { + return ( + + ); + } + + if (isWasm && !isCSPRFun) { + return ( + + {deployType} + + ); + } + + if (isCSPRFun) { + return ; + } + + if (!contractPackage) { + return ( + + N/A + + ); + } + const contractTypeId = + contractPackage.latest_version_contract_type_id || + contractPackage.contract_type_id; + + if ( + contractHash === actionIdentificationHashes.auction_manager_contract_hash + ) { + return ; + } + + if ( + contractHash === actionIdentificationHashes.associated_keys_contract_hash + ) { + return ( + + ); + } + + if ( + contractPackageHash === + actionIdentificationHashes.cspr_market_contract_package_hash + ) { + return ; + } + + if ( + contractTypeId === ContractTypeId.CustomCep18 || + contractTypeId === ContractTypeId.Cep18 + ) { + return ; + } + + if ( + contractTypeId === ContractTypeId.CEP78Nft || + contractTypeId === ContractTypeId.CEP47Nft || + contractTypeId === ContractTypeId.CustomCEP78Nft || + contractTypeId === ContractTypeId.CustomCEP47Nft || + contractTypeId === ContractTypeId.CEP95Nft + ) { + return ; + } + + return ; +}; + +type DeployActionRowProps = DeployActionRowComponentProps & { + getAccountInfo: (publicKey: string) => T | null | undefined; + getContractInfoByHash?: ( + contractHash: string, + ) => ContractResult | null | undefined; + getContractPackageInfoByHash: ( + contractPackageHash: string, + ) => DeployContractPackageResult | null | undefined; + csprLiveDomainPath: string; +}; + +export const DeployActionRow = (props: DeployActionRowProps) => { + const { + getAccountInfo, + getContractPackageInfoByHash, + getContractInfoByHash, + deployRawData, + loading, + deploy, + actionIdentificationHashes, + csprLiveDomainPath, + } = props; + return ( + + + + ); +}; diff --git a/src/lib/components/deploy-actions/deploy-result-row.tsx b/src/lib/components/deploy-actions/deploy-result-row.tsx new file mode 100644 index 00000000..a000e2d1 --- /dev/null +++ b/src/lib/components/deploy-actions/deploy-result-row.tsx @@ -0,0 +1,270 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import Skeleton from 'react-loading-skeleton'; +import DeployActionAssociatedKeys from './components/DeployActionAssociatedKeys'; +import { DeployResultNft } from './components/DeployResultNft'; +import { DeployResultCep18 } from './components/DeployResultCep18'; +import TransferActionRow from './components/TransferActionRow'; +import { ActionIdentificationHashesType } from './deploy-action-row'; +import { DeployActionDataProvider } from './services/deploy-action-context'; +import { + ContractResult, + DataResponse, + Deploy, + DeployTransferResult, + FTActionsResult, + GetDeployResult, + NftActionsResult, +} from '../../types/types'; +import FlexRow from '../flex-row/flex-row'; +import BodyText from '../body-text/body-text'; +import FlexColumn from '../flex-column/flex-column'; +import ExpandCollapsedButton from '../expand-collapsed/expand-collapsed-button'; +import { getDeployStatus, Status } from '../deploy-status/deploy-status'; + +const MAXIMUM_VISIBLE_ROWS = 3; + +enum DeployResultRowType { + 'NFT' = 1, + 'FT' = 2, + 'UNI' = 3, + 'LS' = 4, + 'NT' = 5, +} + +export enum ResultRowVariation { + default = 'default', + gray = 'gray', +} + +const sortActionsByTypeAndOrder = (deploy: Deploy) => { + const nftActions: NftActionsResult[] = (deploy.nftActions || []).map( + (action) => ({ + ...action, + type: DeployResultRowType.NFT, + }), + ); + const ftActions: FTActionsResult[] = (deploy.ftActions || []).map( + (action) => ({ + ...action, + type: DeployResultRowType.FT, + }), + ); + + const sortedTransfers: DeployTransferResult[] = (deploy.transfers || []) + .sort( + (transferA, transferB) => + transferA.transfer_index - transferB.transfer_index, + ) + .map((action) => ({ + ...action, + type: DeployResultRowType.NT, + })); + + const sortedTokenActions = [...nftActions, ...ftActions].sort( + (actionA, actionB) => actionA.transform_idx - actionB.transform_idx, + ); + + return [...sortedTransfers, ...sortedTokenActions]; +}; + +const DefaultResultItem = styled(FlexRow)(({ theme }) => ({ + padding: '14px 0', + ':not(:first-child):after': { + content: "''", + position: 'absolute', + left: 0, + right: 0, + top: 0, + borderBottom: theme.border.tableRowSeparator, + }, + + position: 'relative', +})); + +const GrayResultItem = styled(FlexRow)(({ theme }) => ({ + borderRadius: '4px', + background: `${theme.styleguideColors.backgroundSecondary}80`, + padding: '10px 16px', + position: 'relative', + span: { + fontSize: '13px', + }, + '> *': { + flexWrap: 'wrap', + }, + ':not(:first-child)': { + marginTop: '8px', + }, +})); + +const ResultItemWrapper = ({ variation, ...props }) => { + return variation === ResultRowVariation.default ? ( + + ) : ( + + ); +}; + +interface DeployResultRowComponentProps { + deploy: Deploy; + loading: boolean; + actionIdentificationHashes: ActionIdentificationHashesType; + deployRawData?: DataResponse | null; + actionComponents?: React.ReactElement[] | null; + variation?: ResultRowVariation; + shouldCollapse?: boolean; +} + +export const DeployResultRowComponent = ( + props: DeployResultRowComponentProps, +) => { + const { + deploy, + deployRawData, + loading, + actionIdentificationHashes, + variation = ResultRowVariation.default, + shouldCollapse = false, + actionComponents, + } = props; + const [isCollapsed, setCollapsed] = useState(shouldCollapse); + const handleExpandList = () => { + setCollapsed(!isCollapsed); + }; + + const deployStatus = getDeployStatus(deploy); + + if (deployStatus === Status.Error) { + return null; + } + + if (loading) { + return ( + + + + + + ); + } + + if ( + deploy.contractHash === + actionIdentificationHashes.associated_keys_contract_hash + ) { + return ( + + + + ); + } + + const showResultRow = + deploy.transfers || deploy.nftActions || deploy.ftActions; + + if (!showResultRow) { + return null; + } + + const sortedActions = sortActionsByTypeAndOrder(deploy); + + const getActionElementToRender = (action) => { + switch (action.type) { + case DeployResultRowType.NFT: + return ( + + ); + case DeployResultRowType.FT: + return ( + + ); + case DeployResultRowType.NT: + return ( + + ); + default: + return null; + } + }; + + const sortedActionComponents = sortedActions.map((action) => + getActionElementToRender(action), + ); + + const combinedActionComponents = [ + ...sortedActionComponents, + ...(actionComponents || []), + ]; + + return ( + + {combinedActionComponents?.length + ? combinedActionComponents + .filter((action, i) => + isCollapsed ? i < MAXIMUM_VISIBLE_ROWS : true, + ) + .map((action, idx) => ( + + {action} + + )) + : null} + {shouldCollapse && + combinedActionComponents?.length > MAXIMUM_VISIBLE_ROWS ? ( + + <>View all + {combinedActionComponents?.length} + <> results + + } + expandedLabel={<>Collapse results } + onExpand={handleExpandList} + /> + ) : null} + + ); +}; + +type DeployResultRowProps = DeployResultRowComponentProps & { + getAccountInfo: (publicKey: string) => T | null | undefined; + getContractPackageInfoByHash?: ( + contractHash: string, + ) => ContractResult | null | undefined; + csprLiveDomainPath: string; +}; + +export const DeployResultRow = (props: DeployResultRowProps) => { + const { + getAccountInfo, + getContractPackageInfoByHash, + getContractInfoByHash, + csprLiveDomainPath, + ...rest + } = props; + return ( + + + + ); +}; diff --git a/src/lib/components/deploy-actions/services/deploy-action-context.tsx b/src/lib/components/deploy-actions/services/deploy-action-context.tsx new file mode 100644 index 00000000..b350a863 --- /dev/null +++ b/src/lib/components/deploy-actions/services/deploy-action-context.tsx @@ -0,0 +1,78 @@ +import React, { + createContext, + PropsWithChildren, + useCallback, + useContext, +} from 'react'; + +type DeployActionDataContextType = { + getAccountInfo: (publicKey: string) => T | null | undefined; + getContractPackageInfoByHash: ( + contractPackageHash: string, + ) => T | null | undefined; + getContractInfoByHash?: (contractHash: string) => T | null | undefined; + getPublicKeyAccountHash: (accountHash: string) => string | null | undefined; + csprLiveDomainPath: string; +}; + +export const deployActionDataContext = + createContext({ + getAccountInfo: () => null, + getPublicKeyAccountHash: () => null, + getContractInfoByHash: () => null, + getContractPackageInfoByHash: () => null, + csprLiveDomainPath: '', + }); + +const { Provider: DeployActionDataContextProvider } = deployActionDataContext; + +export const useDeployActionDataContext = () => { + return useContext(deployActionDataContext); +}; + +type DeployActionDataProviderProps = { + getAccountInfo: (publicKey: string) => T | null | undefined; + getContractPackageInfoByHash?: ( + contractPackageHash: string, + ) => T | null | undefined; + getContractInfoByHash?: (contractHash: string) => T | null | undefined; + csprLiveDomainPath: string; +}; + +export const DeployActionDataProvider = ( + props: PropsWithChildren, +) => { + const { getAccountInfo, csprLiveDomainPath, children } = props; + + const getPublicKeyAccountHash = useCallback( + (accountHash: string): string | null | undefined => { + const publicKeyByHash = getAccountInfo(accountHash)?.public_key; + + return publicKeyByHash ? publicKeyByHash : null; + }, + [getAccountInfo], + ); + const getContractInfoByHash = (contractHash) => + props.getContractInfoByHash + ? props.getContractInfoByHash(contractHash) + : null; + + const getContractPackageInfoByHash = (contractPackageHash) => + props.getContractPackageInfoByHash + ? props.getContractPackageInfoByHash(contractPackageHash) + : null; + + return ( + + {children} + + ); +}; diff --git a/src/lib/components/deploy-actions/storybook/deploy-action-stories.tsx b/src/lib/components/deploy-actions/storybook/deploy-action-stories.tsx new file mode 100644 index 00000000..372d717c --- /dev/null +++ b/src/lib/components/deploy-actions/storybook/deploy-action-stories.tsx @@ -0,0 +1,118 @@ +import React from 'react'; +import { Meta, StoryFn } from '@storybook/react'; +import { DeployActionRow } from '../deploy-action-row'; +import FlexRow from '../../flex-row/flex-row'; +import FlexColumn from '../../flex-column/flex-column'; +import { + associatedKeysDeploy, + auctionDeploy, + csprFunDeploy, + defaultDeploy, + mockedAccountInfos, + mockedContractInfos, + mockedContractPackageInfos, + transferDeploy, + csprMarketDeploy, + cep18Deploy, + nftDeploy, +} from './mockedDeploys'; +import { MapDeploy } from '../utils/deploy-action-helpers'; +import BodyText from '../../body-text/body-text'; + +export default { + renderComponent: (args) => DeployActionRow, + title: 'Composites/Deploy/DeployActionRow', + args: { + deploy: MapDeploy(defaultDeploy), + loading: false, + actionIdentificationHashes: { + native_transfer_contract_hash: 'native_transfer_contract_hash', + auction_manager_contract_hash: 'auction_manager_contract_hash', + associated_keys_contract_hash: 'associated_keys_contract_hash', + cspr_market_contract_package_hash: 'cspr_market_contract_package_hash', + }, + getAccountInfo: (hash) => + mockedAccountInfos.filter( + (account) => + account.public_key === hash || account.account_hash === hash, + )[0], + getContractPackageInfoByHash: (hash) => + mockedContractPackageInfos.filter( + (contract_package) => contract_package.contract_package_hash === hash, + )[0], + getContractInfoByHash: (hash) => + mockedContractInfos.filter( + (contract) => contract.contract_hash === hash, + )[0], + }, +} as Meta; + +const exampleComponents = [ + { + templateLabel: 'Default deploy action message:', + renderComponent: (args) => , + }, + { + templateLabel: 'Transfer deploy action message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Cspr.fun deploy action message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Auction deploy action message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Associated keys deploy action message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Cspr market deploy action message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'CEP-18 deploy action message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Nft deploy action message:', + renderComponent: (args) => ( + + ), + }, +]; + +const TemplateDeployActions: StoryFn = (args) => { + return ( + + {exampleComponents.map((example) => ( + + + + {example.templateLabel} + + + + {example.renderComponent(args)} + + + ))} + + ); +}; + +export const DeployActions = TemplateDeployActions.bind({}); diff --git a/src/lib/components/deploy-actions/storybook/deploy-result-stories.tsx b/src/lib/components/deploy-actions/storybook/deploy-result-stories.tsx new file mode 100644 index 00000000..2897a3ff --- /dev/null +++ b/src/lib/components/deploy-actions/storybook/deploy-result-stories.tsx @@ -0,0 +1,141 @@ +import React from 'react'; +import { Meta, StoryFn } from '@storybook/react'; +import FlexRow from '../../flex-row/flex-row'; +import FlexColumn from '../../flex-column/flex-column'; +import { + associatedKeysDeploy, + auctionDeploy, + csprFunDeploy, + defaultDeploy, + mockedAccountInfos, + mockedContractInfos, + mockedContractPackageInfos, + transferDeploy, + csprMarketDeploy, + cep18Deploy, + nftDeploy, +} from './mockedDeploys'; +import { MapDeploy } from '../utils/deploy-action-helpers'; +import BodyText from '../../body-text/body-text'; +import { DeployResultRow, ResultRowVariation } from '../deploy-result-row'; + +export default { + renderComponent: (args) => DeployResultRow, + title: 'Composites/Deploy/DeployResultRow', + args: { + deploy: MapDeploy(defaultDeploy), + loading: false, + actionIdentificationHashes: { + native_transfer_contract_hash: 'native_transfer_contract_hash', + auction_manager_contract_hash: 'auction_manager_contract_hash', + associated_keys_contract_hash: 'associated_keys_contract_hash', + cspr_market_contract_package_hash: 'cspr_market_contract_package_hash', + }, + getAccountInfo: (hash) => + mockedAccountInfos.filter( + (account) => + account.public_key === hash || account.account_hash === hash, + )[0], + getContractPackageInfoByHash: (hash) => + mockedContractPackageInfos.filter( + (contract_package) => contract_package.contract_package_hash === hash, + )[0], + getContractInfoByHash: (hash) => + mockedContractInfos.filter( + (contract) => contract.contract_hash === hash, + )[0], + }, +} as Meta; + +const exampleComponents = [ + { + templateLabel: 'Transfer deploy results message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Cspr.fun deploy results message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Auction deploy results message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Associated keys deploy results message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Cspr market deploy results message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'CEP-18 deploy results message:', + renderComponent: (args) => ( + + ), + }, + { + templateLabel: 'Nft deploy results message:', + renderComponent: (args) => ( + + ), + }, +]; + +const TemplateDeployDefaultResults: StoryFn = ( + args, +) => { + return ( + + {exampleComponents.map((example) => ( + + + + {example.templateLabel} + + + + {example.renderComponent(args)} + + + ))} + + ); +}; + +export const DeployDefaultResults = TemplateDeployDefaultResults.bind({}); + +const TemplateDeployGreyBgResults: StoryFn = (args) => { + const styledArgs = { + ...args, + variation: ResultRowVariation.gray, + }; + return ( + + {exampleComponents.map((example) => ( + + + + {example.templateLabel} + + + + {example.renderComponent(styledArgs)} + + + ))} + + ); +}; + +export const DeployGreyResults = TemplateDeployGreyBgResults.bind({}); diff --git a/src/lib/components/deploy-actions/storybook/mockedDeploys.ts b/src/lib/components/deploy-actions/storybook/mockedDeploys.ts new file mode 100644 index 00000000..ef5afb4d --- /dev/null +++ b/src/lib/components/deploy-actions/storybook/mockedDeploys.ts @@ -0,0 +1,1826 @@ +export const mockedAccountInfos = [ + { + account_hash: + '8c15bba2d147859c7b7a8f43028eeb4d3c9571c6e36dfecc97c77463d3af08cd', + account_info: null, + balance: '17036461366585526', + centralized_account_info: { + account_hash: + '8c15bba2d147859c7b7a8f43028eeb4d3c9571c6e36dfecc97c77463d3af08cd', + avatar_url: + 'https://casper-assets.s3.amazonaws.com/accounts/cspr-association.png', + name: 'Casper Association', + url: 'https://casper.network', + }, + cspr_name: null, + deployment_threshold: 2, + genesis_balance: '2964329384000000000', + key_management_threshold: 3, + main_purse_uref: + 'uref-105bddece7eb0ef2d1daa8ad46e18af59e803d99a4a5d5dc9393502246fbcfe3-007', + public_key: + '02024c5e3ba7b1da49cda950319aec914cd3c720fbec3dcf25aa4add631e28f70aa9', + }, + { + account_hash: + '3bb2277db93e2c812ec9f68c9b02a5d54c524e9c3583a41da6388b89a94ed487', + account_info: { + account_hash: + '3bb2277db93e2c812ec9f68c9b02a5d54c524e9c3583a41da6388b89a94ed487', + created: '2022-04-08T17:48:39Z', + deploy_hash: + 'ec17087cd4940829bd2455cc08a4e6da3023add50ee351edc5f5e6dcaadcb1a4', + info: { + nodes: [ + { + description: + 'This validator is running on a bare metal machine with top hardware specifications.', + functionality: ['validator'], + location: { + country: 'PL', + latitude: 0, + longitude: 0, + name: 'Poznan', + }, + public_key: + '01e688f7fa2d1e011f4ba40f5edd3bb4e8c46bce4b9985a4806a4f9cd032f318e6', + }, + ], + owner: { + affiliated_accounts: [ + { + public_key: + '01e688f7fa2d1e011f4ba40f5edd3bb4e8c46bce4b9985a4806a4f9cd032f318e6', + }, + ], + branding: { + logo: { + png_1024: '', + png_256: 'https://caspervalidator.pl/images/cspr.png', + svg: '', + }, + }, + description: + 'This validator is running on a bare metal machine with top hardware specifications.', + email: 'your.validator@gmail.com', + identity: { + casper_association_kyc_onchain: '', + casper_association_kyc_url: '', + ownership_disclosure_url: '', + }, + location: { + country: 'PL', + latitude: 0, + longitude: 0, + name: 'Poznan', + }, + name: 'Casper Validator', + social: { + facebook: '', + github: '', + keybase: '', + medium: '', + reddit: '', + telegram: '', + twitter: '', + wechat: '', + youtube: '', + }, + type: ['validator'], + website: 'https://caspervalidator.pl', + }, + }, + is_active: true, + updated: '2025-11-25T00:00:21Z', + url: 'https://caspervalidator.pl', + verified_account_hashes: [ + '3BB2277DB93E2C812EC9F68C9B02A5D54C524E9C3583A41DA6388B89A94ED487', + ], + }, + balance: '2406558050764', + centralized_account_info: null, + cspr_name: null, + deployment_threshold: 1, + genesis_balance: null, + key_management_threshold: 1, + main_purse_uref: + 'uref-ce75562ae6bc7acd45d837a0007a0c9462d7e7e80210893b21a1546d0accf4eb-007', + public_key: + '01e688f7fa2d1e011f4ba40f5edd3bb4e8c46bce4b9985a4806a4f9cd032f318e6', + }, + { + account_hash: + '6174cf2e6f8fed1715c9a3bace9c50bfe572eecb763b0ed3f644532616452008', + account_info: null, + auction_status: null, + balance: '0', + centralized_account_info: { + account_hash: + '6174cf2e6f8fed1715c9a3bace9c50bfe572eecb763b0ed3f644532616452008', + avatar_url: + 'https://casper-assets.s3.amazonaws.com/accounts/auction-pool.svg', + name: 'Auction Pool', + url: 'https://docs.casper.network/staking/', + }, + cspr_name: null, + delegated_balance: null, + deployment_threshold: 1, + genesis_balance: null, + key_management_threshold: 1, + main_purse_uref: + 'uref-f5025ad2c07c8952484c13edc575e4a10a158af6bf99698a1e4c61ce2d3013e6-007', + public_key: null, + staked_balance: null, + undelegating_balance: null, + }, + { + account_hash: + 'fe115dcc6d78f929a5cd2fc4ffd94ffc7d5a2f542e0dcc4df39a59e4948e8299', + account_info: null, + auction_status: null, + balance: '0', + centralized_account_info: null, + cspr_name: 'banana.cspr', + delegated_balance: null, + deployment_threshold: 1, + genesis_balance: null, + key_management_threshold: 1, + main_purse_uref: + 'uref-0549906b69951cdc4989fb71a70b5c84b8d0d0af013fc24fccf66cf0a0c834f2-007', + public_key: + '0202f1ba488be1aeec9d6f597bcc88dda5a93181f87f3f7c1d271cebc8e5dd625684', + staked_balance: null, + undelegating_balance: null, + }, + { + account_hash: + 'ba86b6ac0797768b5603ee6d6d68545ab9bc5c67df8e0ff47b7d66804d80643e', + account_info: null, + balance: '0', + centralized_account_info: null, + cspr_name: null, + deployment_threshold: 1, + genesis_balance: null, + key_management_threshold: 1, + main_purse_uref: + 'uref-9821025530e70f7b3ebd7004408da9f4538985db2be542f628b8ac3843a50dbd-007', + public_key: + '020374057352dfa78c21b9258942c15353e208f4865f0f5bfc1b6bf16db431c9fe5a', + }, +]; + +export const mockedContractPackageInfos = [ + { + account_info: null, + centralized_account_info: null, + coingecko_data: null, + coingecko_id: null, + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + cspr_name: null, + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + friendlymarket_data: null, + has_ces_events: true, + icon_url: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + is_contract_info_approved: true, + latest_version_contract_hash: + '678b0982117ab020bbd21736f969b364e7764679de0030faecc1aa8501e0338b', + latest_version_contract_type_id: 2, + metadata: { + balances_uref: + 'uref-0e59cd9be7d0f0e180752d936ddff05df3c0685586e358bf662fc8b9b2225eb9-007', + decimals: 9, + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + logo: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + name: 'Ghostbuster Token', + symbol: 'GBT', + total_supply_uref: + 'uref-1787a63eb00218548c8692ef3eea577537440c0a9265e41aea162c5453d5b742-007', + }, + name: 'Ghostbuster Token', + owner_hash: + 'a03d568737faa6878e070da838cd596c2afdd0ee75b0a8baec745042f5ddbe3f', + owner_public_key: + '020251c907e8837018c48b403275e4c5a5800c087cf4ffa6e85e6210705660682b75', + timestamp: '2025-08-19T23:06:43Z', + website_url: null, + }, + { + account_info: null, + centralized_account_info: null, + coingecko_data: null, + coingecko_id: null, + contract_package_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + cspr_name: null, + description: + 'Effortlessly create and launch your own custom token in just a few minutes. No coding required.', + friendlymarket_data: null, + has_ces_events: true, + icon_url: 'https://assets.cspr.fun/logos/7sc8oekolbo.png', + is_contract_info_approved: true, + latest_version_contract_hash: + '122ae343fb9e2c75e27ad7661bca3e001caf5b7d54f9db119275ae0993f1077f', + latest_version_contract_type_id: null, + metadata: {}, + name: 'CSPR.fun', + owner_hash: + '79f62bc7ae2be67903b7c2632e90b4168933657caebd05da25e20e8b48fd4ad9', + owner_public_key: + '01c8f445cc89f36395b3a2b365ca85f08f1e6498de7068a8dde7bd6406ed33d47f', + timestamp: '2025-08-17T13:04:39Z', + website_url: 'https://cspr.fun', + }, + { + account_info: null, + centralized_account_info: null, + coingecko_data: null, + coingecko_id: null, + contract_package_hash: + 'da405d7d7a85732cc17f944f7afcacd37590ce0b8666400c51df8823e820269f', + cspr_name: null, + description: 'Casper Toys by S_E_R_G_I_O_589', + friendlymarket_data: null, + has_ces_events: true, + icon_url: + 'https://maritime.sealstorage.io/make/c4e5a03066ce3c60/c7b6bfa84b1b4e62ae7671eca0961cb6', + is_contract_info_approved: true, + latest_version_contract_hash: + '83fbd793939cbf875748849abef7e4c441ee32c64c6009bd0775e70c5eb47006', + latest_version_contract_type_id: 7, + metadata: { + burn_mode: 0, + events_mode: 2, + holder_mode: 2, + identifier_mode: 0, + metadata_mutability: 0, + minting_mode: 0, + name: 'Casper Toys от S_E_R_G_I_O_589', + nft_kind: 1, + nft_metadata_kind: 2, + ownership_mode: 2, + symbol: 'CTS', + total_supply_uref: + 'uref-8d2bb078123b5d379c6f8a7650f63ddb846557854ea28ee8fc3922cc359979ba-007', + whitelist_mode: 0, + }, + name: 'Casper Toys от S_E_R_G_I_O_589', + owner_hash: null, + owner_public_key: + '02033bfaba171bee08f9cd29aeed85ceaf3b11a590f682da437e43303a0ada77ea0d', + timestamp: '2023-08-20T10:37:53Z', + website_url: null, + }, + { + coingecko_id: null, + contract_package_hash: + '31cc023b17c903a963ec60eab96a60f1fa37cb74b4b3bafc91a441e0e9d70f97', + description: + 'CSPR.market smart contract that manages the marketplace order book and transactions', + icon_url: 'https://casper-assets.s3.amazonaws.com/contracts/csprmarket.png', + is_contract_info_approved: true, + latest_version_contract_type_id: null, + metadata: {}, + name: 'CSPR.market v1', + owner_hash: null, + owner_public_key: + '02033d8502125c698fdea5edd240bb366166216141c3526bc23e765d1331b216b7e8', + timestamp: '2023-07-19T23:44:21Z', + website_url: 'https://cspr.market', + }, +]; + +export const mockedContractInfos = [ + { + contract_hash: + '678b0982117ab020bbd21736f969b364e7764679de0030faecc1aa8501e0338b', + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + deploy_hash: + '8053ae93a0ac2ce7c746872eb2358f63b0a5a686a185158fe24f1711d76b977b', + block_height: 5348304, + contract_type_id: 2, + timestamp: '2025-08-19T23:06:43Z', + contract_version: 1, + is_disabled: false, + contract_package: { + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + owner_public_key: + '020251c907e8837018c48b403275e4c5a5800c087cf4ffa6e85e6210705660682b75', + owner_hash: + 'a03d568737faa6878e070da838cd596c2afdd0ee75b0a8baec745042f5ddbe3f', + name: 'Ghostbuster Token', + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + metadata: { + balances_uref: + 'uref-0e59cd9be7d0f0e180752d936ddff05df3c0685586e358bf662fc8b9b2225eb9-007', + decimals: 9, + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + logo: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + name: 'Ghostbuster Token', + symbol: 'GBT', + total_supply_uref: + 'uref-1787a63eb00218548c8692ef3eea577537440c0a9265e41aea162c5453d5b742-007', + }, + latest_version_contract_type_id: 2, + timestamp: '2025-08-19T23:06:43Z', + icon_url: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + website_url: null, + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + }, +]; + +export const defaultDeploy = { + deploy_hash: + '71164c73c55dfe4f2b7f32c2f0fede2e28e48aa5e710c449a3bd1ff787ca979d', + block_hash: + '1dea7e9aef9888b3e8132844e5102b7279d842daea76e9064b58c6d0c965bfdf', + block_height: 5855731, + caller_public_key: + '01bf489970ee9ad639854b9a78ed19d08b5f8d8f2185099b44c0fc5f6f467b14b4', + caller_hash: + '9945a99148394a58637238c81c425ad7a3ef2ee1a7d964a3cf3e97a1d6c04738', + execution_type_id: 6, + contract_package_hash: + '86f2d45f024d7bb7fb5266b2390d7c253b588a0a16ebd946a60cb4314600af74', + contract_hash: + 'ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea', + entry_point_id: 20, + args: { + amount: { + cl_type: 'U512', + parsed: '38795658520042', + }, + public_key: { + cl_type: 'PublicKey', + parsed: + '01bf489970ee9ad639854b9a78ed19d08b5f8d8f2185099b44c0fc5f6f467b14b4', + }, + }, + payment_amount: '6000000000', + refund_amount: '0', + cost: '6000000000', + consumed_gas: '6000000000', + error_message: null, + status: 'processed', + timestamp: '2025-11-24T06:50:13Z', + rate: 8.78, + account_info: { + account_hash: + '9945a99148394a58637238c81c425ad7a3ef2ee1a7d964a3cf3e97a1d6c04738', + created: '2023-07-29T08:57:53Z', + deploy_hash: + '57006f20012a48671131af933a9aaaf31b21aa5a71137a38410e3854a719ce1e', + info: { + nodes: [ + { + description: + 'This validator is running on a bare metal machine with top hardware specifications', + functionality: ['validator'], + location: { + country: 'NL', + latitude: 51.991485, + longitude: 4.20695, + name: 'NAALDWIJK', + }, + public_key: + '012bac1d0ff9240ff0b7b06d555815640497861619ca12583ddef434885416e69b', + }, + { + description: + 'This validator is running on a bare metal machine with top hardware specifications', + functionality: ['validator'], + location: { + country: 'DE', + latitude: 49.2326, + longitude: 7.00982, + name: 'Saarbrucken', + }, + public_key: + '01bf489970ee9ad639854b9a78ed19d08b5f8d8f2185099b44c0fc5f6f467b14b4', + }, + ], + owner: { + affiliated_accounts: [ + { + public_key: + '012bac1d0ff9240ff0b7b06d555815640497861619ca12583ddef434885416e69b', + }, + { + public_key: + '01bf489970ee9ad639854b9a78ed19d08b5f8d8f2185099b44c0fc5f6f467b14b4', + }, + ], + branding: { + logo: { + png_1024: 'https://everstake.one/img/Everstake-1024.png', + png_256: 'https://everstake.one/img/Everstake-256.png', + svg: 'https://everstake.one/img/Everstake-logo.svg', + }, + }, + description: + 'Reliable and experienced staking service provider from Ukraine.', + email: 'inbox@everstake.one', + identity: { + casper_association_kyc_onchain: '', + casper_association_kyc_url: '', + ownership_disclosure_url: '', + }, + location: { + country: 'UA', + latitude: 50.418493, + longitude: 30.517631, + name: 'Kyiv', + }, + name: 'Everstake', + resources: { + code_of_conduct_url: '', + other: [ + { + name: 'About Us', + url: 'https://everstake.one', + }, + ], + privacy_policy_url: '', + terms_of_service_url: '', + }, + social: { + discord: 'https://discord.com/invite/PqrbhKNpA5', + facebook: '', + github: 'everstake', + keybase: 'everstake', + medium: '@everstake', + reddit: 'Everstake', + telegram: '', + twitter: '@everstake_pool', + wechat: '', + youtube: '', + }, + type: ['validator'], + website: 'https://everstake.one', + }, + }, + is_active: true, + updated: '2025-11-24T00:00:12Z', + url: 'https://casper.everstake.one', + verified_account_hashes: [ + '24B6D5AABB8F0AC17D272763A405E9CECA9166B75B745CF200695E172857C2DD', + '9945A99148394A58637238C81C425AD7A3EF2EE1A7D964A3CF3E97A1D6C04738', + ], + }, + centralized_account_info: null, + contract_package: { + contract_package_hash: + '86f2d45f024d7bb7fb5266b2390d7c253b588a0a16ebd946a60cb4314600af74', + owner_public_key: null, + owner_hash: null, + name: 'Auction', + description: + 'Built-in contract that allows interaction with the validator auction, and provides possibility to bid and delegate funds to Casper network participants', + metadata: {}, + latest_version_contract_type_id: 1, + timestamp: '2021-03-31T15:00:40Z', + icon_url: 'https://casper-assets.s3.amazonaws.com/contracts/auction.png', + website_url: 'https://casper.network', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + contract: { + block_height: 0, + contract_hash: + 'ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea', + contract_package_hash: + '86f2d45f024d7bb7fb5266b2390d7c253b588a0a16ebd946a60cb4314600af74', + contract_type_id: 1, + contract_version: 1, + deploy_hash: null, + is_disabled: true, + major_protocol_version: 1, + timestamp: '2021-03-31T15:00:40Z', + }, + contract_entrypoint: { + action_type_id: null, + contract_hash: + 'ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea', + contract_package_hash: + '86f2d45f024d7bb7fb5266b2390d7c253b588a0a16ebd946a60cb4314600af74', + id: 20, + name: 'withdraw_bid', + }, + caller_cspr_name: null, + transfers: null, + nft_token_actions: null, + ft_token_actions: null, +}; + +export const transferDeploy = { + deploy_hash: + '6b4c9add5c37bb17accc06b8dd55983480f95b10f87fff1e3b4f0d91a723ee1f', + block_hash: + 'd166b9c9c21db6be5fe002f4e39eaa37c8b9cda2b6f40ee1cd0137a42e9e146f', + block_height: 5857827, + caller_public_key: + '02037d4f9cdd7f9209c0826af3466510d13c5232713ed1d97783d90b77ebdf208808', + caller_hash: + '0c3dceb081b08078d56f5c5cad4630a9ee5307842beca1af9510559fbe81aaf3', + execution_type_id: 6, + contract_package_hash: + '4475016098705466254edd18d267a9dad43e341d4dafadb507d0fe3cf2d4a74b', + contract_hash: 'native_transfer_contract_hash', + entry_point_id: 10, + args: { + amount: { + cl_type: 'U512', + parsed: '388000000000', + }, + id: { + cl_type: { + Option: 'U64', + }, + parsed: null, + }, + target: { + cl_type: 'PublicKey', + parsed: + '02029aea8db4789c62a8de3f24886cd8aa4048aad40f898a269003bc34f0ab87c8ea', + }, + }, + payment_amount: '100000000', + refund_amount: '0', + cost: '100000000', + consumed_gas: '100000000', + error_message: null, + status: 'processed', + timestamp: '2025-11-24T16:22:26Z', + rate: 8.7, + account_info: null, + centralized_account_info: null, + contract_package: { + contract_package_hash: + '4475016098705466254edd18d267a9dad43e341d4dafadb507d0fe3cf2d4a74b', + owner_public_key: null, + owner_hash: null, + name: 'Mint', + description: + 'Built - in contract that controls all actions for moving token around in purses', + metadata: {}, + latest_version_contract_type_id: 1, + timestamp: '2021-03-31T15:00:40Z', + icon_url: 'https://casper-assets.s3.amazonaws.com/contracts/mint.png', + website_url: 'https://casper.network', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + contract: { + block_height: 0, + contract_hash: + '7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + contract_package_hash: + '4475016098705466254edd18d267a9dad43e341d4dafadb507d0fe3cf2d4a74b', + contract_type_id: 1, + contract_version: 1, + deploy_hash: null, + is_disabled: true, + major_protocol_version: 1, + timestamp: '2021-03-31T15:00:40Z', + }, + contract_entrypoint: { + action_type_id: null, + contract_hash: + '7cc1b1db4e08bbfe7bacf8e1ad828a5d9bcccbb33e55d322808c3a88da53213a', + contract_package_hash: + '4475016098705466254edd18d267a9dad43e341d4dafadb507d0fe3cf2d4a74b', + id: 10, + name: 'transfer', + }, + caller_cspr_name: null, + transfers: [ + { + id: 0, + transfer_index: null, + initiator_account_hash: + '0c3dceb081b08078d56f5c5cad4630a9ee5307842beca1af9510559fbe81aaf3', + from_purse: + 'uref-5ff2cea79c5ea0b157b830e89ca29f662f2384d19b9aad04ebc691994505ab6c-007', + to_purse: + 'uref-47dc78c6deea138929ff2c80fcad012312a3857cecd919d3179da45d9fb96425-004', + to_account_hash: + '2e912f8fe44443632d459ab1023ce615aa476028935b268c546c3b6acf26aaa5', + amount: '388000000000', + from_purse_public_key: + '02037d4f9cdd7f9209c0826af3466510d13c5232713ed1d97783d90b77ebdf208808', + to_purse_public_key: + '02029aea8db4789c62a8de3f24886cd8aa4048aad40f898a269003bc34f0ab87c8ea', + from_purse_account_info: null, + to_purse_account_info: null, + from_purse_centralized_account_info: null, + to_purse_centralized_account_info: null, + from_purse_cspr_name: null, + to_purse_cspr_name: null, + }, + ], + nft_token_actions: null, + ft_token_actions: null, +}; + +export const csprFunDeploy = { + deploy_hash: + '70991afa05d61c24f82e8315ea2ef93858c52613856c52ba16e19e3a7683d0d7', + block_hash: + '6c781ed4eea274ef71c3ed7afd7869db69801241d28c78269d56428840a59dc6', + block_height: 5855168, + caller_public_key: + '020217833dd53365fc6639b8f940f2df53d0415164face7a476416bbee7bdeac56f8', + caller_hash: + '14ef6746474e91d27c37a50566ee7262c388aa2cd1aa4c452f6028d55f37283f', + execution_type_id: 7, + contract_package_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + contract_hash: + '122ae343fb9e2c75e27ad7661bca3e001caf5b7d54f9db119275ae0993f1077f', + entry_point_id: 445439, + args: { + amount: { + cl_type: 'U512', + parsed: '9457654000000000', + }, + csprfun_contract_hash_key: { + cl_type: 'Key', + parsed: + 'hash-122ae343fb9e2c75e27ad7661bca3e001caf5b7d54f9db119275ae0993f1077f', + }, + csprfun_contract_package_hash_key: { + cl_type: 'Key', + parsed: + 'hash-91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + }, + is_buy: { + cl_type: 'Bool', + parsed: false, + }, + min_amount_received: { + cl_type: 'U256', + parsed: '8768615514999', + }, + recipient: { + cl_type: 'Key', + parsed: + 'account-hash-14ef6746474e91d27c37a50566ee7262c388aa2cd1aa4c452f6028d55f37283f', + }, + token_to_trade_contract_hash_key: { + cl_type: 'Key', + parsed: + 'hash-678b0982117ab020bbd21736f969b364e7764679de0030faecc1aa8501e0338b', + }, + wcspr_contract_hash_key: { + cl_type: 'Key', + parsed: + 'hash-40bd4a45c414df61be3832e28ff6dcedc479744707c611fd97fea0d90619146f', + }, + }, + payment_amount: '16000000000', + refund_amount: '5277516408', + cost: '16000000000', + consumed_gas: '8963311455', + error_message: null, + status: 'processed', + timestamp: '2025-11-24T04:16:26Z', + rate: 0.00604117, + account_info: null, + centralized_account_info: null, + contract_package: { + contract_package_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + owner_public_key: + '01c8f445cc89f36395b3a2b365ca85f08f1e6498de7068a8dde7bd6406ed33d47f', + owner_hash: + '79f62bc7ae2be67903b7c2632e90b4168933657caebd05da25e20e8b48fd4ad9', + name: 'CSPR.fun', + description: + 'Effortlessly create and launch your own custom token in just a few minutes. No coding required.', + metadata: {}, + latest_version_contract_type_id: null, + timestamp: '2025-08-17T13:04:39Z', + icon_url: 'https://assets.cspr.fun/logos/7sc8oekolbo.png', + website_url: 'https://cspr.fun', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + contract: { + block_height: 5335578, + contract_hash: + '122ae343fb9e2c75e27ad7661bca3e001caf5b7d54f9db119275ae0993f1077f', + contract_package_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + contract_type_id: null, + contract_version: 1, + deploy_hash: + 'ed3e26843fdfdb18fdbd53a31e3d307082406393ddbfea7f27e5e59b42254919', + is_disabled: false, + major_protocol_version: 2, + timestamp: '2025-08-17T13:04:39Z', + }, + contract_entrypoint: { + action_type_id: null, + contract_hash: + '122ae343fb9e2c75e27ad7661bca3e001caf5b7d54f9db119275ae0993f1077f', + contract_package_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + id: 445439, + name: 'trade', + }, + caller_cspr_name: null, + transfers: [ + { + id: 0, + transfer_index: null, + initiator_account_hash: + '14ef6746474e91d27c37a50566ee7262c388aa2cd1aa4c452f6028d55f37283f', + from_purse: + 'uref-f734ff5156f79bd8ff5114d752c8ffeffa1251709fa4226e99f221eb741ab69f-007', + to_purse: + 'uref-34407b70cf8b9b1d835ffd9e2834a576dde6e690103ac9d20160aa2636a2d35b-004', + to_account_hash: + '14ef6746474e91d27c37a50566ee7262c388aa2cd1aa4c452f6028d55f37283f', + amount: '9231076793968', + from_purse_public_key: null, + to_purse_public_key: + '020217833dd53365fc6639b8f940f2df53d0415164face7a476416bbee7bdeac56f8', + from_purse_account_info: null, + to_purse_account_info: null, + from_purse_centralized_account_info: null, + to_purse_centralized_account_info: null, + from_purse_cspr_name: null, + to_purse_cspr_name: null, + }, + ], + nft_token_actions: null, + ft_token_actions: [ + { + block_height: 5855168, + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + transform_idx: 7, + from_type: 0, + from_hash: + '14ef6746474e91d27c37a50566ee7262c388aa2cd1aa4c452f6028d55f37283f', + to_type: 1, + to_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + ft_action_type_id: 3, + amount: + '115792089237316195423570985008687907853269984665640564039457584007913129639935', + timestamp: null, + rate: null, + from_public_key: + '020217833dd53365fc6639b8f940f2df53d0415164face7a476416bbee7bdeac56f8', + to_public_key: null, + from_account_info: null, + to_account_info: null, + caller_account_info: null, + from_centralized_account_info: null, + to_centralized_account_info: null, + caller_centralized_account_info: null, + contract_package: { + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + owner_public_key: + '020251c907e8837018c48b403275e4c5a5800c087cf4ffa6e85e6210705660682b75', + owner_hash: + 'a03d568737faa6878e070da838cd596c2afdd0ee75b0a8baec745042f5ddbe3f', + name: 'Ghostbuster Token', + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + metadata: { + balances_uref: + 'uref-0e59cd9be7d0f0e180752d936ddff05df3c0685586e358bf662fc8b9b2225eb9-007', + decimals: 9, + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + logo: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + name: 'Ghostbuster Token', + symbol: 'GBT', + total_supply_uref: + 'uref-1787a63eb00218548c8692ef3eea577537440c0a9265e41aea162c5453d5b742-007', + }, + latest_version_contract_type_id: 2, + timestamp: '2025-08-19T23:06:43Z', + icon_url: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + website_url: null, + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + deploy: null, + from_cspr_name: null, + to_cspr_name: null, + }, + { + block_height: 5855168, + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + transform_idx: 36, + from_type: 0, + from_hash: + '14ef6746474e91d27c37a50566ee7262c388aa2cd1aa4c452f6028d55f37283f', + to_type: 1, + to_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + ft_action_type_id: 2, + amount: '9457654000000000', + timestamp: null, + rate: null, + from_public_key: + '020217833dd53365fc6639b8f940f2df53d0415164face7a476416bbee7bdeac56f8', + to_public_key: null, + from_account_info: null, + to_account_info: null, + caller_account_info: null, + from_centralized_account_info: null, + to_centralized_account_info: null, + caller_centralized_account_info: null, + contract_package: { + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + owner_public_key: + '020251c907e8837018c48b403275e4c5a5800c087cf4ffa6e85e6210705660682b75', + owner_hash: + 'a03d568737faa6878e070da838cd596c2afdd0ee75b0a8baec745042f5ddbe3f', + name: 'Ghostbuster Token', + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + metadata: { + balances_uref: + 'uref-0e59cd9be7d0f0e180752d936ddff05df3c0685586e358bf662fc8b9b2225eb9-007', + decimals: 9, + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + logo: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + name: 'Ghostbuster Token', + symbol: 'GBT', + total_supply_uref: + 'uref-1787a63eb00218548c8692ef3eea577537440c0a9265e41aea162c5453d5b742-007', + }, + latest_version_contract_type_id: 2, + timestamp: '2025-08-19T23:06:43Z', + icon_url: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + website_url: null, + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + deploy: null, + from_cspr_name: null, + to_cspr_name: null, + }, + { + block_height: 5855168, + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + transform_idx: 49, + from_type: 1, + from_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + to_type: 0, + to_hash: + '17c58c52c4a1a65a5a84b30162580dbe0e6b74bd415966cc5aae98fd3eb04326', + ft_action_type_id: 2, + amount: '94576540000000', + timestamp: null, + rate: null, + from_public_key: null, + to_public_key: + '01ac293aca885f5579fb7695b95d76df78aee30534a2cc02841454ddb171c4fac9', + from_account_info: null, + to_account_info: null, + caller_account_info: null, + from_centralized_account_info: null, + to_centralized_account_info: null, + caller_centralized_account_info: null, + contract_package: { + contract_package_hash: + '250d115534ca639f1f14b0a5e5cdf2c49d08c8e869ce897047088109046322d6', + owner_public_key: + '020251c907e8837018c48b403275e4c5a5800c087cf4ffa6e85e6210705660682b75', + owner_hash: + 'a03d568737faa6878e070da838cd596c2afdd0ee75b0a8baec745042f5ddbe3f', + name: 'Ghostbuster Token', + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + metadata: { + balances_uref: + 'uref-0e59cd9be7d0f0e180752d936ddff05df3c0685586e358bf662fc8b9b2225eb9-007', + decimals: 9, + description: + "If there's something wrong, in the web3-hood, who you're going to call? ", + logo: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + name: 'Ghostbuster Token', + symbol: 'GBT', + total_supply_uref: + 'uref-1787a63eb00218548c8692ef3eea577537440c0a9265e41aea162c5453d5b742-007', + }, + latest_version_contract_type_id: 2, + timestamp: '2025-08-19T23:06:43Z', + icon_url: 'https://assets.cspr.fun/logos/2gs94zxwva7.png', + website_url: null, + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + deploy: null, + from_cspr_name: null, + to_cspr_name: null, + }, + { + block_height: 5855168, + contract_package_hash: + 'b42a439eb81cc5bf250e30785eaa59c7285a919663a98a21217df0fd7dcb19a3', + transform_idx: 59, + from_type: 1, + from_hash: + '91683630ce3bd09003e039eee22a013d36ebe7d6aa25f52f5fd3311bb2ca875c', + to_type: 0, + to_hash: + '14ef6746474e91d27c37a50566ee7262c388aa2cd1aa4c452f6028d55f37283f', + ft_action_type_id: 2, + amount: '9231076793968', + timestamp: null, + rate: null, + from_public_key: null, + to_public_key: + '020217833dd53365fc6639b8f940f2df53d0415164face7a476416bbee7bdeac56f8', + from_account_info: null, + to_account_info: null, + caller_account_info: null, + from_centralized_account_info: null, + to_centralized_account_info: null, + caller_centralized_account_info: null, + contract_package: { + contract_package_hash: + 'b42a439eb81cc5bf250e30785eaa59c7285a919663a98a21217df0fd7dcb19a3', + owner_public_key: + '01f61490e53606fbec3bcd9124213eac25186faafa150af9f6b9efc45358f844d1', + owner_hash: null, + name: 'Wrapped Casper (Friendly Market)', + description: + 'Wrapped CSPR is a fungible, tradable version of CSPR used across Friendly Market’s DeFi ecosystem.', + metadata: { + balances_uref: + 'uref-014516655d42f506655255b00adccc5651e1de270f2dfd0206aae2b79b0c10ee-007', + decimals: 9, + name: 'Wrapped Casper', + symbol: 'WCSPR', + total_supply_uref: + 'uref-a0987e3fa8df4d1240f5c7092413af89ac6e6c15825010fb9742152e82325ceb-007', + }, + latest_version_contract_type_id: 2, + timestamp: '2022-05-29T18:26:33Z', + icon_url: + 'https://casper-assets.s3.amazonaws.com/contracts/friendly-wcspr.png', + website_url: 'https://www.friendly.market', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + deploy: null, + from_cspr_name: null, + to_cspr_name: null, + }, + ], +}; + +export const auctionDeploy = { + deploy_hash: + '3bb681aac2334a3a97a1e75399fc2bd22b306642229402ae31564358391beb3f', + block_hash: + '59e70705e1a00408199575bdd73d0e48b0328205dc7e016bb97c65c85bca0d60', + block_height: 5862181, + caller_public_key: + '0202eb6d725c2b10ae682af26ed6e49364ede03f306383fb038c0e736ad76436e8aa', + caller_hash: + '95cf8f83bf7f6ed59f1d53c00b98825247a5e8d8eaa75655fa01c149009a89ed', + execution_type_id: 2, + contract_package_hash: + '86f2d45f024d7bb7fb5266b2390d7c253b588a0a16ebd946a60cb4314600af74', + contract_hash: 'auction_manager_contract_hash', + entry_point_id: 13, + args: { + amount: { + cl_type: 'U512', + parsed: '248410155400000', + }, + delegator: { + cl_type: 'PublicKey', + parsed: + '0202eb6d725c2b10ae682af26ed6e49364ede03f306383fb038c0e736ad76436e8aa', + }, + validator: { + cl_type: 'PublicKey', + parsed: + '01e688f7fa2d1e011f4ba40f5edd3bb4e8c46bce4b9985a4806a4f9cd032f318e6', + }, + }, + payment_amount: '2500000000', + refund_amount: '0', + cost: '2500000000', + consumed_gas: '2500000000', + error_message: null, + status: 'processed', + timestamp: '2025-11-25T12:10:45Z', + rate: 0.00601674, + account_info: null, + centralized_account_info: null, + contract_package: { + contract_package_hash: + '86f2d45f024d7bb7fb5266b2390d7c253b588a0a16ebd946a60cb4314600af74', + owner_public_key: null, + owner_hash: null, + name: 'Auction', + description: + 'Built-in contract that allows interaction with the validator auction, and provides possibility to bid and delegate funds to Casper network participants', + metadata: {}, + latest_version_contract_type_id: 1, + timestamp: '2021-03-31T15:00:40Z', + icon_url: 'https://casper-assets.s3.amazonaws.com/contracts/auction.png', + website_url: 'https://casper.network', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + contract: { + block_height: 0, + contract_hash: + 'ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea', + contract_package_hash: + '86f2d45f024d7bb7fb5266b2390d7c253b588a0a16ebd946a60cb4314600af74', + contract_type_id: 1, + contract_version: 1, + deploy_hash: null, + is_disabled: true, + major_protocol_version: 1, + timestamp: '2021-03-31T15:00:40Z', + }, + contract_entrypoint: { + action_type_id: null, + contract_hash: + 'ccb576d6ce6dec84a551e48f0d0b7af89ddba44c7390b690036257a04a3ae9ea', + contract_package_hash: + '86f2d45f024d7bb7fb5266b2390d7c253b588a0a16ebd946a60cb4314600af74', + id: 13, + name: 'delegate', + }, + caller_cspr_name: null, + transfers: [ + { + id: 0, + transfer_index: null, + initiator_account_hash: + '95cf8f83bf7f6ed59f1d53c00b98825247a5e8d8eaa75655fa01c149009a89ed', + from_purse: + 'uref-9489b8444967d563f520eb353ecc2b5404ccb859923784b18a9f87cb3f9ec2ef-007', + to_purse: + 'uref-cb4626140704059af3a7eda4ed2fafb52035a408e363e3daed0b0a34f4f46040-007', + to_account_hash: + '6174cf2e6f8fed1715c9a3bace9c50bfe572eecb763b0ed3f644532616452008', + amount: '248410155400000', + from_purse_public_key: + '0202eb6d725c2b10ae682af26ed6e49364ede03f306383fb038c0e736ad76436e8aa', + to_purse_public_key: null, + from_purse_account_info: null, + to_purse_account_info: null, + from_purse_centralized_account_info: null, + to_purse_centralized_account_info: null, + from_purse_cspr_name: null, + to_purse_cspr_name: null, + }, + ], + nft_token_actions: null, + ft_token_actions: null, +}; + +export const associatedKeysDeploy = { + deploy_hash: + 'f66f53d8f83d27d280c05faef5bb65d0b7161a010359735fa875097b552b0a1f', + block_hash: + '855d7fd0c3ba31b149251e5b936ee76a1403b1d9162b5f478ac6d68feefab708', + block_height: 5536863, + caller_public_key: + '01aea816a1db5886755c6d0c29ce4f6c54c5364e97b13fee60e7c99e7cecbcf6a8', + caller_hash: + 'c42ee7c830b74701578b65429fe0112ffc88f5dd22c90b069b126f31675226bc', + execution_type_id: 4, + contract_package_hash: + '51f3812fde357ac73c6d89785155be59ddbcba97cf8f5b49362ebdbbd90290d2', + contract_hash: 'associated_keys_contract_hash', + entry_point_id: 435148, + args: { + deployment_threshold: { + cl_type: 'U8', + parsed: 1, + }, + key_management_threshold: { + cl_type: 'U8', + parsed: 1, + }, + keys: { + cl_type: { + List: 'Key', + }, + parsed: [ + 'account-hash-c42ee7c830b74701578b65429fe0112ffc88f5dd22c90b069b126f31675226bc', + 'account-hash-39dd3c32f12b2564054bcf9da7dba289af7a53c5c511c26d0b2efbb97e6aba03', + ], + }, + weights: { + cl_type: { + List: 'U8', + }, + parsed: [1, 1], + }, + }, + payment_amount: '50000000000', + refund_amount: '36775062059', + cost: '50000000000', + consumed_gas: '966583921', + error_message: null, + status: 'processed', + timestamp: '2025-09-24T18:03:26Z', + rate: 0.00939168, + account_info: { + account_hash: + 'c42ee7c830b74701578b65429fe0112ffc88f5dd22c90b069b126f31675226bc', + created: '2025-01-19T20:56:39Z', + deploy_hash: + '7ddb7de133d8f3a78c9b39251309c4515e0a0ae058aed5435e74d54bcce7d8b1', + info: { + nodes: [ + { + description: + 'This validator is running on a bare metal machine with top hardware specifications', + functionality: ['validator'], + location: { + country: 'TR', + latitude: '', + longitude: '', + name: 'TÜRKİYE', + }, + public_key: + '01aea816a1db5886755c6d0c29ce4f6c54c5364e97b13fee60e7c99e7cecbcf6a8', + }, + ], + owner: { + affiliated_accounts: [ + { + public_key: + '01aea816a1db5886755c6d0c29ce4f6c54c5364e97b13fee60e7c99e7cecbcf6a8', + }, + ], + branding: { + logo: { + png_1024: '', + png_256: + 'https://raw.githubusercontent.com/omercanga/bluestake/main/assets/bluestake_logo.png', + svg: '', + }, + }, + description: + 'BlueStake is a great validator running on a bare metal machine with top hardware specifications', + email: 'hello@bluestake.site', + identity: { + casper_association_kyc_onchain: '', + casper_association_kyc_url: '', + ownership_disclosure_url: '', + }, + location: { + country: 'TR', + latitude: '', + longitude: '', + name: 'TÜRKİYE', + }, + name: 'BlueStake', + resources: { + code_of_conduct_url: '', + other: [ + { + name: 'About Us', + url: 'https://www.bluestake.site/about', + }, + ], + privacy_policy_url: 'https://www.bluestake.site/privacy', + terms_of_service_url: 'https://www.bluestake.site/tos', + }, + social: { + facebook: '', + github: '', + keybase: '', + medium: '', + reddit: '', + telegram: '', + twitter: '', + wechat: '', + youtube: '', + }, + type: ['validator'], + website: 'https://www.bluestake.site', + }, + }, + is_active: true, + updated: '2025-11-25T00:00:49Z', + url: 'https://www.bluestake.site', + verified_account_hashes: [ + '39DD3C32F12B2564054BCF9DA7DBA289AF7A53C5C511C26D0B2EFBB97E6ABA03', + 'C42EE7C830B74701578B65429FE0112FFC88F5DD22C90B069B126F31675226BC', + ], + }, + centralized_account_info: null, + contract_package: { + contract_package_hash: + '51f3812fde357ac73c6d89785155be59ddbcba97cf8f5b49362ebdbbd90290d2', + owner_public_key: + '02033d8502125c698fdea5edd240bb366166216141c3526bc23e765d1331b216b7e8', + owner_hash: null, + name: 'Associated Key Manager', + description: + 'Smart contract that updates associated key settings for an account', + metadata: {}, + latest_version_contract_type_id: null, + timestamp: '2024-02-07T12:02:03Z', + icon_url: + 'https://casper-assets.s3.amazonaws.com/contracts/associated-key-manager.png', + website_url: 'https://makegroup.io', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + contract: { + block_height: 2437279, + contract_hash: + 'b2ec4f982efa8643c979cb3ab42ad1a18851c2e6f91804cd3e65c079679bdc59', + contract_package_hash: + '51f3812fde357ac73c6d89785155be59ddbcba97cf8f5b49362ebdbbd90290d2', + contract_type_id: null, + contract_version: 1, + deploy_hash: + '735194de714d1ae98be4d028530c8329fb90fcb40f9c19230698fcea2ba40cc2', + is_disabled: false, + major_protocol_version: 1, + timestamp: '2024-02-07T12:02:03Z', + }, + contract_entrypoint: { + action_type_id: null, + contract_hash: + 'b2ec4f982efa8643c979cb3ab42ad1a18851c2e6f91804cd3e65c079679bdc59', + contract_package_hash: + '51f3812fde357ac73c6d89785155be59ddbcba97cf8f5b49362ebdbbd90290d2', + id: 435148, + name: 'set_associated_keys', + }, + caller_cspr_name: null, + transfers: null, + nft_token_actions: null, + ft_token_actions: null, +}; + +export const csprMarketDeploy = { + deploy_hash: + 'bc6f637c9300c0f184252811f1d5570b745a1a0641cc49b73b6b64f2a6a1f8aa', + block_hash: + '5692cebd4f59d73f4b0ce41bff2cc69e7442bf513c87b840f44a24a5f2ee5889', + block_height: 5862179, + caller_public_key: + '02033bfaba171bee08f9cd29aeed85ceaf3b11a590f682da437e43303a0ada77ea0d', + caller_hash: + '81aed480140ac4e7c615f219c70b7a2d72e97c0dff23f52c994d70be9d043d3a', + execution_type_id: 4, + contract_package_hash: 'cspr_market_contract_package_hash', + contract_hash: + '5adb720d529964437caf75f3df974edffd204fe511b9e359e7dff28f79d12337', + entry_point_id: 7542, + args: { + collection: { + cl_type: 'Key', + parsed: + 'hash-da405d7d7a85732cc17f944f7afcacd37590ce0b8666400c51df8823e820269f', + }, + lookup_mode: { + cl_type: 'U8', + parsed: 0, + }, + offerer: { + cl_type: 'Key', + parsed: + 'account-hash-fe115dcc6d78f929a5cd2fc4ffd94ffc7d5a2f542e0dcc4df39a59e4948e8299', + }, + token_id: { + cl_type: 'String', + parsed: '8', + }, + }, + payment_amount: '20000000000', + refund_amount: '1580287485', + cost: '20000000000', + consumed_gas: '17892950019', + error_message: null, + status: 'processed', + timestamp: '2025-11-25T12:10:49Z', + rate: 0.00601674, + account_info: null, + centralized_account_info: null, + contract_package: { + contract_package_hash: + '31cc023b17c903a963ec60eab96a60f1fa37cb74b4b3bafc91a441e0e9d70f97', + owner_public_key: + '02033d8502125c698fdea5edd240bb366166216141c3526bc23e765d1331b216b7e8', + owner_hash: null, + name: 'CSPR.market v1', + description: + 'CSPR.market smart contract that manages the marketplace order book and transactions', + metadata: {}, + latest_version_contract_type_id: null, + timestamp: '2023-07-19T23:44:21Z', + icon_url: 'https://casper-assets.s3.amazonaws.com/contracts/csprmarket.png', + website_url: 'https://cspr.market', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + contract: { + block_height: 1908000, + contract_hash: + '5adb720d529964437caf75f3df974edffd204fe511b9e359e7dff28f79d12337', + contract_package_hash: + '31cc023b17c903a963ec60eab96a60f1fa37cb74b4b3bafc91a441e0e9d70f97', + contract_type_id: 9, + contract_version: 1, + deploy_hash: + 'fe216be605de5f9b2e1a21a463a712cb73ed3cbd33fa0eea13f68d364fe344e6', + is_disabled: false, + major_protocol_version: 1, + timestamp: '2023-07-19T23:44:21Z', + }, + contract_entrypoint: { + action_type_id: null, + contract_hash: + '5adb720d529964437caf75f3df974edffd204fe511b9e359e7dff28f79d12337', + contract_package_hash: + '31cc023b17c903a963ec60eab96a60f1fa37cb74b4b3bafc91a441e0e9d70f97', + id: 7542, + name: 'accept_offer', + }, + caller_cspr_name: null, + transfers: [ + { + id: 0, + transfer_index: null, + initiator_account_hash: + '81aed480140ac4e7c615f219c70b7a2d72e97c0dff23f52c994d70be9d043d3a', + from_purse: + 'uref-247ab08e2f3ca8c8819bfaeba9ecebf2cff157158ea3f7335e67682a203b9218-007', + to_purse: + 'uref-d747cf8e6feddc80d193f2c54ba367fec01706d983d3bee6453557fd1359adfc-004', + to_account_hash: + '81aed480140ac4e7c615f219c70b7a2d72e97c0dff23f52c994d70be9d043d3a', + amount: '68250000000', + from_purse_public_key: null, + to_purse_public_key: + '02033bfaba171bee08f9cd29aeed85ceaf3b11a590f682da437e43303a0ada77ea0d', + from_purse_account_info: null, + to_purse_account_info: null, + from_purse_centralized_account_info: null, + to_purse_centralized_account_info: null, + from_purse_cspr_name: null, + to_purse_cspr_name: null, + }, + { + id: 0, + transfer_index: null, + initiator_account_hash: + '81aed480140ac4e7c615f219c70b7a2d72e97c0dff23f52c994d70be9d043d3a', + from_purse: + 'uref-247ab08e2f3ca8c8819bfaeba9ecebf2cff157158ea3f7335e67682a203b9218-007', + to_purse: + 'uref-9d415deda06c102bf6383582e806afbcceb4a878b3e3ac985041f0bb70291ef9-004', + to_account_hash: + '7e16d73bb3d7c791089c4ff1242875dc8b06194c2d18155532d22d3946354a3c', + amount: '1750000000', + from_purse_public_key: null, + to_purse_public_key: null, + from_purse_account_info: null, + to_purse_account_info: null, + from_purse_centralized_account_info: null, + to_purse_centralized_account_info: null, + from_purse_cspr_name: null, + to_purse_cspr_name: null, + }, + ], + nft_token_actions: [ + { + contract_package_hash: + 'da405d7d7a85732cc17f944f7afcacd37590ce0b8666400c51df8823e820269f', + token_id: '8', + from_type: 0, + from_hash: + '81aed480140ac4e7c615f219c70b7a2d72e97c0dff23f52c994d70be9d043d3a', + to_type: 0, + to_hash: + 'fe115dcc6d78f929a5cd2fc4ffd94ffc7d5a2f542e0dcc4df39a59e4948e8299', + nft_action_id: 4, + token_tracking_id: 27517, + rate: null, + from_public_key: + '02033bfaba171bee08f9cd29aeed85ceaf3b11a590f682da437e43303a0ada77ea0d', + to_public_key: + '0202f1ba488be1aeec9d6f597bcc88dda5a93181f87f3f7c1d271cebc8e5dd625684', + from_account_info: null, + caller_account_info: null, + to_account_info: null, + from_centralized_account_info: null, + caller_centralized_account_info: null, + to_centralized_account_info: null, + contract_package: { + contract_package_hash: + 'da405d7d7a85732cc17f944f7afcacd37590ce0b8666400c51df8823e820269f', + owner_public_key: + '02033bfaba171bee08f9cd29aeed85ceaf3b11a590f682da437e43303a0ada77ea0d', + owner_hash: null, + name: 'Casper Toys от S_E_R_G_I_O_589', + description: 'Casper Toys by S_E_R_G_I_O_589', + metadata: { + burn_mode: 0, + events_mode: 2, + holder_mode: 2, + identifier_mode: 0, + metadata_mutability: 0, + minting_mode: 0, + name: 'Casper Toys от S_E_R_G_I_O_589', + nft_kind: 1, + nft_metadata_kind: 2, + ownership_mode: 2, + symbol: 'CTS', + total_supply_uref: + 'uref-8d2bb078123b5d379c6f8a7650f63ddb846557854ea28ee8fc3922cc359979ba-007', + whitelist_mode: 0, + }, + latest_version_contract_type_id: 7, + timestamp: '2023-08-20T10:37:53Z', + icon_url: + 'https://maritime.sealstorage.io/make/c4e5a03066ce3c60/c7b6bfa84b1b4e62ae7671eca0961cb6', + website_url: null, + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + deploy: null, + from_cspr_name: null, + to_cspr_name: 'banana.cspr', + }, + ], + ft_token_actions: null, +}; + +export const cep18Deploy = { + deploy_hash: + '43a3dc81a388eaec80b0444bd45bf3aba15edf1543c82fa7e553600172e82748', + block_hash: + 'd7dbf9dd4e397ca9ba4339bbc5819558220bd770449b5d127f47d2d704e3e31b', + block_height: 4320695, + caller_public_key: + '01284cecb3b4d6a3e75701a007f24578d4a5b592fb6a6724c47d3f9ae26803cb34', + caller_hash: + '2f3125376ec98abc30f57179d63ee0370339d9ad3401c5a1ae64c19d0ba2092a', + execution_type_id: 2, + contract_package_hash: + 'b42a439eb81cc5bf250e30785eaa59c7285a919663a98a21217df0fd7dcb19a3', + contract_hash: + '40bd4a45c414df61be3832e28ff6dcedc479744707c611fd97fea0d90619146f', + entry_point_id: 877, + args: { + amount: { + cl_type: 'U256', + parsed: '825000000000', + }, + recipient: { + cl_type: 'Key', + parsed: { + Account: + 'account-hash-ba86b6ac0797768b5603ee6d6d68545ab9bc5c67df8e0ff47b7d66804d80643e', + }, + }, + }, + payment_amount: '800000000', + refund_amount: '45491599', + cost: '754048889', + consumed_gas: '754048889', + error_message: null, + status: 'processed', + timestamp: '2025-02-05T14:31:42Z', + rate: 0.0124258, + account_info: null, + centralized_account_info: null, + contract_package: { + contract_package_hash: + 'b42a439eb81cc5bf250e30785eaa59c7285a919663a98a21217df0fd7dcb19a3', + owner_public_key: + '01f61490e53606fbec3bcd9124213eac25186faafa150af9f6b9efc45358f844d1', + owner_hash: null, + name: 'Wrapped Casper (Friendly Market)', + description: + 'Wrapped CSPR is a fungible, tradable version of CSPR used across Friendly Market’s DeFi ecosystem.', + metadata: { + balances_uref: + 'uref-014516655d42f506655255b00adccc5651e1de270f2dfd0206aae2b79b0c10ee-007', + decimals: 9, + name: 'Wrapped Casper', + symbol: 'WCSPR', + total_supply_uref: + 'uref-a0987e3fa8df4d1240f5c7092413af89ac6e6c15825010fb9742152e82325ceb-007', + }, + latest_version_contract_type_id: 2, + timestamp: '2022-05-29T18:26:33Z', + icon_url: + 'https://casper-assets.s3.amazonaws.com/contracts/friendly-wcspr.png', + website_url: 'https://www.friendly.market', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + contract: { + block_height: 819684, + contract_hash: + '40bd4a45c414df61be3832e28ff6dcedc479744707c611fd97fea0d90619146f', + contract_package_hash: + 'b42a439eb81cc5bf250e30785eaa59c7285a919663a98a21217df0fd7dcb19a3', + contract_type_id: 2, + contract_version: 1, + deploy_hash: + 'a27070ac8580a2b21727c007c97db7312e8b73a200dfd7afeb82a84d629ea039', + is_disabled: false, + major_protocol_version: 1, + timestamp: '2022-05-29T18:26:33Z', + }, + contract_entrypoint: { + action_type_id: null, + contract_hash: + '40bd4a45c414df61be3832e28ff6dcedc479744707c611fd97fea0d90619146f', + contract_package_hash: + 'b42a439eb81cc5bf250e30785eaa59c7285a919663a98a21217df0fd7dcb19a3', + id: 877, + name: 'transfer', + }, + caller_cspr_name: null, + transfers: null, + nft_token_actions: null, + ft_token_actions: [ + { + block_height: 4320695, + contract_package_hash: + 'b42a439eb81cc5bf250e30785eaa59c7285a919663a98a21217df0fd7dcb19a3', + transform_idx: 20, + from_type: 0, + from_hash: + '2f3125376ec98abc30f57179d63ee0370339d9ad3401c5a1ae64c19d0ba2092a', + to_type: 0, + to_hash: + 'ba86b6ac0797768b5603ee6d6d68545ab9bc5c67df8e0ff47b7d66804d80643e', + ft_action_type_id: 2, + amount: '825000000000', + timestamp: null, + rate: null, + from_public_key: + '01284cecb3b4d6a3e75701a007f24578d4a5b592fb6a6724c47d3f9ae26803cb34', + to_public_key: + '020374057352dfa78c21b9258942c15353e208f4865f0f5bfc1b6bf16db431c9fe5a', + from_account_info: null, + to_account_info: null, + caller_account_info: null, + from_centralized_account_info: null, + to_centralized_account_info: null, + caller_centralized_account_info: null, + contract_package: { + contract_package_hash: + 'b42a439eb81cc5bf250e30785eaa59c7285a919663a98a21217df0fd7dcb19a3', + owner_public_key: + '01f61490e53606fbec3bcd9124213eac25186faafa150af9f6b9efc45358f844d1', + owner_hash: null, + name: 'Wrapped Casper (Friendly Market)', + description: + 'Wrapped CSPR is a fungible, tradable version of CSPR used across Friendly Market’s DeFi ecosystem.', + metadata: { + balances_uref: + 'uref-014516655d42f506655255b00adccc5651e1de270f2dfd0206aae2b79b0c10ee-007', + decimals: 9, + name: 'Wrapped Casper', + symbol: 'WCSPR', + total_supply_uref: + 'uref-a0987e3fa8df4d1240f5c7092413af89ac6e6c15825010fb9742152e82325ceb-007', + }, + latest_version_contract_type_id: 2, + timestamp: '2022-05-29T18:26:33Z', + icon_url: + 'https://casper-assets.s3.amazonaws.com/contracts/friendly-wcspr.png', + website_url: 'https://www.friendly.market', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + deploy: null, + from_cspr_name: null, + to_cspr_name: null, + }, + ], +}; + +export const nftDeploy = { + deploy_hash: + 'b186b71a44600f5f104ce3508f01e382cc20c76bc1cfc513e763bbbad290011a', + block_hash: + 'db5c98541609e9fa8a4ac1ca827dbf985e1e254c7ae8ac0f46219fcf2008b53b', + block_height: 5705920, + caller_public_key: + '02032b2315a03717ebb201fce631cd20d43c713f6c14d5041d6a9196ac320a3f535c', + caller_hash: + 'fc2f444016de6599374e64bd9d80b8df7e00eee3123e1bb993de0b588b0ee1a1', + execution_type_id: 2, + contract_package_hash: + 'c4e5a03066ce3c6006f562939e48f7076c77de5d46cf8fe625c41e02c5e74814', + contract_hash: + '2e64dbd1aea72e5b7ad3fa6cc64087150962fb13e5acdf2f886540b543ef0727', + entry_point_id: 3708, + args: { + spender: { + cl_type: 'Key', + parsed: + 'hash-31cc023b17c903a963ec60eab96a60f1fa37cb74b4b3bafc91a441e0e9d70f97', + }, + token_ids: { + cl_type: { + List: 'U256', + }, + parsed: ['1174'], + }, + }, + payment_amount: '2500000000', + refund_amount: '1415423684', + cost: '2500000000', + consumed_gas: '612768421', + error_message: null, + status: 'processed', + timestamp: '2025-10-26T20:42:46Z', + rate: 0.00822102, + account_info: null, + centralized_account_info: null, + contract_package: { + contract_package_hash: + 'c4e5a03066ce3c6006f562939e48f7076c77de5d46cf8fe625c41e02c5e74814', + owner_public_key: + '02033d8502125c698fdea5edd240bb366166216141c3526bc23e765d1331b216b7e8', + owner_hash: null, + name: 'CSPR.studio', + description: null, + metadata: { + name: 'NFT Studio', + symbol: 'NFTS', + }, + latest_version_contract_type_id: 4, + timestamp: '2022-10-26T07:24:11Z', + icon_url: 'https://casper-assets.s3.amazonaws.com/contracts/csprstudio.svg', + website_url: 'https://cspr.studio', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + contract: { + block_height: 1211836, + contract_hash: + '2e64dbd1aea72e5b7ad3fa6cc64087150962fb13e5acdf2f886540b543ef0727', + contract_package_hash: + 'c4e5a03066ce3c6006f562939e48f7076c77de5d46cf8fe625c41e02c5e74814', + contract_type_id: 4, + contract_version: 1, + deploy_hash: + '5245b39e1d4f3b340bf62029012610052afd8d509696f9ff333eda4e06ee0031', + is_disabled: false, + major_protocol_version: 1, + timestamp: '2022-10-26T07:24:11Z', + }, + contract_entrypoint: { + action_type_id: null, + contract_hash: + '2e64dbd1aea72e5b7ad3fa6cc64087150962fb13e5acdf2f886540b543ef0727', + contract_package_hash: + 'c4e5a03066ce3c6006f562939e48f7076c77de5d46cf8fe625c41e02c5e74814', + id: 3708, + name: 'approve', + }, + caller_cspr_name: null, + transfers: null, + nft_token_actions: [ + { + contract_package_hash: + 'c4e5a03066ce3c6006f562939e48f7076c77de5d46cf8fe625c41e02c5e74814', + token_id: '1174', + from_type: 0, + from_hash: + 'fc2f444016de6599374e64bd9d80b8df7e00eee3123e1bb993de0b588b0ee1a1', + to_type: 1, + to_hash: + '31cc023b17c903a963ec60eab96a60f1fa37cb74b4b3bafc91a441e0e9d70f97', + nft_action_id: 3, + token_tracking_id: 1126899, + rate: null, + from_public_key: + '02032b2315a03717ebb201fce631cd20d43c713f6c14d5041d6a9196ac320a3f535c', + to_public_key: null, + from_account_info: null, + caller_account_info: null, + to_account_info: null, + from_centralized_account_info: null, + caller_centralized_account_info: null, + to_centralized_account_info: null, + contract_package: { + contract_package_hash: + 'c4e5a03066ce3c6006f562939e48f7076c77de5d46cf8fe625c41e02c5e74814', + owner_public_key: + '02033d8502125c698fdea5edd240bb366166216141c3526bc23e765d1331b216b7e8', + owner_hash: null, + name: 'CSPR.studio', + description: null, + metadata: { + name: 'NFT Studio', + symbol: 'NFTS', + }, + latest_version_contract_type_id: 4, + timestamp: '2022-10-26T07:24:11Z', + icon_url: + 'https://casper-assets.s3.amazonaws.com/contracts/csprstudio.svg', + website_url: 'https://cspr.studio', + coingecko_id: null, + latest_version_contract_hash: null, + account_info: null, + centralized_account_info: null, + coingecko_data: null, + friendlymarket_data: null, + }, + deploy: null, + from_cspr_name: null, + to_cspr_name: null, + }, + ], + ft_token_actions: null, +}; diff --git a/src/lib/components/deploy-actions/utils/contract.tsx b/src/lib/components/deploy-actions/utils/contract.tsx new file mode 100644 index 00000000..65c1090d --- /dev/null +++ b/src/lib/components/deploy-actions/utils/contract.tsx @@ -0,0 +1,67 @@ +// import { +// DeployEntryPointName, +// DeployResultWithInfo, +// } from '@block-explorer/entities'; +export const WASM_DEPLOY = 1; +export const WASM_PROXY_DEPLOY = 7; + +export const ExecutionTypesMap = { + 1: 'WASM', //"ModuleBytes" + 2: 'Contract call', //"StoredContractByHash" + 3: 'Contract call', //"StoredContractByName", + 4: 'Contract call', //"StoredVersionedContractByHash", + 5: 'Contract call', //"StoredVersionedContractByName", + 6: 'Native', + 7: 'WASM', +}; + +export enum DeployEntryPointName { + TRANSFER = 'transfer', +} + +/** + * Check if the Deploy is a transfer deploy by comparing native trasfer contract hash and entrypoint name, return TRUE + * @param contractHash + * @param entryPointName + */ +export const isTransferDeploy = ( + contractHash: string | null, + entryPointName: string | null | undefined, + native_transfer_contract_hash: string, +) => { + return ( + contractHash === native_transfer_contract_hash && + entryPointName === DeployEntryPointName.TRANSFER + ); +}; + +/** + * Check if the Deploy is a WASM deploy, return TRUE + * @param executionTypeId + */ +export const isWASMTransaction = (executionTypeId: number) => { + return executionTypeId === WASM_DEPLOY; +}; + +/** + * Check if the Deploy is a WASM deploy, return TRUE + * @param executionTypeId + */ +export const isWASMProxyTransaction = (executionTypeId: number) => { + return executionTypeId === WASM_PROXY_DEPLOY; +}; + +/** + * Check if the Transaction is an ODRA WASM Proxy, return TRUE + * @param transaction + */ +export const isODRAWasmProxyTransaction = ( + transaction, + // : DeployResultWithInfo +): boolean => { + return Boolean( + isWASMProxyTransaction(transaction.executionTypeId) && + transaction.args?.amount && + transaction.args?.attached_value, + ); +}; diff --git a/src/lib/components/deploy-actions/utils/deploy-action-helpers.ts b/src/lib/components/deploy-actions/utils/deploy-action-helpers.ts new file mode 100644 index 00000000..7497ba1c --- /dev/null +++ b/src/lib/components/deploy-actions/utils/deploy-action-helpers.ts @@ -0,0 +1,130 @@ +import { + Args, + CLValueParser, + Conversions, + ExecutionResult, + Transform, +} from 'casper-js-sdk'; +import { getExecutionResultsFromDeployRawData } from './use-get-execution-results'; +import { Deploy, DeployResult, GetDeployResult } from '../../../types/types'; +import { convertTransactionArgsToObj } from '../../../utils/cltype'; + +export const deriveUpdatedAssociatedKey = ( + deployRawData: GetDeployResult | undefined, +): string | undefined => { + const executionResult: ExecutionResult | null = + getExecutionResultsFromDeployRawData(deployRawData); + + const transforms = executionResult?.effects ?? []; + + const writeAccountDeployInfo = transforms.filter((obj: Transform) => + obj.kind.isWriteAccount(), + ); + + const writeAccountTransform = + writeAccountDeployInfo?.length > 0 ? writeAccountDeployInfo[0] : null; + + return writeAccountTransform?.kind?.parseAsWriteAccount().toPrefixedString(); +}; +// +// export const hasDeployCustomAction = (deploy: Deploy): boolean => { +// if (!deploy || !deploy.contractPackage) return false; +// +// const { entryPoint, contractPackage, contractHash, contractPackageHash } = +// deploy; +// +// //addx hash +// const isTransfer = +// isTransferDeploy(contractHash, entryPoint?.name) && +// !!deploy.transfers?.length; +// +// const isCustomContractAction = +// contractHash === config.auction_manager_contract_hash || +// contractHash === config.associated_keys_contract_hash || +// contractPackageHash === config.cspr_market_contract_package_hash; +// +// const contractTypeId = +// contractPackage.latest_version_contract_type_id || +// contractPackage.contract_type_id; +// +// const isCep18 = +// contractTypeId === ContractTypeId.CustomCep18 || +// contractTypeId === ContractTypeId.Cep18; +// +// const isNFT = +// contractTypeId === ContractTypeId.CEP78Nft || +// contractTypeId === ContractTypeId.CEP47Nft || +// contractTypeId === ContractTypeId.CustomCEP78Nft || +// contractTypeId === ContractTypeId.CustomCEP47Nft; +// +// return isTransfer || isCustomContractAction || isCep18 || isNFT; +// }; + +export function getWasmProxyArguments(args) { + const clValue = CLValueParser.toJSON(args); + + return convertTransactionArgsToObj( + Args.fromBytes(Conversions.decodeBase16(clValue.bytes.substring(8))), + ); +} + +export function getWasmProxyArgumentsFromRawData(argumentsFromRawData) { + const wasmArgs = argumentsFromRawData.args.args.get('args'); + + if (!wasmArgs) return null; + + try { + return getWasmProxyArguments(wasmArgs); + } catch (e) { + console.error('getWasmProxyArgumentsFromRawData', e); + return null; + } +} + +export const MapDeploy = ({ + deploy_hash, + block_hash, + caller_public_key, + contract_hash, + contract_package_hash, + error_message, + payment_amount, + contract_entrypoint, + contract_package, + execution_type_id, + nft_token_actions, + ft_token_actions, + account_info, + centralized_account_info, + rate, + caller_cspr_name, + caller_hash, + consumed_gas, + refund_amount, + block_height, + ...rest +}: DeployResult): Deploy => { + return { + ...rest, + accountInfo: account_info, + blockHash: block_hash, + blockHeight: block_height, + callerCsprName: caller_cspr_name, + callerHash: caller_hash, + callerPublicKey: caller_public_key, + centralizedAccountInfo: centralized_account_info, + consumedGas: consumed_gas, + contractHash: contract_hash, + contractPackage: contract_package, + contractPackageHash: contract_package_hash, + deployHash: deploy_hash, + entryPoint: contract_entrypoint, + errorMessage: error_message, + executionTypeId: execution_type_id, + ftActions: ft_token_actions, + nftActions: nft_token_actions, + paymentAmount: payment_amount, + refundAmount: refund_amount, + timeTransactionCurrencyRate: rate, + }; +}; diff --git a/src/lib/components/deploy-actions/utils/prepare-action-messages.ts b/src/lib/components/deploy-actions/utils/prepare-action-messages.ts new file mode 100644 index 00000000..cbda7e82 --- /dev/null +++ b/src/lib/components/deploy-actions/utils/prepare-action-messages.ts @@ -0,0 +1,297 @@ +import { Deploy, TransactorHashType } from '../../../types/types'; +import { FTEntryPointType } from '../../../types/FTToken'; +import { + getNftTokenIdsFromArguments, + guardedDeriveSplitDataFromArguments, +} from '../../../utils/deploy-args'; +import { NftTokenEntryPoint } from '../../../types/NFTToken'; + +export interface MessageDataAccount { + accountHash?: string; + publicKey?: string; + hash?: string; + logo?: string; + path?: string; + hashType?: TransactorHashType; +} + +export interface MessageData { + entryPointName?: string | null; + actionName?: string; + numOfTokens?: number; + numOfTokensPrefix?: string | null; + symbol?: string; + callerPrefix?: string; + callerAccount?: MessageDataAccount; + prefix1?: string; + account1?: MessageDataAccount; + prefix2?: string; + account2?: MessageDataAccount; + nftTokenIds?: string[] | null; + contractPrefix?: string; + amount?: string; +} + +const getCep18TransactorsDataFromArgs = (args) => { + const recipientHash = guardedDeriveSplitDataFromArguments( + args.recipient, + 'Hash', + ); + const recipientAccountHash = guardedDeriveSplitDataFromArguments( + args.recipient, + 'Account', + ); + const ownerHash = guardedDeriveSplitDataFromArguments(args.owner, 'Account'); + const spenderHash = guardedDeriveSplitDataFromArguments(args.spender, 'Hash'); + + return { + recipientHash, + recipientAccountHash, + ownerHash, + spenderHash, + }; +}; + +export const prepareFtActionMessageDataForDeployDetails = ( + deploy: Deploy, + getPublicKeyByAccountHash: (hash: string) => any, +): MessageData | null => { + const { entryPoint, args, contractPackage } = deploy; + const entryPointName = entryPoint?.name || ''; + const amount = deploy.args.amount?.parsed as string; + + const actionName = { + [FTEntryPointType.transfer]: 'Transfer', + [FTEntryPointType.approve]: 'Approve transfer rights', + [FTEntryPointType.burn]: 'Burn', + [FTEntryPointType.mint]: 'Mint', + }; + + const contractPrefixesMap = { + [FTEntryPointType.transfer]: 'of', + [FTEntryPointType.burn]: 'of', + [FTEntryPointType.mint]: 'of', + [FTEntryPointType.approve]: 'for', + }; + + const senderPrefixesMap = { + [FTEntryPointType.transfer]: 'from', + [FTEntryPointType.burn]: 'owned by', + [FTEntryPointType.mint]: 'to', + [FTEntryPointType.approve]: 'to', + }; + + const { recipientHash, recipientAccountHash, ownerHash, spenderHash } = + getCep18TransactorsDataFromArgs(args); + + if ( + actionName[entryPointName] === undefined || + !amount || + !(recipientHash || recipientAccountHash || ownerHash || spenderHash) + ) { + return null; + } + + const tokenSymbol = contractPackage.metadata?.symbol; + const senderPrefix = senderPrefixesMap[entryPointName]; + const contractPrefix = contractPrefixesMap[entryPointName]; + + const actionOutcome: Partial = { + amount, + ...(tokenSymbol && { symbol: tokenSymbol }), + ...(contractPrefix && { contractPrefix }), + ...(ownerHash?.hash && { + prefix1: senderPrefix, + account1: { + hash: ownerHash?.hash, + publicKey: ownerHash?.hash && getPublicKeyByAccountHash(ownerHash.hash), + hashType: TransactorHashType.account, + }, + }), + ...(spenderHash?.hash && { + prefix1: senderPrefix, + account1: { + hash: spenderHash?.hash, + hashType: TransactorHashType.hash, + }, + }), + // here could be a case when recipientAccountHash and recipientHash are both present + // so, we need to avoid overwriting recipientAccountHash with recipientHash + ...(recipientAccountHash?.hash + ? { + prefix2: 'to', + account2: { + hash: recipientAccountHash?.hash, + publicKey: + recipientAccountHash?.hash && + getPublicKeyByAccountHash(recipientAccountHash.hash), + hashType: TransactorHashType.account, + }, + } + : { + prefix2: 'to', + account2: { + hash: recipientHash?.hash, + hashType: TransactorHashType.hash, + }, + }), + }; + + return { + entryPointName: entryPointName, + actionName: actionName[entryPointName] || entryPointName, + ...actionOutcome, + }; +}; + +const getNftTransactorsDataFromArgs = (args) => { + const tokenOwner = guardedDeriveSplitDataFromArguments( + args.token_owner, + 'Account', + ); + const owner = guardedDeriveSplitDataFromArguments(args.owner, 'Account'); + const from = guardedDeriveSplitDataFromArguments(args.from, 'Account'); + + const sourceKey = guardedDeriveSplitDataFromArguments( + args.source_key, + 'Account', + ); + + const targetKey = guardedDeriveSplitDataFromArguments( + args.target_key, + 'Account', + ); + const recipientHash = guardedDeriveSplitDataFromArguments( + args.recipient, + 'Account', + ); + + const accountSpenderHash = guardedDeriveSplitDataFromArguments( + args.spender, + 'Account', + ); + + const contractSpenderHash = guardedDeriveSplitDataFromArguments( + args.spender, + 'Hash', + ); + const operatorHash = guardedDeriveSplitDataFromArguments( + args.operator, + 'Hash', + ); + const to = guardedDeriveSplitDataFromArguments(args.to, 'Account'); + + return { + tokenOwner, + owner, + sourceKey, + targetKey, + recipientHash, + contractSpenderHash, + operatorHash, + accountSpenderHash, + from, + to, + }; +}; + +export const prepareNftActionMessageDataForDeployDetails = ( + deploy: Deploy, + getPublicKeyByAccountHash: (hash: string) => any, +): MessageData | null => { + const { entryPoint, args } = deploy; + const entryPointName = entryPoint?.name || ''; + + const actionName = { + [NftTokenEntryPoint.transfer]: 'Transfer', + [NftTokenEntryPoint.transfer_from]: 'Transfer', + [NftTokenEntryPoint.approve]: 'Approve transfer rights', + [NftTokenEntryPoint.burn]: 'Burn', + [NftTokenEntryPoint.mint]: 'Mint', + [NftTokenEntryPoint.update_token_meta]: 'Update metadata', + [NftTokenEntryPoint.set_approval_for_all]: 'Approve transfer rights', + }; + + const contractPrefixesMap = { + [NftTokenEntryPoint.approve]: 'for', + [NftTokenEntryPoint.update_token_meta]: 'for', + [NftTokenEntryPoint.mint]: 'of', + [NftTokenEntryPoint.set_approval_for_all]: 'of', + }; + + const senderPrefixesMap = { + [NftTokenEntryPoint.transfer]: 'from', + [NftTokenEntryPoint.transfer_from]: 'from', + [NftTokenEntryPoint.burn]: 'owned by', + [NftTokenEntryPoint.approve]: 'to', + [NftTokenEntryPoint.mint]: 'to', + }; + + if (actionName[entryPointName] === undefined) { + return null; + } + + const nftTokenIds = getNftTokenIdsFromArguments(args); + const { + recipientHash, + tokenOwner, + contractSpenderHash, + operatorHash, + sourceKey, + owner, + targetKey, + accountSpenderHash, + from, + to, + } = getNftTransactorsDataFromArgs(args); + + const account1Hash = + tokenOwner?.hash || + sourceKey?.hash || + owner?.hash || + accountSpenderHash?.hash || + from?.hash; + const account2Hash = recipientHash?.hash || targetKey?.hash || to?.hash; + + const contractPrefix = contractPrefixesMap[entryPointName]; + const senderPrefix = senderPrefixesMap[entryPointName]; + + const actionOutcome: Partial = { + nftTokenIds: nftTokenIds, + contractPrefix, + ...(account1Hash && { + prefix1: senderPrefix, + account1: { + hash: account1Hash, + publicKey: account1Hash && getPublicKeyByAccountHash(account1Hash), + hashType: TransactorHashType.account, + }, + }), + ...(contractSpenderHash?.hash && { + prefix1: senderPrefix, + account1: { + hash: contractSpenderHash?.hash, + hashType: TransactorHashType.hash, + }, + }), + ...(account2Hash && { + account2: { + hash: account2Hash, + publicKey: account2Hash && getPublicKeyByAccountHash(account2Hash), + hashType: TransactorHashType.account, + }, + }), + ...(operatorHash?.hash && { + account2: { + hash: operatorHash?.hash, + hashType: TransactorHashType.hash, + }, + }), + }; + + return { + entryPointName: entryPointName, + actionName: actionName[entryPointName] || entryPointName, + ...actionOutcome, + }; +}; diff --git a/src/lib/components/deploy-actions/utils/use-get-execution-results.ts b/src/lib/components/deploy-actions/utils/use-get-execution-results.ts new file mode 100644 index 00000000..23223c07 --- /dev/null +++ b/src/lib/components/deploy-actions/utils/use-get-execution-results.ts @@ -0,0 +1,33 @@ +import { + ExecutionResult, + InfoGetDeployResultV1Compatible, + InfoGetTransactionResultV1Compatible, +} from 'casper-js-sdk'; +import { GetDeployResult, NetworkMajorVersion } from '../../../types/types'; + +export const getExecutionResultsFromDeployRawData = ( + deployRawData?: GetDeployResult, +): ExecutionResult | null => { + if (!deployRawData) return null; + const networkVersionFromRawData = + (deployRawData.api_version && deployRawData.api_version.startsWith('1') + ? NetworkMajorVersion.V1 + : NetworkMajorVersion.V2) || NetworkMajorVersion.V2; + + if (networkVersionFromRawData === '1') { + const transactionData = + InfoGetDeployResultV1Compatible.fromJSON(deployRawData); + + return transactionData?.executionResults && + transactionData?.executionResults[0] + ? ExecutionResult.fromV1(transactionData.executionResults?.[0].result) + : null; + } + + const transactionData = + InfoGetTransactionResultV1Compatible.fromJSON(deployRawData); + + return transactionData?.executionInfo + ? transactionData.executionInfo.executionResult + : null; +}; diff --git a/src/lib/components/deploy-status/deploy-status.tsx b/src/lib/components/deploy-status/deploy-status.tsx new file mode 100644 index 00000000..8bd815e7 --- /dev/null +++ b/src/lib/components/deploy-status/deploy-status.tsx @@ -0,0 +1,123 @@ +import React from 'react'; +import styled from 'styled-components'; +import { Deploy, DeployResult } from '../../types/types'; +import Tooltip from '../tooltip/tooltip'; +import SvgIcon from '../svg-icon/svg-icon'; +import FlexRow from '../flex-row/flex-row'; +import BodyText from '../body-text/body-text'; +import SuccessIcon from '../../assets/icons/ic-success.svg'; +import ClockIcon from '../../assets/icons/ic-clock.svg'; +import ErrorIcon from '../../assets/icons/ic-error.svg'; +import CrossIcon from '../../assets/icons/ic-cross.svg'; + +export enum DeployStatusSize { + Small = 14, + Medium = 16, +} + +export enum Status { + Success = 'success', + Processed = 'processed', + Error = 'error', + /** @deprecated Became 'Processed' */ + Executed = 'executed', + Pending = 'pending', + Expired = 'expired', +} + +const StatusIcons = { + [Status.Success]: SuccessIcon, + [Status.Pending]: ClockIcon, + [Status.Error]: ErrorIcon, + [Status.Expired]: CrossIcon, +}; + +const StatusColors = { + [Status.Success]: 'contentGreen', + [Status.Pending]: 'contentLightBlue', + [Status.Error]: 'contentRed', + [Status.Expired]: 'contentTertiary', +}; + +export interface DeployStatusProps { + deployResult: DeployResult | Deploy | null | undefined; + iconWithText?: boolean; + size?: 14 | 16; +} + +const SvgIconWrapper = styled.span<{ status: Status }>(({ theme, status }) => ({ + color: theme.styleguideColors[StatusColors[status]], + marginRight: 8, + display: 'flex', + alignItems: 'center', +})); + +export const getDeployStatus = ( + deployResult?: DeployResult | Deploy | null, +): Status => { + if ( + deployResult && + deployResult?.status && + deployResult?.status !== Status.Processed && + deployResult?.status !== Status.Executed + ) { + return deployResult?.status as Status; + } + + if (deployResult?.errorMessage) { + return Status.Error; + } + + return Status.Success; +}; + +export const DeployStatus = ({ + deployResult, + iconWithText, + size = DeployStatusSize.Medium, +}: DeployStatusProps) => { + const StatusLabel = { + [Status.Success]: 'Success', + [Status.Processed]: 'Processed', + [Status.Error]: 'Error', + [Status.Executed]: 'Executed', + [Status.Pending]: 'Pending', + [Status.Expired]: 'Expired', + }; + + const status = getDeployStatus(deployResult); + const message = deployResult?.errorMessage || StatusLabel[status]; + + if (!iconWithText) { + return ( + + + + + + ); + } + + return ( + + + + + {message} + + ); +}; diff --git a/src/lib/components/expand-collapsed/expand-collapsed-button.tsx b/src/lib/components/expand-collapsed/expand-collapsed-button.tsx new file mode 100644 index 00000000..61a760f1 --- /dev/null +++ b/src/lib/components/expand-collapsed/expand-collapsed-button.tsx @@ -0,0 +1,61 @@ +import styled from 'styled-components'; +import React, { useState } from 'react'; +import BodyText from '../body-text/body-text'; +import SvgIcon from '../svg-icon/svg-icon'; +import ArrowDownIcon from '../../assets/icons/ic-arrow-down.svg'; +import FlexRow from '../flex-row/flex-row'; + +const CollapsedRow = styled(FlexRow)(({ theme }) => ({ + marginTop: '8px', + '&:hover': { + span: { + color: theme.styleguideColors.contentRed, + }, + [`${SvgIcon}`]: { + path: { + fill: theme.styleguideColors.contentRed, + }, + }, + }, +})); + +interface ExpandCollapsedButtonProps { + expandedLabel: React.ReactNode; + collapsedLabel: React.ReactNode; + showArrow?: boolean; + onExpand?: (collapsed: boolean) => void; +} + +export const ExpandCollapsedButton = ({ + expandedLabel, + collapsedLabel, + showArrow = true, + onExpand, +}: ExpandCollapsedButtonProps) => { + const [isCollapsed, setCollapsed] = useState(true); + + return ( + { + setCollapsed(!isCollapsed); + onExpand && onExpand(!isCollapsed); + }} + > + + {isCollapsed ? collapsedLabel : expandedLabel} + {showArrow && ( + + )} + + + ); +}; + +ExpandCollapsedButton.displayName = 'ExpandCollapsedButton'; +export default ExpandCollapsedButton; diff --git a/src/lib/components/hash-link/hash-link.tsx b/src/lib/components/hash-link/hash-link.tsx index 47a11a06..b1547cde 100644 --- a/src/lib/components/hash-link/hash-link.tsx +++ b/src/lib/components/hash-link/hash-link.tsx @@ -38,7 +38,7 @@ export const HashLink = ({ return ( - + {truncatedCsprName || formattedHash} diff --git a/src/lib/components/named-key-value/named-key-value.tsx b/src/lib/components/named-key-value/named-key-value.tsx new file mode 100644 index 00000000..679dd439 --- /dev/null +++ b/src/lib/components/named-key-value/named-key-value.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import { formatHash, HashLength } from '../../utils/formatters'; +import { deriveSplitDataFromNamedKeyValue } from '../../utils/named-key'; +import { NamedKeyPrefix } from '../../utils/named-key-prefix'; +import { useMatchMedia } from '../../utils/match-media'; +import FlexRow from '../flex-row/flex-row'; +import Link from '../link/link'; + +interface NamedKeyValueProps { + namedKey: string; + noPrefix?: boolean; + hashLength?: HashLength; + csprLiveDomainPath: string; +} + +export const NamedKeyValue = ({ + namedKey, + noPrefix, + hashLength, + csprLiveDomainPath, +}: NamedKeyValueProps) => { + const responsiveHashLength = useMatchMedia( + [HashLength.TINY, HashLength.MEDIUM, HashLength.FULL, HashLength.FULL], + [], + ); + const { prefix, hash } = deriveSplitDataFromNamedKeyValue(namedKey); + + const isURefNamedKey = namedKey.includes(NamedKeyPrefix.UREF); + const redirectHash = isURefNamedKey ? namedKey : hash; + + const redirectPath = `${csprLiveDomainPath}/search/${redirectHash}`; + return ( + + {redirectPath ? ( + + {!noPrefix && prefix} + {formatHash(hash, hashLength || responsiveHashLength)} + + ) : ( + formatHash(hash, hashLength || responsiveHashLength) + )} + + ); +}; + +export default NamedKeyValue; diff --git a/src/lib/components/table-data-named-key/table-data-named-key.tsx b/src/lib/components/table-data-named-key/table-data-named-key.tsx new file mode 100644 index 00000000..86291f80 --- /dev/null +++ b/src/lib/components/table-data-named-key/table-data-named-key.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { HashLength } from '../../utils/formatters'; +import FlexRow from "../flex-row/flex-row"; +import Tooltip from "../tooltip/tooltip"; +import BodyText from "../body-text/body-text"; +import Copy from "../copy/copy"; +import NamedKeyValue from "../named-key-value/named-key-value"; + +interface TableDataNamedKeyProps { + purse: string; + fontSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'; + hashLength?: HashLength; + csprLiveDomainPath: string; +} + +export const TableDataNamedKey = ({ + purse, + fontSize = 'xs', + hashLength = HashLength.TINY, + csprLiveDomainPath +}: TableDataNamedKeyProps) => { + return ( + + + + + + + + + ); +}; diff --git a/src/lib/components/text-row/text-row.tsx b/src/lib/components/text-row/text-row.tsx index 83d9a335..f552c65d 100644 --- a/src/lib/components/text-row/text-row.tsx +++ b/src/lib/components/text-row/text-row.tsx @@ -2,7 +2,6 @@ import React, { ReactNode } from 'react'; import styled from 'styled-components'; import { BodyText } from '../body-text/body-text'; import { FlexRow } from '../flex-row/flex-row'; -import { SubtitleText } from '../subtitle-text/subtitle-text'; import { TruncateBox } from '../truncate-box/truncate-box'; import { formatHash } from '../../utils/formatters'; import { Tooltip } from '../tooltip/tooltip'; diff --git a/src/lib/components/token-amount/token-amount.tsx b/src/lib/components/token-amount/token-amount.tsx new file mode 100644 index 00000000..cbc1b803 --- /dev/null +++ b/src/lib/components/token-amount/token-amount.tsx @@ -0,0 +1,43 @@ +import React from 'react'; + +import Big from 'big.js'; +import { + formatTokenAmount, + getAmountFromMotes, +} from '../../utils/ft-token-amount'; +import {DEFAULT_PRECISION} from '../../utils/formatters'; + +export interface TokenAmountProps { + amount: string | null; + decimals?: number; + symbol?: string; + precision?: number; + shouldShortenAmount?: boolean; +} + +export function TokenAmount({ + amount, + decimals, + symbol = '', + precision = DEFAULT_PRECISION, + shouldShortenAmount = false, +}: TokenAmountProps) { + if (amount == null) { + return <>{'N/A'}; + } + + const calculatedAmount: string = decimals + ? getAmountFromMotes(amount, decimals) + : Big(amount.toString() || '0').toString(); + + const formattedAmount = formatTokenAmount( + calculatedAmount, + precision, + shouldShortenAmount + ); + const formattedText = formattedAmount + ` ${symbol}`; + + return <>{formattedText}; +} + +export default TokenAmount; diff --git a/src/lib/components/tooltip-with-extended-info/tooltip-with-extended-info.tsx b/src/lib/components/tooltip-with-extended-info/tooltip-with-extended-info.tsx new file mode 100644 index 00000000..497069c3 --- /dev/null +++ b/src/lib/components/tooltip-with-extended-info/tooltip-with-extended-info.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { isValidPublicKey } from 'casper-js-sdk'; +import FlexColumn from '../flex-column/flex-column'; +import CaptionText from '../caption-text/caption-text'; +import BodyText from '../body-text/body-text'; +import Tooltip from '../tooltip/tooltip'; + +const TooltipWithExtendedInfo = ({ + extendedLine, + hash, + tooltipCaption, + children, +}: React.PropsWithChildren<{ + hash: string; + tooltipCaption?: string; + extendedLine?: { + title: string | undefined; + caption: string; + }; +}>) => { + const hasExtendedLine = extendedLine?.title != undefined; + + const keyTooltipCaption = tooltipCaption + ? tooltipCaption + : isValidPublicKey(hash) + ? 'Public Key' + : 'Account hash'; + + const title = hasExtendedLine ? extendedLine?.title : hash; + const caption = hasExtendedLine ? extendedLine?.caption : keyTooltipCaption; + + const additionalBlock = hasExtendedLine && ( + + + {keyTooltipCaption} + + + {hash} + + + ); + + return ( + + {children} + + ); +}; + +export default TooltipWithExtendedInfo; diff --git a/src/lib/components/transactor-info/transactor-info.tsx b/src/lib/components/transactor-info/transactor-info.tsx new file mode 100644 index 00000000..8ef90037 --- /dev/null +++ b/src/lib/components/transactor-info/transactor-info.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import { deriveAccountInfo } from '../../utils/account'; +import { AvatarProps } from '../avatar/avatar'; +import { ContractIdentifier } from '../contract-identifier/contract-identifier'; +import { + AccountCentralizedInfo, + AccountInfoResult, + DeployContractPackageResult, + TransactorHashType, +} from '../../types/types'; +import { Size } from '../../types.ts'; +import { HashLength } from '../../utils/formatters'; +import Address from '../address/address'; +import { BodyTextProps } from '@make-software/cspr.design'; + +interface TransactorInfoProps { + type?: TransactorHashType | undefined; + accountInfo: AccountInfoResult | AccountCentralizedInfo | undefined; + contractPackage?: DeployContractPackageResult; + hash: string | null; + publicKey: string | null; + csprName?: string | null; + loading: boolean; + contractPackagePath: string; + accountPath: string; + hashLength?: HashLength; + hashFontSize?: BodyTextProps['scale']; + minifiedCopyNotification?: boolean; + avatarSize?: AvatarProps['size']; + nameSize?: Size; + withName?: boolean; + csprLiveDomainPath: string; +} + +export const TransactorInfo = ({ + type, + accountInfo, + contractPackage, + publicKey, + hash, + csprName, + loading, + hashLength, + hashFontSize = 'xs', + minifiedCopyNotification = true, + avatarSize = 'default', + withName = false, + csprLiveDomainPath, +}: TransactorInfoProps) => { + const accountInfoResult = deriveAccountInfo(accountInfo); + + return type && type === TransactorHashType.hash ? ( + + ) : ( +
+ ); +}; + +export default TransactorInfo; diff --git a/src/lib/index.ts b/src/lib/index.ts index e8fdc96d..34d1faa3 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -73,6 +73,10 @@ export * from './components/warning-message/warning-message'; export * from './components/modal-content-header/modal-content-header'; export * from './components/dropdown-with-search/searchable-dropdown'; export * from './components/identicon/identicon'; +export * from './components/deploy-actions/deploy-action-row'; +export * from './components/contract-identifier/contract-identifier'; +export * from './components/contract-icon/contract-icon'; +export * from './components/activity-feed-item/activity-feed-item'; export * from './hooks/use-click-and-touch-away'; export * from './hooks/use-escape-key'; export * from './hooks/use-click-away'; diff --git a/src/lib/types/CLType.ts b/src/lib/types/CLType.ts new file mode 100644 index 00000000..954dfdb9 --- /dev/null +++ b/src/lib/types/CLType.ts @@ -0,0 +1,81 @@ +export enum CLType { + /** A boolean value */ + Bool = 'Bool', + /** A 32-bit signed integer */ + I32 = 'I32', + /** A 64-bit signed integer */ + I64 = 'I64', + /** An 8-bit unsigned integer (a byte) */ + U8 = 'U8', + /** A 32-bit unsigned integer */ + U32 = 'U32', + /** A 64-bit unsigned integer */ + U64 = 'U64', + /** A 128-bit unsigned integer */ + U128 = 'U128', + /** A 256-bit unsigned integer */ + U256 = 'U256', + /** A 512-bit unsigned integer */ + U512 = 'U512', + /** A unit type, i.e. type with no values (analogous to `void` in C and `()` in Rust) */ + Unit = 'Unit', + /** A string of characters */ + String = 'String', + /** A key in the global state - URef/hash/etc. */ + Key = 'Key', + /** An Unforgeable Reference (URef) */ + URef = 'URef', + /** An [[Option]], i.e. a type that can contain a value or nothing at all */ + Option = 'Option', + /** A list of values */ + List = 'List', + /** A fixed-length array of bytes */ + ByteArray = 'ByteArray', + /** + * A [[Result]], i.e. a type that can contain either a value representing success or one representing failure. + */ + Result = 'Result', + /** A key-value map. */ + Map = 'Map', + /** A 1-value tuple. */ + Tuple1 = 'Tuple1', + /** A 2-value tuple, i.e. a pair of values. */ + Tuple2 = 'Tuple2', + /** A 3-value tuple. */ + Tuple3 = 'Tuple3', + /** A value of any type. */ + Any = 'Any', + /** A value of public key type. */ + PublicKey = 'PublicKey', +} + +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/lib/types/FTToken.ts b/src/lib/types/FTToken.ts new file mode 100644 index 00000000..8f9213ca --- /dev/null +++ b/src/lib/types/FTToken.ts @@ -0,0 +1,123 @@ +import { + AccountCentralizedInfo, + AccountInfoResult, + DeployContractPackageResult, + DeployResult, + TransactorHashType, +} from './types'; + +export type Decimals = string | number | undefined | null; +/** + * FungibleTokenResult + */ +export type FTResult = { + contract_hash: string; + decimals: number; + name: string; + symbol: string; +}; + +/** + * FungibleTokenAmountDataType + */ +export interface FTAmountDataType { + symbol: string | undefined | null; + decimals: number | null; + totalSupply: string | null; + totalSupplyMotes: string | null; +} + +export interface FtTokenMarketData { + price: number | null; + volume_24h: number | null; + iconPath: string | null; + website: string | null; + change_24h?: number | null; +} + +export type Cep18AmountData = FTAmountDataType & FtTokenMarketData; + +/** + * FungibleTokenBalanceTokenResult + */ +export type FTBalanceTokenResult = { + account_hash: string; + balance: string; + contract_package_hash: string; + contract_package?: DeployContractPackageResult | null; +}; + +/** + * FungibleTokenTransactionResult + */ + +export type FTTransactionResult = { + amount: string; + block_height: number; + contract_package_hash: string; + deploy_hash: string; + ft_action_type_id: number; + from_hash: string | null; + from_public_key: string | null; + from_type: string; + from_account_info?: AccountInfoResult | null; + from_centralized_account_info?: AccountCentralizedInfo | null; + caller_account_info?: AccountInfoResult | null; + caller_centralized_account_info?: AccountCentralizedInfo | null; + timestamp: string; + to_hash: string | null; + to_public_key: string | null; + to_type: string; + to_account_info?: AccountInfoResult | null; + to_centralized_account_info?: AccountCentralizedInfo | null; + from_cspr_name?: string; + to_cspr_name?: string; + transform_idx?: number; + rate?: number; + deploy?: DeployResult; + contract_package?: DeployContractPackageResult; +}; + +/** + * FungibleTokenActionTypeEnum + */ +export enum FTActionTypeEnum { + 'Mint' = 1, + 'Transfer' = 2, + 'Approve' = 3, + 'Burn' = 4, +} + +/** + * FungibleTokenActionType + */ +export const FTActionType = { + [FTActionTypeEnum.Mint]: 'Mint', + [FTActionTypeEnum.Transfer]: 'Transfer', + [FTActionTypeEnum.Approve]: 'Approve', + [FTActionTypeEnum.Burn]: 'Burn', +}; + +export enum FTEntryPointType { + approve = 'approve', + mint = 'mint', + burn = 'burn', + transfer = 'transfer', +} + +export interface FTTokenOwnerResult { + owner_type?: TransactorHashType; + owner_hash: string; + contract_package: DeployContractPackageResult | null; + contract_package_hash: string; + tokens_number: number; + account_info?: AccountInfoResult; + centralized_account_info?: AccountInfoResult; + owner_cspr_name?: string; + owner_public_key?: string; + balance?: string; +} + +export function FTToken(obj: any): FTResult { + return obj; +} diff --git a/src/lib/types/NFTToken.ts b/src/lib/types/NFTToken.ts new file mode 100644 index 00000000..c5ccf09a --- /dev/null +++ b/src/lib/types/NFTToken.ts @@ -0,0 +1,175 @@ +import { + AccountCentralizedInfo, + AccountInfoResult, + DeployContractPackageResult, + DeployResult, + PaginatedResponse, + TransactorHashType, +} from './types'; + +export enum TokenStandardEnum { + 'CEP47' = 1, + 'CEP78' = 2, +} + +export const NFTTokenStandard = { + [TokenStandardEnum.CEP47]: 'CEP47', + [TokenStandardEnum.CEP78]: 'CEP78', +}; + +export enum NftActivityTypeEnum { + 'Mint' = 1, + 'Burn' = 2, + 'Approve' = 3, + 'Transfer' = 4, + 'Metadata' = 5, + 'Revoke' = 6, +} + +export const NFTActivityType = { + [NftActivityTypeEnum.Mint]: 'Mint', + [NftActivityTypeEnum.Burn]: 'Burn', + [NftActivityTypeEnum.Approve]: 'Approve', + [NftActivityTypeEnum.Transfer]: 'Transfer', + [NftActivityTypeEnum.Metadata]: 'Metadata update', + [NftActivityTypeEnum.Revoke]: 'Revoke', +}; + +export enum CsprMarketEntryPoint { + delist_token = 'delist_token', + list_token = 'list_token', + accept_offer = 'accept_offer', + cancel_offer = 'cancel_offer', + make_offer = 'make_offer', +} + +export enum NftTokenEntryPoint { + approve = 'approve', + burn = 'burn', + mint = 'mint', + transfer = 'transfer', + transfer_from = 'transfer_from', + update_token_meta = 'update_token_meta', + set_approval_for_all = 'set_approval_for_all', +} + +export interface NFTTokenMetadata { + name?: string; + description?: string; + nftPreview?: string; + contentIpfs?: string; + pictureIpfs?: string; +} + +export interface NFTTokenMetadataEntry { + key: string; + value: string; +} + +export interface NFTTokenAttribute { + trait_type: string; + value: string; +} + +export interface NFTTokenAttributesEntry { + key: string; + value: NFTTokenAttribute[]; +} + +export interface NFTTokenMetadataWithLinks { + itemsWithLinks: NFTTokenMetadataEntry[]; + attributes: NFTTokenAttributesEntry | null; +} + +export interface NFTTokenResult { + block_height: number; + tracking_id: string; + token_standard_id: number; + is_burned: boolean; + contract_package_hash: string; + contract_package?: DeployContractPackageResult; + token_id: string; + owner_hash: string; + owner_public_key: string; + owner_type: number; + offchain_metadata: Record; + onchain_metadata: NFTTokenMetadataEntry[]; + timestamp: string; + offchain_metadata_status: number; + owner_cspr_name: string; + + //remove after migration of all the apis which involve NFTTokenResult entity + metadata: NFTTokenMetadataEntry[]; + owner_account_hash: string; +} + +export function NFTToken(obj: any): NFTTokenResult { + return obj; +} + +export interface NFTTokenActivityResult { + block_height: number; + token_tracking_id: string; + timestamp: string; + caller_account_info?: AccountInfoResult | null; + caller_centralized_account_info?: AccountCentralizedInfo | null; + deploy_hash: string; + from_hash: string | null; + from_public_key: string | null; + from_account_info?: AccountInfoResult | null; + from_centralized_account_info?: AccountCentralizedInfo | null; + from_type: number; + to_hash: string | null; + to_public_key: string | null; + to_type: number; + to_account_info?: AccountInfoResult | null; + to_centralized_account_info?: AccountCentralizedInfo | null; + to_cspr_name?: string | null; + from_cspr_name?: string | null; + caller_cspr_name?: string | null; + nft_action_id: string; + token_id: string; + rate: number; + deploy?: DeployResult; +} + +const dictionaryToList = (data): NFTTokenMetadataEntry[] => { + return data + ? Object.entries(data).map((item) => { + return { key: item[0], value: item[1] as string }; + }) + : []; +}; + +export const MapTokenMetadataAsList = (token): NFTTokenResult => { + const metadata = Array.isArray(token?.metadata) + ? token?.metadata + : dictionaryToList(token?.metadata); + + return { + ...token, + metadata: metadata, + }; +}; + +export const MapTokensMetadataAsList = ( + tokens, +): PaginatedResponse => { + const mappedTokenMetadataAsList = tokens.data.map(MapTokenMetadataAsList); + + return { + ...tokens, + data: mappedTokenMetadataAsList, + }; +}; + +export interface NFTTokenOwnerResult { + owner_type: TransactorHashType; + owner_hash: string; + contract_package_hash: string; + tokens_number: number; + account_info?: AccountInfoResult; + centralized_account_info?: AccountInfoResult; + cspr_name?: string; + owner_public_key?: string; +} diff --git a/src/lib/types/types.ts b/src/lib/types/types.ts new file mode 100644 index 00000000..5cc4ccfe --- /dev/null +++ b/src/lib/types/types.ts @@ -0,0 +1,313 @@ +import { InfoGetDeployResult, DeployExecutionResult } from 'casper-js-sdk'; +import { CLTypeTypeResult } from './CLType'; +export type ResponseError = { message?: string }; + +export type DataResponse = { + data: T; + error?: ResponseError; +}; + +export type PaginatedResponse = { + data: T[]; + item_count: number; + page_count: number; +}; + +export interface GetDeployResult extends InfoGetDeployResult { + execution_results: DeployExecutionResult; +} + +export enum NetworkMajorVersion { + 'V1' = '1', + 'V2' = '2', +} + +export enum ContractTypeId { + System = 1, + Cep18 = 2, + CustomCep18 = 3, + CEP47Nft = 4, + CustomCEP47Nft = 5, + DeFi = 6, + CEP78Nft = 7, + CustomCEP78Nft = 8, + NFTMarketplace = 9, + CEP95Nft = 10, +} + +export type DeployContractPackageMetadata = { + symbol: string; + name: string; + decimals: number; + balances_uref: string; + total_supply_uref: string; + burn_mode?: string; + holder_mode?: string; + identifier_mode?: string; + metadata_mutability?: string; + minting_mode?: string; + nft_kind?: string; + nft_metadata_kind?: string; + ownership_mode?: string; + whitelist_mode?: string; + owner_reverse_lookup_mode?: string; +}; + +export interface AccountCentralizedInfo { + account_hash: string; + url: string; + name: string; + avatar_url: string; +} + +export interface GeneralizedAccountInfo { + logo: string | null; + name?: string; +} + +export interface AccountInfoResult { + account_hash: string; + url: string; + is_active: boolean; + deploy_hash: string; + verified_account_hashes: string[]; + balance?: number; + genesis_balance?: string; + delegated_balance?: string; + staked_balance?: string; + undelegating_balance?: string; + auction_status?: string; + deployment_threshold: number; + key_management_threshold: number; + account_info?: AccountInfoResult; + centralized_account_info?: AccountCentralizedInfo; + public_key?: string; + cspr_name?: string; +} +export type FMPriceData = { + price: number; + volume_24h: number; +}; + +export type CoingeckoPriceData = FMPriceData & { + change_24h: number; +}; + +export type DeployContractPackageResult = { + description: string | null; + icon_url: string | null; + name: string | null; + contract_package_hash: string; + latest_version_contract_type_id: number | null; + owner_public_key: string | null; + owner_hash: string | null; + timestamp: string; + has_ces_events: boolean; + deploys_number?: number; + activity_number?: number; + metadata?: DeployContractPackageMetadata; + account_info?: AccountInfoResult | null; + centralized_account_info?: AccountCentralizedInfo | null; + contract_description?: string; + cspr_name?: string | null; + coingecko_id: string | null; + latest_version_contract_hash: string | null; + coingecko_data: CoingeckoPriceData; + friendlymarket_data: FMPriceData; + // TODO: remove these types + contract_type_id?: number | null; + contract_name: string | null; + website_url?: string | null; +}; + +export type ContractResult = { + block_height: number; + contract_hash: string; + contract_package_hash: string; + contract_type_id: number; + contract_version: number; + deploy_hash: string; + from_purse_public_key: string; + is_disabled: boolean; + timestamp: string; + contract_package?: DeployContractPackageResult; +}; + +export type DeployClTypeResult = { + cl_type: CLTypeTypeResult; + parsed: CLTypeParsedResult | string | null; +}; + +export type DeployArgsResult = { + amount?: DeployClTypeResult; + spender?: DeployClTypeResult; + bsc_recipient_address?: DeployClTypeResult; + contract_hash_str?: DeployClTypeResult; + recipient?: DeployClTypeResult; + owner?: DeployClTypeResult; + token_id?: DeployClTypeResult; + token_meta?: DeployClTypeResult; + token_metas?: DeployClTypeResult; + token_meta_data?: DeployClTypeResult; + id?: DeployClTypeResult; + target?: DeployClTypeResult; + contract_name?: DeployClTypeResult; + decimals?: DeployClTypeResult; + initial_supply?: DeployClTypeResult; + name?: DeployClTypeResult; + symbol?: DeployClTypeResult; + amount_in?: DeployClTypeResult; + amount_out_min?: DeployClTypeResult; + deadline?: DeployClTypeResult; + path?: DeployClTypeResult; + to?: DeployClTypeResult; + tokens?: DeployClTypeResult; + delegator?: DeployClTypeResult; + validator?: DeployClTypeResult; + new_validator?: DeployClTypeResult; + offerer?: DeployClTypeResult; + collection?: DeployClTypeResult; + token_owner?: DeployClTypeResult; + operator?: DeployClTypeResult; + token_ids?: DeployClTypeResult; + target_key?: DeployClTypeResult; + source_key?: DeployClTypeResult; + csprfun_contract_hash_key?: DeployClTypeResult; + token_to_trade_contract_hash_key?: DeployClTypeResult; + attached_value?: DeployClTypeResult; +}; +export type DeployEntryPointResult = { + action_type_id: null; + contract_hash: string | null; + contract_package_hash: string | null; + id: string | null; + name: string | null; +}; + +export type NftActionsResult = { + block_height: number; + contract_package: DeployContractPackageResult; + contract_package_hash: string; + deploy_hash: string; + from_hash: null; + from_public_key: string | null; + from_type: null; + nft_action_id: number; + timestamp: string; + to_hash: string; + to_public_key: string | null; + to_type: number; + token_id: string; + token_tracking_id: number; + transform_idx: number; +}; + +export enum HashType { + accountHash = 'account-hash', + hash = 'hash', +} + +export enum TransactorHashType { + 'account' = 0, + 'hash' = 1, +} + +export type FTActionsResult = { + amount: string; + contract_package: DeployContractPackageResult; + contract_package_hash: string; + deploy_hash: string; + ft_action_type_id: number; + from_hash: string; + from_public_key: string | null; + from_type: TransactorHashType; + timestamp: string; + to_hash: string; + to_public_key: string | null; + to_type: TransactorHashType; + transform_idx: number; +}; + +export type DeployTransferResult = { + amount: string; + block_height: number; + transfer_index: number; + deploy_hash: string; + from_purse_public_key: string | null; + from_purse: string; + id: string | null; + initiator_account_hash: string; + timestamp: string; + to_account_hash: string; + to_purse: string; + transform_key: string; + to_purse_public_key: string | null; + to_purse_account_info: AccountInfoResult | null; + from_purse_account_info: AccountInfoResult | null; + to_purse_centralized_account_info: AccountCentralizedInfo | null; + from_purse_centralized_account_info: AccountCentralizedInfo | null; +}; + +export interface DeployResult { + // means it's a pending deploy + args: DeployArgsResult; + block_hash: string | null; + caller_public_key: string; + caller_hash: string; + contract_entrypoint?: DeployEntryPointResult; + contract_hash: string | null; + contract_package: DeployContractPackageResult; + contract_package_hash: string | null; + cost: string; + consumed_gas: string; + deploy_hash: string; + error_message: string | null; + execution_type_id: number; + nft_token_actions?: NftActionsResult[]; + ft_token_actions?: FTActionsResult[]; + payment_amount: string | null; + refund_amount?: string | null; + rate: number; + status: string; + timestamp: string; + transfers?: DeployTransferResult[]; + pending?: boolean; + account_info?: AccountInfoResult; + centralized_account_info?: AccountCentralizedInfo; + cspr_name?: string; + amount: string | null; + currency_cost: number; + caller_cspr_name?: string | null; + block_height: number; +} + +export interface Deploy { + // means it's a pending deploy + accountInfo?: AccountInfoResult; + amount: string | null; + args: DeployArgsResult; + blockHash: string | null; + blockHeight: number | null; + callerCsprName?: string | null; + callerHash: string; + callerPublicKey: string; + centralizedAccountInfo?: AccountCentralizedInfo | null; + consumedGas: string; + contractHash: string | null; + contractPackage: DeployContractPackageResult; + contractPackageHash: string | null; + cost: string; + deployHash: string; + entryPoint?: DeployEntryPointResult; + errorMessage: string | null; + executionTypeId: number; + ftActions?: FTActionsResult[]; + nftActions?: NftActionsResult[]; + paymentAmount: string | null; + pending?: boolean; + refundAmount?: string | null; + status: string; + timeTransactionCurrencyRate: number; + timestamp: string; + transfers?: DeployTransferResult[]; +} diff --git a/src/lib/utils/account.tsx b/src/lib/utils/account.tsx new file mode 100644 index 00000000..7d20962d --- /dev/null +++ b/src/lib/utils/account.tsx @@ -0,0 +1,105 @@ +import { isObjEmpty } from './object.tsx'; +import {AccountInfoResult, GeneralizedAccountInfo} from "../types/types"; +import { Conversions, PublicKey as CLPublicKey } from 'casper-js-sdk'; + +type Input = { base64: string } | { publicKeyHex: string }; + +export const AccountModel = (input: Input) => { + const getRawPublicKey = () => { + let value: CLPublicKey; + + if ('publicKeyHex' in input) { + value = CLPublicKey.fromHex(input.publicKeyHex); + } else if ('base64' in input) { + // TODO: Seems like we are not using 'base64' input + // TODO: base64 signer account will always use fromEd25519 because there is no prefix available + // const bytes = Conversions.decodeBase64(input.base64); + // value = CLPublicKey.fromEd25519(bytes); + } else { + throw Error('missing account key'); + } + + // @ts-ignore + return value; + }; + + const getPublicKey = () => { + // toAccountHex => sig key prefix + base16 (hex) hash + return getRawPublicKey().toHex(); + }; + + const getBase16AccountHash = () => { + // toAccountHash => raw hash + return Conversions.encodeBase16(getRawPublicKey().accountHash().toBytes()); + }; + + const getBase64AccountHash = () => { + // toAccountHash => raw hash + return Conversions.encodeBase64(getRawPublicKey().accountHash().toBytes()); + }; + + return { + getPublicKey: getPublicKey, + getAccountHash: getBase16AccountHash, + getBase64AccountHash: getBase64AccountHash, + }; +}; + +export const getAccountInfoLogo = ( + accountInfo: AccountInfoResult | null | undefined +): string | null => { + if (!accountInfo) return null; + + const logo = accountInfo.info?.owner?.branding?.logo; + + if (logo?.svg) { + return logo?.svg; + } + + if (logo?.png_256) { + return logo?.png_256; + } + + return null; +}; + +export const getCentralizedAccountInfoLogo = ( + accountInfo: AccountCentralizedInfo | null | undefined +): string | null => { + if (!accountInfo) return null; + + const logo = accountInfo.avatar_url; + + if (logo) { + return logo; + } + + return null; +}; + +/** + * Derive account info from accountInfo or centralizedAccountInfo. + * Reason for doing that, we have different interfaces for those objects. + * @param accountInfoObj : AccountInfoResult | AccountCentralizedInfo + */ +export const deriveAccountInfo = ( + accountInfoObj: any +): GeneralizedAccountInfo | null => { + if (accountInfoObj == null) { + return null; + } + + const hasInfoStandard = !isObjEmpty(accountInfoObj?.info); + + if (hasInfoStandard) { + return { + name: accountInfoObj?.info?.owner?.name, + logo: getAccountInfoLogo(accountInfoObj), + }; + } + + return { + name: accountInfoObj?.name, + logo: getCentralizedAccountInfoLogo(accountInfoObj), + }; +}; diff --git a/src/lib/utils/cltype.tsx b/src/lib/utils/cltype.tsx new file mode 100644 index 00000000..74545998 --- /dev/null +++ b/src/lib/utils/cltype.tsx @@ -0,0 +1,126 @@ + +import {Args, Approval as ApprovalSDK, Approval} from 'casper-js-sdk'; +import {CLType, CLTypeParsedListResult, CLTypeParsedResult, CLTypeTypeResult} from "../types/CLType"; + +export const stringifyCLTypeType = ( + type: string | CLType | CLTypeTypeResult +): string => { + const getTypeFromNestedObj = (type) => + typeof type === 'object' ? Object.keys(type)[0] : type; + + const clValueType = getTypeFromNestedObj(type); + const clValueInnerType = getTypeFromNestedObj(type[clValueType]); + + const clValueListInnerType = + clValueType === CLType.List && clValueInnerType === CLType.Option + ? stringifyCLTypeType(type[clValueType]) + : clValueInnerType; + + switch (clValueType) { + case CLType.ByteArray: + case CLType.List: + return `${clValueType}[${clValueListInnerType}]`; + case CLType.Tuple1: + case CLType.Tuple2: + case CLType.Tuple3: + case CLType.Map: + case CLType.Key: + return `${clValueType}`; + case CLType.Option: + return `${clValueType}(${clValueInnerType})`; + + default: + return `${clValueType}`; + } +}; + +export const stringifyCLTypeValue = ({ + type, + value, + balance, +}: { + type?: CLTypeTypeResult | string; + value: CLTypeParsedResult | null; + balance?: string | null; +}) => { + if (!type) { + return Array.isArray(value) + ? value.join(', ') + : typeof value === 'object' + ? JSON.stringify(value) + : value; + } + + const getTypeFromNestedObj = (type) => + typeof type === 'object' ? Object.keys(type)[0] : type; + + const clValueType = getTypeFromNestedObj(type); + const clValueInnerType = getTypeFromNestedObj(type[clValueType]); + + switch (clValueType) { + case CLType.Unit: + return balance; + + case CLType.List: + return (value as CLTypeParsedListResult) + ?.map((listItem) => + stringifyCLTypeValue({ + type: clValueInnerType, + value: listItem, + }) + ) + .join(', '); + + case CLType.Tuple1: + case CLType.Tuple2: + case CLType.Tuple3: + return (value as CLTypeParsedListResult)?.join(', '); + + case CLType.Option: + return stringifyCLTypeValue({ + type: clValueInnerType, + value: value, + }); + case CLType.Result: + case CLType.Map: + return JSON.stringify(value); + + case CLType.Bool: + return value !== null && value !== undefined ? value.toString() : null; + + default: + return value; + } +}; + +export const convertTransactionArgsToObj = ( + args: Args +): Record => { + if (!args) { + return {}; + } + + const argsKeys = [...args.args.keys()]; + + return argsKeys.reduce((prev, curr) => { + return { + ...prev, + [curr]: args.getByName(curr).toJSON(), + }; + }, {}); +}; + +export const convertApprovalsFromBytesToString = ( + approvals: ApprovalSDK[] +): Approval[] => { + if (!approvals || !approvals.length) { + return []; + } + + return approvals.map((approval) => { + return { + signer: approval.signer.toHex(), + signature: approval.signature.toJSON(), + }; + }) as Approval[]; +}; diff --git a/src/lib/utils/currency.ts b/src/lib/utils/currency.ts index 8d13d356..2303dcd7 100644 --- a/src/lib/utils/currency.ts +++ b/src/lib/utils/currency.ts @@ -1,21 +1,30 @@ import Big from 'big.js'; -import { DEFAULT_PRECISION, FULL_PRECISION } from './formatters'; +import { SMALL_PRECISION, DEFAULT_PRECISION, FULL_PRECISION } from './formatters'; export enum PrecisionCase { + 'none' = 'none', + 'small' = 'small', 'deployCost' = 'deployCost', 'full' = 'full', } +export const CSPR_DECIMALS = 9; export const MOTES_PER_CSPR_RATE = '1000000000'; // 1 000 000 000 MOTES === 1 CSPR export const currencyPrecisionByCase = (precisionCase?: PrecisionCase) => { switch (precisionCase) { + case PrecisionCase.small: + return SMALL_PRECISION; + case PrecisionCase.deployCost: return DEFAULT_PRECISION; case PrecisionCase.full: return FULL_PRECISION; + case PrecisionCase.none: + return 0; + default: return 0; } diff --git a/src/lib/utils/deploy-args.ts b/src/lib/utils/deploy-args.ts new file mode 100644 index 00000000..01ec521c --- /dev/null +++ b/src/lib/utils/deploy-args.ts @@ -0,0 +1,66 @@ +import { Args, CLValueParser, Conversions } from 'casper-js-sdk'; +import { DeployArgsResult } from '../types/types'; +import { isNonNullable } from './guards'; +import { deriveSplitDataFromNamedKeyValue } from './named-key'; + +export const getNftTokensQuantityFromArgs = (args: DeployArgsResult) => { + if (args.token_ids || args.token_metas || args.tokens) { + return ( + ((args.token_ids || args.token_metas || args.tokens)?.parsed as any[]) || + [] + ).length; + } + + if (args.token_meta_data || args.token_id) { + return 1; + } + + return undefined; +}; + +export const getNftTokenIdsFromArguments = (args) => { + const hasTokens = + args.token_metas?.parsed || args.token_id?.parsed || args.token_ids?.parsed; + + const getTokenIdsFromClValue = (clValue) => + clValue?.parsed + ? clValue?.parsed.map((token) => + typeof token === 'string' ? token : token.key, + ) + : []; + + if (hasTokens) { + const tokens = [ + ...getTokenIdsFromClValue(args.token_ids), + ...getTokenIdsFromClValue(args.token_metas), + ]; + const ids = [...tokens, args.token_id?.parsed].filter(isNonNullable); + + return [...new Set(ids)]; + } + return null; +}; + +/** + * + * @param argument args from Deploy + * @param parsedKey string { deprecated } + */ +export const guardedDeriveSplitDataFromArguments = ( + argument: any, + parsedKey: string, +) => { + if (argument && argument.parsed) { + // parse arguments for v1 + if (argument.parsed[parsedKey]) { + return deriveSplitDataFromNamedKeyValue(argument.parsed[parsedKey]); + } + + if (typeof argument.parsed !== 'object') { + // parse arguments for v2 + return deriveSplitDataFromNamedKeyValue(argument.parsed); + } + } + + return null; +}; diff --git a/src/lib/utils/derive-ft-token-data-service.ts b/src/lib/utils/derive-ft-token-data-service.ts new file mode 100644 index 00000000..652b6b51 --- /dev/null +++ b/src/lib/utils/derive-ft-token-data-service.ts @@ -0,0 +1,46 @@ +import deriveFtTokenMarketDataService from './derive-ft-token-market-data-service'; +import { FTAmountDataType, FtTokenMarketData } from '../types/FTToken'; +import { DeployContractPackageResult } from '../types/types'; + +type Cep18DataTypeNew = Omit< + FTAmountDataType, + 'totalSupply' | 'totalSupplyMotes' +> & + FtTokenMarketData; + +type GetFtTokenDataProps = { + contractPackageInfo: DeployContractPackageResult | undefined | null; + isShiboo?: boolean; +}; + +export const deriveFtTokenData = ( + props: GetFtTokenDataProps | null, +): Cep18DataTypeNew => { + const ftTokenMarketData: FtTokenMarketData = deriveFtTokenMarketDataService( + props?.contractPackageInfo, + ); + + if (props?.isShiboo) { + return { + symbol: 'SHIBOO', + decimals: 18, + ...ftTokenMarketData, + }; + } + + if (!props?.contractPackageInfo) { + return { + symbol: null, + decimals: null, + ...ftTokenMarketData, + }; + } + + const { metadata } = props.contractPackageInfo; + + return { + symbol: metadata?.symbol ?? null, + decimals: metadata?.decimals != null ? metadata?.decimals : null, + ...ftTokenMarketData, + }; +}; diff --git a/src/lib/utils/derive-ft-token-market-data-service.ts b/src/lib/utils/derive-ft-token-market-data-service.ts new file mode 100644 index 00000000..e4be70a6 --- /dev/null +++ b/src/lib/utils/derive-ft-token-market-data-service.ts @@ -0,0 +1,40 @@ +import { DeployContractPackageResult } from '../types/types'; +import { FtTokenMarketData } from '../types/FTToken'; + +export const deriveFtTokenMarketDataService = ( + contractPackageInfo: DeployContractPackageResult | undefined | null, +): FtTokenMarketData => { + if (!contractPackageInfo) { + return { + price: null, + volume_24h: null, + iconPath: null, + website: null, + }; + } + + const coinGeckoData = contractPackageInfo?.coingecko_data; + const friendlyMarketData = contractPackageInfo?.friendlymarket_data; + + if (coinGeckoData) { + return { + ...coinGeckoData, + iconPath: 'assets/icons/logos/coingecko_logo.png', + website: contractPackageInfo?.coingecko_id + ? `https://www.coingecko.com/en/coins/${contractPackageInfo.coingecko_id}` + : null, + }; + } + + if (friendlyMarketData) { + return { + ...friendlyMarketData, + iconPath: 'assets/icons/logos/fm_logo.png', + website: contractPackageInfo?.latest_version_contract_hash + ? `https://www.friendly.market/swap/CSPR/${contractPackageInfo.latest_version_contract_hash}` + : null, + }; + } +}; + +export default deriveFtTokenMarketDataService; diff --git a/src/lib/utils/formatters.ts b/src/lib/utils/formatters.ts index f859c24b..efd4f786 100644 --- a/src/lib/utils/formatters.ts +++ b/src/lib/utils/formatters.ts @@ -232,6 +232,11 @@ export const formatDateWithMonthAndYear = (value: string): string => { })}`; }; +export enum HashFontSize { + 'default' = 'default', + 'big' = 'big', +} + export enum HashLength { FULL = 0, TINY = 5, diff --git a/src/lib/utils/ft-token-amount.ts b/src/lib/utils/ft-token-amount.ts new file mode 100644 index 00000000..04430208 --- /dev/null +++ b/src/lib/utils/ft-token-amount.ts @@ -0,0 +1,47 @@ +import Big from 'big.js'; +import { + formatNumber, + formatBigNumbers, + DEFAULT_AMOUNT_PRECISION, +} from './formatters'; +import { Decimals } from '../types/FTToken'; + +export const tokenDivider = (decimals: Decimals) => + Big(10).pow(Number(decimals || 0)); + +export const getAmountFromMotes = ( + amount: string | undefined | null, + decimals: Decimals, +) => + Big(amount?.toString() || 0) + .div(tokenDivider(Number(decimals || 0))) + .toString(); + +export const formatTokenAmount = ( + amount: string | undefined | null, + precision?: number, + shouldShortenAmount?: boolean, +) => { + const formattedCep18Amount = amount + ? formatNumber(amount, { + precision: precision != null ? precision : DEFAULT_AMOUNT_PRECISION, + }) + : '-'; + + return formattedCep18Amount.length > 7 && shouldShortenAmount + ? formatBigNumbers(amount) + : formattedCep18Amount; +}; + +export const ftTokenAmountToCurrency = ( + amount: string | number, + currencyPerFtTokenRate: number, +): string => { + if (currencyPerFtTokenRate === 0) { + throw new Error('ftTokenAmountToCurrency: the price cannot be zero'); + } + + return Big(amount.toString()) + .mul(currencyPerFtTokenRate.toString()) + .toString(); +}; diff --git a/src/lib/utils/guards.tsx b/src/lib/utils/guards.tsx new file mode 100644 index 00000000..e3356ec1 --- /dev/null +++ b/src/lib/utils/guards.tsx @@ -0,0 +1,3 @@ +export const isNonNullable = ( + value: T, +): value is NonNullable => value != null; diff --git a/src/lib/utils/named-key-prefix.ts b/src/lib/utils/named-key-prefix.ts index 04db7783..3b209671 100644 --- a/src/lib/utils/named-key-prefix.ts +++ b/src/lib/utils/named-key-prefix.ts @@ -14,13 +14,13 @@ export enum NamedKeyPrefix { export const hashPrefixRegEx = new RegExp( `(${Object.values(NamedKeyPrefix).join('|')})(?=[0-9a-fA-F])`, - 'i' + 'i', ); export const hasNamedKeyPrefix = (value: any): boolean => typeof value === 'string' && Object.values(NamedKeyPrefix).some((prefix) => - (value || '').includes(prefix) + (value || '').includes(prefix), ); export const getNamedKeyPrefix = (value: string): string => { diff --git a/src/lib/utils/named-key.tsx b/src/lib/utils/named-key.tsx new file mode 100644 index 00000000..ac6c583b --- /dev/null +++ b/src/lib/utils/named-key.tsx @@ -0,0 +1,24 @@ +import { hashPrefixRegEx } from './named-key-prefix'; + +export interface SplitDataType { + prefix: string; + hash: string; +} + +export const deriveSplitDataFromNamedKeyValue = ( + namedKeyValue: string, +): SplitDataType => { + const [hash, lastDigits] = namedKeyValue + .replace(hashPrefixRegEx, '') + .split('-'); + + const formattedPrefix = namedKeyValue.match(hashPrefixRegEx) + ? namedKeyValue.match(hashPrefixRegEx)![0] + : ''; + const formattedHash = lastDigits ? `${hash}-${lastDigits}` : `${hash}`; + + return { + prefix: formattedPrefix, + hash: formattedHash, + }; +}; diff --git a/src/lib/utils/object.tsx b/src/lib/utils/object.tsx new file mode 100644 index 00000000..161d2659 --- /dev/null +++ b/src/lib/utils/object.tsx @@ -0,0 +1,13 @@ +export const isObjEmpty = (obj) => obj == null || Object.keys(obj).length === 0; + +export const mapToDictionary = >( + data: V[], +): T => + data && + data.reduce( + (prev, curr) => ({ + ...prev, + [curr.key.trim()]: curr.value, + }), + {} as T, + ); diff --git a/src/lib/utils/truncate-hash.ts b/src/lib/utils/truncate-hash.ts new file mode 100644 index 00000000..bf9b3664 --- /dev/null +++ b/src/lib/utils/truncate-hash.ts @@ -0,0 +1,5 @@ +export const SHORTENED_ENTRY_TYPE_LENGTH = 20; +export const SHORTENED_CONTRACT_NAME_LENGTH = 20; + +export const truncateName = (name, limit) => + name && name.length > limit ? name.substring(0, limit - 1) + '...' : name;