diff --git a/cypress/component/unit/truncate.cy.tsx b/cypress/component/unit/truncate.cy.tsx
index 976ec515..b8b2a7d8 100644
--- a/cypress/component/unit/truncate.cy.tsx
+++ b/cypress/component/unit/truncate.cy.tsx
@@ -1,6 +1,6 @@
///
-import { truncate } from '../../../src/util/truncate';
+import { truncate } from '../../../src/lib/util/truncate';
describe('Component | Unit | Util | Truncate', () => {
before(() => {
diff --git a/package-lock.json b/package-lock.json
index 00df370c..44dd4be4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,16 +1,17 @@
{
"name": "@massalabs/react-ui-kit",
- "version": "0.0.3",
+ "version": "0.0.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@massalabs/react-ui-kit",
- "version": "0.0.3",
+ "version": "0.0.4",
"dependencies": {
"@headlessui/react": "^1.7.15",
"copy-to-clipboard": "^3.3.3",
"currency.js": "^2.0.4",
+ "dot-object": "^2.1.5",
"minidenticons": "^4.2.1",
"react": "^18.2.0",
"react-currency-input-field": "^3.6.11",
@@ -20,7 +21,8 @@
"react-number-format": "^5.2.2",
"tw-colors": "^1.2.5",
"viem": "^1.5.2",
- "vite-plugin-svgr": "^3.2.0"
+ "vite-plugin-svgr": "^3.2.0",
+ "zustand": "^4.5.2"
},
"devDependencies": {
"@babel/preset-env": "^7.21.4",
@@ -40,6 +42,7 @@
"@testing-library/dom": "^9.2.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
+ "@types/dot-object": "^2.1.6",
"@types/jest": "^29.5.1",
"@types/react": "^18.2.46",
"@types/react-dom": "^18.0.11",
@@ -68,6 +71,10 @@
"tailwindcss": "^3.3.1",
"typescript": "^5.2.2",
"vite": "^4.5.3"
+ },
+ "peerDependencies": {
+ "@massalabs/massa-web3": "^4.0.2-dev",
+ "@massalabs/wallet-provider": "^2.0.1-dev"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -2821,6 +2828,12 @@
"react-dom": "^16 || ^17 || ^18"
}
},
+ "node_modules/@hicaru/bearby.js": {
+ "version": "0.5.8",
+ "resolved": "https://registry.npmjs.org/@hicaru/bearby.js/-/bearby.js-0.5.8.tgz",
+ "integrity": "sha512-K6mLazzHkDNF5Qmx5iQ4+UqmvBJxtuwg1ZHEDEvOKB1SV/QNuKJ54/HRlLMqJE0RHam2zP7s++RlnMZUIfWgGg==",
+ "peer": true
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.11",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
@@ -3823,6 +3836,15 @@
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==",
"dev": true
},
+ "node_modules/@lukeed/csprng": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz",
+ "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/@massalabs/eslint-config": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/@massalabs/eslint-config/-/eslint-config-0.0.9.tgz",
@@ -3839,6 +3861,95 @@
"eslint-plugin-tsdoc": "^0.2.17"
}
},
+ "node_modules/@massalabs/massa-web3": {
+ "version": "4.0.2-dev.20240410152026",
+ "resolved": "https://registry.npmjs.org/@massalabs/massa-web3/-/massa-web3-4.0.2-dev.20240410152026.tgz",
+ "integrity": "sha512-SGsXbxICvdwOnRThh2MSswvzA/k5OfrlJSujZBgNA2CoATXGBar11YcDEIgVttHRRqQSJG39EQcMOs3eRC0irA==",
+ "peer": true,
+ "dependencies": {
+ "@massalabs/wallet-provider": "^2.0.0",
+ "@massalabs/web3-utils": "^1.4.9",
+ "@noble/ed25519": "^1.7.3",
+ "@noble/hashes": "^1.2.0",
+ "@types/ws": "^8.5.4",
+ "@web3pack/base58-check": "^1.0.3",
+ "axios": "^0.26.1",
+ "bignumber.js": "^9.1.1",
+ "bip39": "^3.0.4",
+ "bs58check": "^3.0.1",
+ "buffer": "^6.0.3",
+ "crypto-js": "^4.1.1",
+ "dotenv": "^16.0.3",
+ "js-base64": "^3.7.5",
+ "string_decoder": "^1.3.0",
+ "tslib": "^2.5.2",
+ "util": "^0.12.5",
+ "varint": "^6.0.0"
+ },
+ "optionalDependencies": {
+ "bufferutil": "^4.0.7",
+ "utf-8-validate": "^6.0.2"
+ }
+ },
+ "node_modules/@massalabs/massa-web3/node_modules/@massalabs/wallet-provider": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@massalabs/wallet-provider/-/wallet-provider-2.0.0.tgz",
+ "integrity": "sha512-3BKtYszSfKMOi85cxOB1q60uiMWYmdteV28stx2NjT42VtSyKOuWiTJq4KaWbf3ov+fkg+/HknXdl5bhDghbSQ==",
+ "peer": true,
+ "dependencies": {
+ "@hicaru/bearby.js": "^0.5.7",
+ "@massalabs/web3-utils": "^1.4.9-dev",
+ "axios": "^0.28.0",
+ "bs58check": "^3.0.1",
+ "buffer": "^6.0.3",
+ "uid": "^2.0.1"
+ },
+ "optionalDependencies": {
+ "bufferutil": "^4.0.7",
+ "utf-8-validate": "^6.0.2"
+ }
+ },
+ "node_modules/@massalabs/massa-web3/node_modules/@massalabs/wallet-provider/node_modules/axios": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz",
+ "integrity": "sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==",
+ "peer": true,
+ "dependencies": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/@massalabs/massa-web3/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "peer": true,
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/@massalabs/massa-web3/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==",
+ "peer": true
+ },
"node_modules/@massalabs/prettier-config-as": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/@massalabs/prettier-config-as/-/prettier-config-as-0.0.2.tgz",
@@ -3848,6 +3959,101 @@
"assemblyscript-prettier": "^1.0.6"
}
},
+ "node_modules/@massalabs/wallet-provider": {
+ "version": "2.0.1-dev.20240423112601",
+ "resolved": "https://registry.npmjs.org/@massalabs/wallet-provider/-/wallet-provider-2.0.1-dev.20240423112601.tgz",
+ "integrity": "sha512-2NvwKho1Couwd2/gXZ0ZGBymmTiuX6rxjoX2gQnEu8LI2i15uDfRba5Gv6NSSvgLcjExzbhrJOQzPRgDAJhDlQ==",
+ "peer": true,
+ "dependencies": {
+ "@hicaru/bearby.js": "^0.5.7",
+ "@massalabs/web3-utils": "^1.4.9-dev",
+ "axios": "^0.28.0",
+ "bs58check": "^3.0.1",
+ "buffer": "^6.0.3",
+ "uid": "^2.0.1"
+ },
+ "optionalDependencies": {
+ "bufferutil": "^4.0.7",
+ "utf-8-validate": "^6.0.2"
+ }
+ },
+ "node_modules/@massalabs/wallet-provider/node_modules/axios": {
+ "version": "0.28.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.28.1.tgz",
+ "integrity": "sha512-iUcGA5a7p0mVb4Gm/sy+FSECNkPFT4y7wt6OM/CDpO/OnNCvSs3PoMG8ibrC9jRoGYU0gUK5pXVC4NPXq6lHRQ==",
+ "peer": true,
+ "dependencies": {
+ "follow-redirects": "^1.15.0",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/@massalabs/wallet-provider/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "peer": true,
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/@massalabs/wallet-provider/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==",
+ "peer": true
+ },
+ "node_modules/@massalabs/web3-utils": {
+ "version": "1.4.9",
+ "resolved": "https://registry.npmjs.org/@massalabs/web3-utils/-/web3-utils-1.4.9.tgz",
+ "integrity": "sha512-8G91gs6HqpPpR860QDUOzugr81WJTGkBgXQS1gq/oXqt16fPkw2xlsq4c2CFHDjRF9/ftE/JaybiNZ4ilcbEyg==",
+ "peer": true,
+ "dependencies": {
+ "bignumber.js": "^9.1.2",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "string_decoder": "^1.3.0"
+ }
+ },
+ "node_modules/@massalabs/web3-utils/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "peer": true,
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
"node_modules/@mdx-js/react": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.3.0.tgz",
@@ -3918,6 +4124,18 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/@noble/ed25519": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz",
+ "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "peer": true
+ },
"node_modules/@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
@@ -6851,6 +7069,12 @@
"integrity": "sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==",
"dev": true
},
+ "node_modules/@types/dot-object": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@types/dot-object/-/dot-object-2.1.6.tgz",
+ "integrity": "sha512-G1e4SNPOuO72ZXv7wz/W2x29CzQtpxko3G9hBiHqGg/AvFIKoArCs2nbc/WPXnnUkO+1dmvX9WQCyj5gIlAzZg==",
+ "dev": true
+ },
"node_modules/@types/ejs": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.3.tgz",
@@ -7096,7 +7320,7 @@
"version": "15.7.7",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.7.tgz",
"integrity": "sha512-FbtmBWCcSa2J4zL781Zf1p5YUBXQomPEcep9QZCfRfQgTxz3pJWiDFLebohZ9fFntX5ibzOkSsrJ0TEew8cAog==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/qs": {
"version": "6.9.8",
@@ -7114,7 +7338,7 @@
"version": "18.2.46",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.46.tgz",
"integrity": "sha512-nNCvVBcZlvX4NU1nRRNV/mFl1nNRuTuslAJglQsq+8ldXe5Xv0Wd2f7WTE3jOxhLH2BFfiZGC6GCp+kHQbgG+w==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -7143,7 +7367,7 @@
"version": "0.16.4",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz",
"integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==",
- "dev": true
+ "devOptional": true
},
"node_modules/@types/semver": {
"version": "7.5.3",
@@ -7578,6 +7802,47 @@
"web-streams-polyfill": "^3.1.1"
}
},
+ "node_modules/@web3pack/base-x": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@web3pack/base-x/-/base-x-1.0.2.tgz",
+ "integrity": "sha512-P3XgVnEQ1QFyUTmHzT1sXNprLyxE1aG8WAnk5/Fj+3j4AmsK4dRfMdV3t/aIdYP3i1KvjPRkQJhFXGpxUc+M8A==",
+ "peer": true
+ },
+ "node_modules/@web3pack/base58-check": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@web3pack/base58-check/-/base58-check-1.0.3.tgz",
+ "integrity": "sha512-+s4HKOnJbIkj45jhGfSxgWkKsjBENuNbfqASPTLPy/yjGGv/jGCxzFCl0fb4gudV3x0gS50gLpJsC8qQ6cV1gw==",
+ "peer": true,
+ "dependencies": {
+ "@web3pack/base-x": "^1.0.1",
+ "buffer": "^6.0.3",
+ "hash.js": "^1.1.7"
+ }
+ },
+ "node_modules/@web3pack/base58-check/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "peer": true,
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
"node_modules/@webassemblyjs/ast": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
@@ -8300,8 +8565,7 @@
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "dev": true
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/at-least-node": {
"version": "1.0.0",
@@ -8353,7 +8617,6 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
"integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
- "dev": true,
"engines": {
"node": ">= 0.4"
},
@@ -8376,6 +8639,15 @@
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==",
"dev": true
},
+ "node_modules/axios": {
+ "version": "0.26.1",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
+ "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
+ "peer": true,
+ "dependencies": {
+ "follow-redirects": "^1.14.8"
+ }
+ },
"node_modules/babel-core": {
"version": "7.0.0-bridge.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
@@ -8572,11 +8844,16 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
+ "node_modules/base-x": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz",
+ "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==",
+ "peer": true
+ },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -8631,6 +8908,15 @@
"node": "*"
}
},
+ "node_modules/bignumber.js": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
+ "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
+ "peer": true,
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -8650,6 +8936,15 @@
"wasm2js": "bin/wasm2js"
}
},
+ "node_modules/bip39": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz",
+ "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
+ "peer": true,
+ "dependencies": {
+ "@noble/hashes": "^1.2.0"
+ }
+ },
"node_modules/bl": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@@ -8805,6 +9100,25 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
}
},
+ "node_modules/bs58": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz",
+ "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==",
+ "peer": true,
+ "dependencies": {
+ "base-x": "^4.0.0"
+ }
+ },
+ "node_modules/bs58check": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz",
+ "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==",
+ "peer": true,
+ "dependencies": {
+ "@noble/hashes": "^1.2.0",
+ "bs58": "^5.0.0"
+ }
+ },
"node_modules/bser": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
@@ -8853,6 +9167,20 @@
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"devOptional": true
},
+ "node_modules/bufferutil": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz",
+ "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "node-gyp-build": "^4.3.0"
+ },
+ "engines": {
+ "node": ">=6.14.2"
+ }
+ },
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -8975,7 +9303,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
@@ -9367,7 +9694,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dev": true,
"dependencies": {
"delayed-stream": "~1.0.0"
},
@@ -9733,6 +10059,12 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+ "peer": true
+ },
"node_modules/crypto-random-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
@@ -10308,7 +10640,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "dev": true,
"engines": {
"node": ">=0.4.0"
}
@@ -10505,11 +10836,49 @@
"tslib": "^2.0.3"
}
},
+ "node_modules/dot-object": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/dot-object/-/dot-object-2.1.5.tgz",
+ "integrity": "sha512-xHF8EP4XH/Ba9fvAF2LDd5O3IITVolerVV6xvkxoM8zlGEiCUrggpAnHyOoKJKCrhvPcGATFAUwIujj7bRG5UA==",
+ "dependencies": {
+ "commander": "^6.1.0",
+ "glob": "^7.1.6"
+ },
+ "bin": {
+ "dot-object": "bin/dot-object"
+ }
+ },
+ "node_modules/dot-object/node_modules/commander": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/dot-object/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "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/dotenv": {
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz",
"integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==",
- "dev": true,
"engines": {
"node": ">=12"
},
@@ -11357,7 +11726,6 @@
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
- "dev": true,
"peer": true,
"engines": {
"node": ">=0.8.x"
@@ -11851,11 +12219,30 @@
"node": ">=0.4.0"
}
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
- "dev": true,
"dependencies": {
"is-callable": "^1.1.3"
}
@@ -11901,7 +12288,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
- "dev": true,
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
@@ -12045,7 +12431,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
- "dev": true,
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
@@ -12270,7 +12655,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
- "dev": true,
"dependencies": {
"get-intrinsic": "^1.1.3"
},
@@ -12372,7 +12756,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
- "dev": true,
"engines": {
"node": ">= 0.4"
},
@@ -12384,7 +12767,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "dev": true,
"engines": {
"node": ">= 0.4"
},
@@ -12396,7 +12778,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "dev": true,
"dependencies": {
"has-symbols": "^1.0.2"
},
@@ -12407,6 +12788,16 @@
"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==",
+ "peer": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "minimalistic-assert": "^1.0.1"
+ }
+ },
"node_modules/hosted-git-info": {
"version": "2.8.9",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
@@ -12558,7 +12949,6 @@
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -12794,7 +13184,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
- "dev": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -12868,7 +13257,6 @@
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "dev": true,
"engines": {
"node": ">= 0.4"
},
@@ -12965,7 +13353,6 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
- "dev": true,
"dependencies": {
"has-tostringtag": "^1.0.0"
},
@@ -13185,7 +13572,6 @@
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz",
"integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
- "dev": true,
"dependencies": {
"which-typed-array": "^1.1.11"
},
@@ -15369,6 +15755,12 @@
"integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==",
"dev": true
},
+ "node_modules/js-base64": {
+ "version": "3.7.7",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz",
+ "integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==",
+ "peer": true
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -16691,7 +17083,6 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true,
"engines": {
"node": ">= 0.6"
}
@@ -16700,7 +17091,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
"dependencies": {
"mime-db": "1.52.0"
},
@@ -16734,6 +17124,12 @@
"node": ">=15.14.0"
}
},
+ "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==",
+ "peer": true
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -16990,6 +17386,18 @@
"webidl-conversions": "^3.0.0"
}
},
+ "node_modules/node-gyp-build": {
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
+ "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
+ "optional": true,
+ "peer": true,
+ "bin": {
+ "node-gyp-build": "bin.js",
+ "node-gyp-build-optional": "optional.js",
+ "node-gyp-build-test": "build-test.js"
+ }
+ },
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -19068,7 +19476,6 @@
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -19638,7 +20045,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "dev": true,
"dependencies": {
"safe-buffer": "~5.2.0"
}
@@ -20560,6 +20966,18 @@
"node": ">=0.8.0"
}
},
+ "node_modules/uid": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz",
+ "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==",
+ "peer": true,
+ "dependencies": {
+ "@lukeed/csprng": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/undici": {
"version": "5.28.4",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz",
@@ -20818,11 +21236,32 @@
}
}
},
+ "node_modules/use-sync-external-store": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+ "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/utf-8-validate": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.4.tgz",
+ "integrity": "sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==",
+ "hasInstallScript": true,
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "node-gyp-build": "^4.3.0"
+ },
+ "engines": {
+ "node": ">=6.14.2"
+ }
+ },
"node_modules/util": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
"integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==",
- "dev": true,
"dependencies": {
"inherits": "^2.0.3",
"is-arguments": "^1.0.4",
@@ -20888,6 +21327,12 @@
"spdx-expression-parse": "^3.0.0"
}
},
+ "node_modules/varint": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz",
+ "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==",
+ "peer": true
+ },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -21347,7 +21792,6 @@
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz",
"integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==",
- "dev": true,
"dependencies": {
"available-typed-arrays": "^1.0.5",
"call-bind": "^1.0.2",
@@ -21621,6 +22065,33 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
+ },
+ "node_modules/zustand": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz",
+ "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==",
+ "dependencies": {
+ "use-sync-external-store": "1.2.0"
+ },
+ "engines": {
+ "node": ">=12.7.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=16.8",
+ "immer": ">=9.0.6",
+ "react": ">=16.8"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ }
+ }
}
}
}
diff --git a/package.json b/package.json
index e2ceab9f..93c8afac 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@massalabs/react-ui-kit",
- "version": "0.0.3",
+ "version": "0.0.4",
"type": "module",
"files": ["src", "presets"],
"main": "src/index.ts",
@@ -28,6 +28,7 @@
"@headlessui/react": "^1.7.15",
"copy-to-clipboard": "^3.3.3",
"currency.js": "^2.0.4",
+ "dot-object": "^2.1.5",
"minidenticons": "^4.2.1",
"react": "^18.2.0",
"react-currency-input-field": "^3.6.11",
@@ -37,7 +38,12 @@
"react-number-format": "^5.2.2",
"tw-colors": "^1.2.5",
"viem": "^1.5.2",
- "vite-plugin-svgr": "^3.2.0"
+ "vite-plugin-svgr": "^3.2.0",
+ "zustand": "^4.5.2"
+ },
+ "peerDependencies": {
+ "@massalabs/massa-web3": "^4.0.2-dev",
+ "@massalabs/wallet-provider": "^2.0.1-dev"
},
"devDependencies": {
"@babel/preset-env": "^7.21.4",
@@ -57,6 +63,7 @@
"@testing-library/dom": "^9.2.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
+ "@types/dot-object": "^2.1.6",
"@types/jest": "^29.5.1",
"@types/react": "^18.2.46",
"@types/react-dom": "^18.0.11",
diff --git a/scripts/publish-dev.sh b/scripts/publish-dev.sh
index 0f03eaa4..4eb90575 100755
--- a/scripts/publish-dev.sh
+++ b/scripts/publish-dev.sh
@@ -3,14 +3,16 @@ set -e
NPM_PACKAGE=$(cat package.json | jq -r '.name')
-npm version --preid dev --no-git-tag-version --no-commit-hooks prepatch
+TAG=dev
+
+npm version --preid $TAG --no-git-tag-version --no-commit-hooks prepatch
#Use timestamp as package suffix
TIME=$(date -u +%Y%m%d%H%M%S)
-sed -i "/version/s/dev.0/dev.$TIME/g" package.json
+sed -i "/version/s/$TAG.0/$TAG.$TIME/g" package.json
PUBLISH_VERSION=$(cat package.json | jq -r '.version')
echo publishing $NPM_PACKAGE@$PUBLISH_VERSION
# disable husky
npm pkg delete scripts.prepare
-npm publish --access public --tag dev
+npm publish --access public --tag $TAG
diff --git a/src/components/DollarValue/DollarValue.tsx b/src/components/DollarValue/DollarValue.tsx
index a1b2a999..47cb66db 100644
--- a/src/components/DollarValue/DollarValue.tsx
+++ b/src/components/DollarValue/DollarValue.tsx
@@ -4,7 +4,7 @@ import React from 'react';
import { ComponentPropsWithoutRef } from 'react';
import { FiAlertTriangle } from 'react-icons/fi';
import { Tooltip } from '../Tooltip';
-import { formatFTAmount, parseAmount } from '../../util/parseAmount';
+import { formatFTAmount, parseAmount } from '../../lib/util/parseAmount';
export interface DollarValueProps extends ComponentPropsWithoutRef<'p'> {
dollarValue?: string;
@@ -17,7 +17,7 @@ export function DollarValue(props: DollarValueProps) {
if (dollarValueError) {
return (
-
-
+
);
}
diff --git a/src/components/Dropdown/Dropdown.tsx b/src/components/Dropdown/Dropdown.tsx
index a639adee..df387a0b 100644
--- a/src/components/Dropdown/Dropdown.tsx
+++ b/src/components/Dropdown/Dropdown.tsx
@@ -4,7 +4,7 @@ import React, { ReactNode, useEffect, useRef } from 'react';
import { ComponentPropsWithoutRef, useState, MouseEvent } from 'react';
import { FiChevronDown, FiChevronUp } from 'react-icons/fi';
-import useClickOutside from '../../util/useClickOutside';
+import useClickOutside from '../../lib/util/hooks/useClickOutside';
export interface IOption extends ComponentPropsWithoutRef<'div'> {
icon?: ReactNode;
diff --git a/src/components/Icons/Svg/Massa/StationLogo.tsx b/src/components/Icons/Svg/Massa/StationLogo.tsx
index 62051629..ce452712 100644
--- a/src/components/Icons/Svg/Massa/StationLogo.tsx
+++ b/src/components/Icons/Svg/Massa/StationLogo.tsx
@@ -3,7 +3,7 @@
import React from 'react';
import { ComponentPropsWithoutRef } from 'react';
-import { Theme } from '../../../../util/types';
+import { Theme } from '../../../ThemeMode';
interface SVGProps extends ComponentPropsWithoutRef<'div'> {
theme?: Theme | undefined;
diff --git a/src/components/Plugin/Plugin.tsx b/src/components/Plugin/Plugin.tsx
index 09ae90c8..bca322a1 100644
--- a/src/components/Plugin/Plugin.tsx
+++ b/src/components/Plugin/Plugin.tsx
@@ -4,7 +4,7 @@ import React, { useState } from 'react';
import { ReactNode, cloneElement } from 'react';
import { IconContext } from 'react-icons/lib';
-import { truncate } from '../../util/truncate';
+import { truncate } from '../../lib/util/truncate';
export interface PluginProps {
preIcon: JSX.Element;
diff --git a/src/components/RedirectTile/RedirectTile.tsx b/src/components/RedirectTile/RedirectTile.tsx
index 0c8021e9..9cad37bf 100644
--- a/src/components/RedirectTile/RedirectTile.tsx
+++ b/src/components/RedirectTile/RedirectTile.tsx
@@ -3,7 +3,7 @@
import React from 'react';
import { ComponentPropsWithoutRef } from 'react';
-import { openInNewTab } from '../../util/utils';
+import { openInNewTab } from '../../lib/util/utils';
export interface RedirectTileProps extends ComponentPropsWithoutRef<'div'> {
customClass?: string;
diff --git a/src/components/Tag/Tag.tsx b/src/components/Tag/Tag.tsx
index 42567cc6..c97aa22a 100644
--- a/src/components/Tag/Tag.tsx
+++ b/src/components/Tag/Tag.tsx
@@ -2,6 +2,13 @@
// @ts-ignore
import React, { ComponentPropsWithoutRef } from 'react';
+export const tagTypes = {
+ success: 'success',
+ error: 'error',
+ warning: 'warning',
+ info: 'info',
+};
+
interface TagProps extends ComponentPropsWithoutRef<'div'> {
type: string;
children: React.ReactNode;
diff --git a/src/components/ThemeMode/ThemeMode.tsx b/src/components/ThemeMode/ThemeMode.tsx
index 28026178..45d1e76e 100644
--- a/src/components/ThemeMode/ThemeMode.tsx
+++ b/src/components/ThemeMode/ThemeMode.tsx
@@ -4,8 +4,9 @@ import React from 'react';
import { useState } from 'react';
import { FiMoon, FiSun } from 'react-icons/fi';
-import { useLocalStorage } from '../../util/useLocalStorage';
-import { Theme } from '../../util/types';
+import { useLocalStorage } from '../../lib/util/hooks/useLocalStorage';
+
+export type Theme = 'theme-light' | 'theme-dark';
interface ThemeProps {
onSetTheme?: (theme: Theme) => void;
diff --git a/src/components/Token/Token.tsx b/src/components/Token/Token.tsx
index f7d6e48f..c4e8d6cc 100644
--- a/src/components/Token/Token.tsx
+++ b/src/components/Token/Token.tsx
@@ -5,8 +5,8 @@ import { ComponentPropsWithoutRef } from 'react';
import { FiTrash2 } from 'react-icons/fi';
import { Button } from '../Button';
import { Tooltip } from '../Tooltip';
-import { formatFTAmount } from '../../util/parseAmount';
import { DollarValue } from '../DollarValue';
+import { formatFTAmount } from '../../lib/util/parseAmount';
export interface TokenProps extends ComponentPropsWithoutRef<'div'> {
logo?: React.ReactNode;
diff --git a/src/index.ts b/src/index.ts
index e49f6f83..3c098200 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,3 @@
export * from './components';
import './global.css';
-export * from './util/types';
-export * from './util/parseAmount';
+export * from './lib/util/parseAmount';
diff --git a/src/lib/ConnectMassaWallets/components/BearbySvg.tsx b/src/lib/ConnectMassaWallets/components/BearbySvg.tsx
new file mode 100644
index 00000000..3e3485e1
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/BearbySvg.tsx
@@ -0,0 +1,39 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+/* eslint-disable max-len */
+export function BearbySvg() {
+ return (
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/BearbyWallet.tsx b/src/lib/ConnectMassaWallets/components/BearbyWallet.tsx
new file mode 100644
index 00000000..8d60fc63
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/BearbyWallet.tsx
@@ -0,0 +1,33 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { ConnectedAccount } from './ConnectedAccount';
+import { MASBalance } from './MASBalance';
+import { WalletError } from './WalletError';
+import Intl from '../i18n';
+import { useAccountStore } from '../store';
+import { BEARBY_INSTALL } from '../../massa-react/const';
+
+export default function BearbyWallet() {
+ const { connectedAccount } = useAccountStore();
+
+ if (connectedAccount) {
+ return (
+
+
+
+
+ );
+ }
+
+ return (
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.stories.tsx b/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.stories.tsx
new file mode 100644
index 00000000..0b4a456d
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.stories.tsx
@@ -0,0 +1,14 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { ConnectMassaWallet } from './ConnectMassaWallet';
+
+export default {
+ title: 'Lib/ConnectMassaWallet',
+ component: ConnectMassaWallet,
+};
+
+export const _ConnectMassaWallet = {
+ render: () => ,
+};
diff --git a/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.tsx b/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.tsx
new file mode 100644
index 00000000..40313166
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/ConnectMassaWallet.tsx
@@ -0,0 +1,114 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { useEffect, useState } from 'react';
+
+import { BearbySvg } from './BearbySvg';
+import BearbyWallet from './BearbyWallet';
+import SelectMassaWallet from './SelectMassaWallet';
+import StationWallet from './StationWallet';
+import { ChainStatus } from './Status/ChainStatus';
+import SwitchWalletButton from './SwitchWalletButton';
+import Intl from '../i18n';
+import { useAccountStore } from '../store';
+import { MassaWallet, Tooltip } from '../../../components';
+import { SUPPORTED_MASSA_WALLETS } from '../../massa-react/const';
+
+export const ConnectMassaWallet = () => {
+ const { currentProvider, providers, setCurrentProvider, isFetching } =
+ useAccountStore();
+
+ const [selectedProvider, setSelectedProvider] = useState<
+ SUPPORTED_MASSA_WALLETS | undefined
+ >(currentProvider?.name() as SUPPORTED_MASSA_WALLETS);
+
+ useEffect(() => {
+ const provider = providers.find((p) => p.name() === selectedProvider);
+ if (provider && !currentProvider) {
+ setCurrentProvider(provider);
+ }
+ }, [providers, selectedProvider, currentProvider, setCurrentProvider]);
+
+ function renderWallet() {
+ switch (selectedProvider) {
+ case SUPPORTED_MASSA_WALLETS.MASSASTATION:
+ return ;
+ case SUPPORTED_MASSA_WALLETS.BEARBY:
+ return ;
+ default:
+ // Should not happen
+ return <>Error: no wallet selected>;
+ }
+ }
+
+ function renderSelectedWallet() {
+ switch (selectedProvider) {
+ case SUPPORTED_MASSA_WALLETS.MASSASTATION:
+ return (
+ <>
+
+ {Intl.t(`connect-wallet.${SUPPORTED_MASSA_WALLETS.MASSASTATION}`)}
+ >
+ );
+ case SUPPORTED_MASSA_WALLETS.BEARBY:
+ return (
+ <>
+
+ {Intl.t(`connect-wallet.${SUPPORTED_MASSA_WALLETS.BEARBY}`)}
+ >
+ );
+ }
+ }
+
+ const noWalletSelected = !selectedProvider || isFetching;
+
+ function renderNoWalletSelected() {
+ return (
+ {
+ setSelectedProvider(providerName);
+ const provider = providers.find((p) => p.name() === providerName);
+ if (provider) {
+ setCurrentProvider(provider);
+ }
+ }}
+ />
+ );
+ }
+
+ return (
+
+ {noWalletSelected ? (
+ renderNoWalletSelected()
+ ) : (
+ <>
+
+
+ {renderSelectedWallet()}
+
+ {selectedProvider === SUPPORTED_MASSA_WALLETS.BEARBY && (
+
+ )}
+
+
{
+ setSelectedProvider(undefined);
+ setCurrentProvider();
+ }}
+ />
+
+ {renderWallet()}
+ >
+ )}
+
+ );
+};
diff --git a/src/lib/ConnectMassaWallets/components/ConnectedAccount.tsx b/src/lib/ConnectMassaWallets/components/ConnectedAccount.tsx
new file mode 100644
index 00000000..dd00a2db
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/ConnectedAccount.tsx
@@ -0,0 +1,29 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { Clipboard } from '../../../components';
+import { maskAddress } from '../../massa-react/utils';
+import { useAccountStore } from '../store';
+
+interface ConnectedAccountProps {
+ maskLength?: number;
+}
+
+export function ConnectedAccount(props: ConnectedAccountProps) {
+ const { maskLength } = props;
+ const { connectedAccount } = useAccountStore();
+
+ return (
+
+
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/MASBalance.tsx b/src/lib/ConnectMassaWallets/components/MASBalance.tsx
new file mode 100644
index 00000000..ecb08224
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/MASBalance.tsx
@@ -0,0 +1,46 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { useEffect, useState } from 'react';
+
+import { fromMAS } from '@massalabs/massa-web3';
+import { IAccountBalanceResponse } from '@massalabs/wallet-provider';
+
+import Intl from '../i18n';
+import { useAccountStore } from '../store';
+import { FetchingLine } from '../../../components';
+import { fetchMASBalance } from '../../massa-react/utils';
+import { massaToken } from '../../massa-react/const';
+import { formatAmount } from '../../util/parseAmount';
+
+export function MASBalance() {
+ const [balance, setBalance] = useState();
+
+ const { connectedAccount } = useAccountStore();
+
+ useEffect(() => {
+ if (!connectedAccount) return;
+ fetchMASBalance(connectedAccount).then((balance) => {
+ setBalance(balance);
+ });
+ }, [connectedAccount, setBalance]);
+
+ const formattedBalance = formatAmount(
+ fromMAS(balance?.candidateBalance || '0').toString(),
+ 9,
+ ).amountFormattedFull;
+
+ return (
+
+ {Intl.t('connect-wallet.connected-cards.wallet-balance')}
+ {balance === undefined ? (
+
+ ) : (
+ <>
+ {formattedBalance} {massaToken}
+ >
+ )}
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/OperationToast.tsx b/src/lib/ConnectMassaWallets/components/OperationToast.tsx
new file mode 100644
index 00000000..5a927d38
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/OperationToast.tsx
@@ -0,0 +1,34 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import Intl from '../i18n';
+import { generateExplorerLink } from '../../massa-react/utils';
+
+type OperationToastProps = {
+ title: string;
+ operationId?: string;
+ isMainnet?: boolean;
+};
+
+export function OperationToast({
+ title,
+ operationId,
+ isMainnet,
+}: OperationToastProps) {
+ return (
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/SelectMassaWallet.tsx b/src/lib/ConnectMassaWallets/components/SelectMassaWallet.tsx
new file mode 100644
index 00000000..dfa59f0b
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/SelectMassaWallet.tsx
@@ -0,0 +1,55 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { BearbySvg } from './BearbySvg';
+import { Disconnected } from './Status/Disconnected';
+import Intl from '../i18n';
+import { Dropdown, MassaWallet } from '../../../components';
+import { SUPPORTED_MASSA_WALLETS } from '../../massa-react/const';
+
+const walletList = [
+ {
+ name: SUPPORTED_MASSA_WALLETS.MASSASTATION,
+ icon: ,
+ },
+ {
+ name: SUPPORTED_MASSA_WALLETS.BEARBY,
+ icon: ,
+ },
+];
+
+interface SelectMassaWalletProps {
+ onClick: (providerName: SUPPORTED_MASSA_WALLETS) => void;
+}
+
+const SelectMassaWallet = ({ onClick }: SelectMassaWalletProps) => {
+ const walletOptions = () => {
+ return walletList.map((provider) => ({
+ item: Intl.t(`connect-wallet.${provider.name}`),
+ icon: provider.icon,
+ onClick: () => onClick(provider.name),
+ }));
+ };
+
+ return (
+ <>
+
+
+ {Intl.t('connect-wallet.card-destination.to')}
+
+
+
+
+
+
+ >
+ );
+};
+
+export default SelectMassaWallet;
diff --git a/src/lib/ConnectMassaWallets/components/StationSelectAccount.tsx b/src/lib/ConnectMassaWallets/components/StationSelectAccount.tsx
new file mode 100644
index 00000000..d3479fa3
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/StationSelectAccount.tsx
@@ -0,0 +1,38 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { IAccount } from '@massalabs/wallet-provider';
+
+import { useAccountStore } from '../store';
+import { Dropdown } from '../../../components';
+
+export function StationSelectAccount() {
+ const [accounts, connectedAccount, setConnectedAccount] = useAccountStore(
+ (state) => [
+ state.accounts,
+ state.connectedAccount,
+ state.setConnectedAccount,
+ ],
+ );
+
+ const selectedAccountKey: number = (accounts || []).findIndex(
+ (account) => account.name() === connectedAccount?.name(),
+ );
+
+ const onAccountChange = async (account: IAccount) => {
+ setConnectedAccount(account);
+ };
+
+ return (
+ {
+ return {
+ item: account.name(),
+ onClick: () => onAccountChange(account),
+ };
+ })}
+ />
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/StationWallet.tsx b/src/lib/ConnectMassaWallets/components/StationWallet.tsx
new file mode 100644
index 00000000..3d420d26
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/StationWallet.tsx
@@ -0,0 +1,98 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { useEffect, useState } from 'react';
+
+import {
+ isMassaStationAvailable,
+ isMassaWalletEnabled,
+} from '@massalabs/wallet-provider';
+
+import { ConnectedAccount } from './ConnectedAccount';
+import { MASBalance } from './MASBalance';
+import { StationSelectAccount } from './StationSelectAccount';
+import { WalletError } from './WalletError';
+import {
+ MASSA_STATION_INSTALL,
+ MASSA_STATION_STORE,
+ MASSA_WALLET_CREATE_ACCOUNT,
+} from '../../massa-react/const';
+import Intl from '../i18n';
+import { useAccountStore } from '../store';
+
+export default function StationWallet() {
+ const { accounts } = useAccountStore();
+
+ const [stationIsOn, setStationIsOn] = useState(
+ undefined,
+ );
+ const [massaWalletIsOn, setMassaWalletIsOn] = useState(
+ undefined,
+ );
+
+ useEffect(() => {
+ isMassaStationAvailable().then((result) => {
+ setStationIsOn(result);
+ });
+ isMassaWalletEnabled().then((result) => {
+ setMassaWalletIsOn(result);
+ });
+ });
+
+ if (stationIsOn === false) {
+ return (
+
+ );
+ }
+
+ if (massaWalletIsOn === false) {
+ return (
+
+ );
+ }
+
+ if (accounts !== undefined && !accounts.length) {
+ return (
+
+ );
+ }
+
+ if (accounts === undefined) {
+ return ;
+ }
+
+ return (
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/Status/ChainStatus.tsx b/src/lib/ConnectMassaWallets/components/Status/ChainStatus.tsx
new file mode 100644
index 00000000..ab0053dd
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/Status/ChainStatus.tsx
@@ -0,0 +1,15 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { Connected } from './Connected';
+import { Disconnected } from './Disconnected';
+import { useAccountStore } from '../../store';
+
+export function ChainStatus() {
+ const { connectedAccount, currentProvider } = useAccountStore();
+
+ const connected = !!connectedAccount && !!currentProvider;
+
+ return <>{connected ? : }>;
+}
diff --git a/src/lib/ConnectMassaWallets/components/Status/Connected.tsx b/src/lib/ConnectMassaWallets/components/Status/Connected.tsx
new file mode 100644
index 00000000..92d83a5f
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/Status/Connected.tsx
@@ -0,0 +1,12 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import { Tag, tagTypes } from '../../../../components';
+import Intl from '../../i18n';
+
+export function Connected() {
+ return (
+ {Intl.t('connect-wallet.tag.connected')}
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/Status/Disconnected.tsx b/src/lib/ConnectMassaWallets/components/Status/Disconnected.tsx
new file mode 100644
index 00000000..6e53eade
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/Status/Disconnected.tsx
@@ -0,0 +1,14 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import Intl from '../../i18n';
+import { Tag, tagTypes } from '../../../../components';
+
+export function Disconnected() {
+ return (
+
+ {Intl.t('connect-wallet.tag.not-connected')}
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/SwitchWalletButton.tsx b/src/lib/ConnectMassaWallets/components/SwitchWalletButton.tsx
new file mode 100644
index 00000000..ab165859
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/SwitchWalletButton.tsx
@@ -0,0 +1,22 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+import Intl from '../i18n';
+
+export default function SwitchWalletButton({
+ onClick,
+}: {
+ onClick: () => void;
+}) {
+ return (
+
+
+ {Intl.t('connect-wallet.card-destination.switch')}
+
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/components/WalletError.tsx b/src/lib/ConnectMassaWallets/components/WalletError.tsx
new file mode 100644
index 00000000..aea80cd7
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/components/WalletError.tsx
@@ -0,0 +1,27 @@
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+import React from 'react';
+
+interface WalletErrorProps {
+ description: string;
+ link: string;
+ linkLabel: string;
+}
+
+export function WalletError(props: WalletErrorProps) {
+ const { description, link, linkLabel } = props;
+
+ return (
+
+ );
+}
diff --git a/src/lib/ConnectMassaWallets/i18n/en_US.json b/src/lib/ConnectMassaWallets/i18n/en_US.json
new file mode 100644
index 00000000..590b436b
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/i18n/en_US.json
@@ -0,0 +1,51 @@
+{
+ "toast": {
+ "explorer": "view in explorer"
+ },
+ "connect-wallet": {
+ "title": "Connect wallets",
+ "connected": "Connected wallets",
+ "description": "Connect wallets for {network1} and {network2}, to bridge tokens.",
+ "button": "Connect",
+ "card-destination": {
+ "from": "Ethereum wallet",
+ "to": "Massa wallet",
+ "non-massa-wallet": "Switch accounts directly within your wallet.",
+ "switch": "switch wallet",
+ "select-wallet": "Select wallet",
+ "your-wallet": "Your wallet",
+ "bearby-not-installed": "Bearby extension is either turned off or not installed. Make sure the extension is on and refresh the page.",
+ "get-bearby": "Get Bearby here",
+ "massa-station-not-detected": "Massa Station desktop app is not detected. Make sure the app is opened, or click below to install it.",
+ "get-massa-station": "Get Massa Station",
+ "massa-wallet-not-detected": "Massa Wallet is not detected. Make sure the plugin is installed, or click below to install it.",
+ "get-massa-wallet": "Get Massa Wallet",
+ "massa-wallet-no-account": "No wallet accounts found in Massa Wallet.",
+ "massa-wallet-create-account": "Create an account",
+ "not-detected": "wallet is not detected."
+ },
+ "MASSASTATION": "MassaWallet",
+ "BEARBY": "Bearby",
+ "connected-cards": {
+ "wallet-balance": "Balance: "
+ },
+ "connect-massa": {
+ "unsupported-net": "Switch to 'buildnet' in top-right corner of Station's homepage"
+ },
+ "wrong-chain": "Wrong wallet network. Please, switch to {network} in your {name} wallet settings.",
+ "connect-metamask": {
+ "connect-to-metamask": "Connect to Metamask",
+ "invalid-network": "Current network is not supported. Please, switch to {network}.",
+ "switch-network": "Switch network",
+ "no-metamask": "It seems like you don't have Metamask installed.",
+ "install-metamask": "Install Metamask"
+ },
+ "tag": {
+ "not-connected": "Not connected",
+ "connected": "Connected",
+ "wrong-chain": "Unsupported network",
+ "wrong-chain-massa-station-tooltip": "Switch to {network} in top-right corner of Station's homepage",
+ "wrong-chain-bearby-tooltip": "Switch to {network} in top-left corner of Bearby's extension"
+ }
+ }
+}
diff --git a/src/lib/ConnectMassaWallets/i18n/index.ts b/src/lib/ConnectMassaWallets/i18n/index.ts
new file mode 100644
index 00000000..e49a2319
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/i18n/index.ts
@@ -0,0 +1,7 @@
+import I18n from '../../i18n/i18n';
+import enUs from './en_US.json';
+
+const Intl = new I18n({ EN_us: enUs });
+Object.freeze(Intl);
+
+export default Intl;
diff --git a/src/lib/ConnectMassaWallets/index.ts b/src/lib/ConnectMassaWallets/index.ts
new file mode 100644
index 00000000..f33e76b8
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/index.ts
@@ -0,0 +1,2 @@
+export { useAccountStore } from './store';
+export { ConnectMassaWallet } from './components/ConnectMassaWallet';
diff --git a/src/lib/ConnectMassaWallets/store/accountStore.ts b/src/lib/ConnectMassaWallets/store/accountStore.ts
new file mode 100644
index 00000000..c0aefc5a
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/store/accountStore.ts
@@ -0,0 +1,194 @@
+import { Client, ClientFactory } from '@massalabs/massa-web3';
+import { IAccount, IProvider } from '@massalabs/wallet-provider';
+
+import { SUPPORTED_MASSA_WALLETS } from '../../massa-react/const';
+
+async function handleBearbyAccountChange(
+ newAddress: string,
+ store: AccountStoreState,
+) {
+ const { connectedAccount, currentProvider, setConnectedAccount } = store;
+
+ const oldAddress = connectedAccount?.address();
+
+ if (newAddress !== oldAddress) {
+ const newAccounts = await currentProvider?.accounts();
+
+ if (newAccounts?.length) {
+ // Bearby returns only one account
+ const newAccount = newAccounts[0];
+ setConnectedAccount(newAccount);
+ }
+ }
+}
+
+export interface AccountStoreState {
+ connectedAccount?: IAccount;
+ massaClient?: Client;
+ accounts?: IAccount[];
+ currentProvider?: IProvider;
+ providers: IProvider[];
+ isFetching: boolean;
+ accountObserver?: {
+ unsubscribe: () => void;
+ };
+ networkObserver?: {
+ unsubscribe: () => void;
+ };
+ chainId?: bigint;
+
+ setCurrentProvider: (provider?: IProvider) => void;
+ setProviders: (providers: IProvider[]) => void;
+
+ setConnectedAccount: (account?: IAccount) => void;
+ refreshMassaClient: () => void;
+}
+
+const accountStore = (
+ set: (params: Partial) => void,
+ get: () => AccountStoreState,
+) => ({
+ accounts: undefined,
+ connectedAccount: undefined,
+ accountObserver: undefined,
+ networkObserver: undefined,
+ massaClient: undefined,
+ currentProvider: undefined,
+ providers: [],
+ isFetching: false,
+ chainId: undefined,
+
+ setCurrentProvider: (currentProvider?: IProvider) => {
+ try {
+ set({ isFetching: true });
+
+ const previousProvider = get().currentProvider;
+
+ if (previousProvider?.name() !== currentProvider?.name()) {
+ get().accountObserver?.unsubscribe();
+ get().networkObserver?.unsubscribe();
+ set({ accountObserver: undefined, networkObserver: undefined });
+ }
+ if (!currentProvider) {
+ set({
+ currentProvider: undefined,
+ connectedAccount: undefined,
+ accounts: undefined,
+ });
+ return;
+ }
+
+ if (!get().networkObserver) {
+ const networkObserver = currentProvider.listenNetworkChanges(
+ async () => {
+ get().refreshMassaClient();
+ set({ chainId: await currentProvider.getChainId() });
+ },
+ );
+ set({ networkObserver });
+ }
+
+ if (currentProvider?.name() === SUPPORTED_MASSA_WALLETS.BEARBY) {
+ currentProvider
+ .connect()
+ .then(() => {
+ // get current network
+ currentProvider
+ .getChainId()
+ .then((chainId) => {
+ set({ chainId });
+ })
+ .catch((error) => {
+ console.warn('error getting network from bearby', error);
+ });
+ // subscribe to network events
+ const observer = currentProvider.listenAccountChanges(
+ (newAddress: string) => {
+ handleBearbyAccountChange(newAddress, get());
+ },
+ );
+ set({ currentProvider, accountObserver: observer });
+
+ // get connected account
+ currentProvider
+ .accounts()
+ .then((accounts) => {
+ // bearby expose only 1 account
+ get().setConnectedAccount(accounts[0]);
+ set({ accounts });
+ })
+ .catch((error) => {
+ console.warn('error getting accounts from bearby', error);
+ });
+ })
+ .catch((error) => {
+ console.warn('error connecting to bearby', error);
+ });
+ return;
+ }
+
+ set({ currentProvider });
+
+ currentProvider
+ .accounts()
+ .then((accounts) => {
+ set({ accounts });
+
+ const selectedAccount = accounts[0];
+ get().setConnectedAccount(selectedAccount);
+ })
+ .catch((error) => {
+ console.warn('error getting accounts from provider', error);
+ });
+ } finally {
+ set({ isFetching: false });
+ }
+ },
+
+ setProviders: (providers: IProvider[]) => {
+ set({ providers });
+
+ // if current provider is not in the new list of providers, unset it
+ if (!providers.some((p) => p.name() === get().currentProvider?.name())) {
+ set({
+ massaClient: undefined,
+ currentProvider: undefined,
+ connectedAccount: undefined,
+ accounts: undefined,
+ });
+ }
+ },
+
+ // set the connected account, and update the massa client
+ setConnectedAccount: async (connectedAccount?: IAccount) => {
+ set({ connectedAccount });
+ if (connectedAccount) {
+ const currentProvider = get().currentProvider;
+ if (!currentProvider) throw new Error('No provider found');
+ const provider = currentProvider;
+ // update the massa client with the new account
+ set({
+ massaClient: await ClientFactory.fromWalletProvider(
+ provider,
+ connectedAccount,
+ ),
+ });
+ }
+ },
+
+ refreshMassaClient: async () => {
+ const provider = get().currentProvider;
+ if (!provider) return;
+
+ const connectedAccount = get().connectedAccount;
+ if (!connectedAccount) return;
+ set({
+ massaClient: await ClientFactory.fromWalletProvider(
+ provider,
+ connectedAccount,
+ ),
+ });
+ },
+});
+
+export default accountStore;
diff --git a/src/lib/ConnectMassaWallets/store/index.ts b/src/lib/ConnectMassaWallets/store/index.ts
new file mode 100644
index 00000000..3e68babe
--- /dev/null
+++ b/src/lib/ConnectMassaWallets/store/index.ts
@@ -0,0 +1,20 @@
+import { ProvidersListener } from '@massalabs/wallet-provider';
+import { create } from 'zustand';
+
+import accountStore, { AccountStoreState } from './accountStore';
+
+export const useAccountStore = create((set, get) => ({
+ ...accountStore(set, get),
+}));
+
+async function initAccountStore() {
+ new ProvidersListener(4_000).subscribe((providers) => {
+ useAccountStore.getState().setProviders(providers);
+ });
+}
+
+async function initializeStores() {
+ await initAccountStore();
+}
+
+initializeStores();
diff --git a/src/lib/README.MD b/src/lib/README.MD
new file mode 100644
index 00000000..dcf48c30
--- /dev/null
+++ b/src/lib/README.MD
@@ -0,0 +1,47 @@
+# Massa React UI-KIT libraries
+
+This directory contains the React UI-KIT libraries that are used in Massa projects.
+
+## i18n
+
+**You can use it to translate the text in the project.**
+
+Use it like this:
+
+```typescript
+import I18n from '@massalabs/react-ui-kit/lib/i18n';
+// create a json file to store the text you want to translate:
+import enUs from './en_US.json';
+
+const Intl = new I18n({ EN_us: enUs });
+Object.freeze(Intl);
+
+export default Intl;
+```
+
+See the example in the `ConnectMassaWallets` lib.
+
+Future development: allow to change the language in the dapp.
+
+## ConnectMassaWallets
+
+- contains components that are used to connect to Massa wallets.
+- contains a store that you can use in your dapp.
+- use the lib i18n to translate the text in the components.
+
+## massa-react
+
+**Oriented to the interactions with Massa blockchain.**
+
+- contains hooks that you can use in your dapp.
+- contains utility functions that you can use in your dapp.
+- contains constants that you can use in your dapp.
+- use the lib i18n to translate the text in the hooks.
+
+## Util
+
+**General UI utility functions.**
+
+- contains utility functions to format amount
+- contains utility functions that you can use in your dapp.
+- contains hooks that you can use in your dapp.
diff --git a/src/lib/i18n/i18n.ts b/src/lib/i18n/i18n.ts
new file mode 100644
index 00000000..710ae627
--- /dev/null
+++ b/src/lib/i18n/i18n.ts
@@ -0,0 +1,47 @@
+import dot from 'dot-object';
+
+type TranslationObject = string | { [key: string]: TranslationObject };
+
+export type Copy = Record;
+export type Language = string;
+export type Keys = Record;
+
+class I18n {
+ private lang: Language;
+ private copy: Copy;
+
+ constructor(keys: Keys, lang = 'EN_us') {
+ this.lang = lang;
+ this.copy = keys[this.lang];
+ }
+
+ public t(key: string, interpolations?: Record): string {
+ const copy = this.copy;
+ // we are using pick in order to make life easier when the day for plurals and copy with params arrives
+ const result = dot.pick(key, copy);
+
+ if (!result) {
+ console.warn(`I18n::t:: No translation found for key ${key}`);
+ }
+
+ return interpolations
+ ? this._interpolateKeys(result, interpolations)
+ : result ?? key;
+ }
+
+ private _interpolateKeys(
+ str: string,
+ replacements: Record,
+ char1 = '{',
+ char2 = '}',
+ ): string {
+ const regex = new RegExp(`${char1}[^${char2}]*${char2}`, 'g');
+
+ return str.replace(regex, (match) => {
+ const key = match.slice(1, -1);
+ return replacements[key] ?? match;
+ });
+ }
+}
+
+export default I18n;
diff --git a/src/lib/massa-react/const.ts b/src/lib/massa-react/const.ts
new file mode 100644
index 00000000..7bf80ea6
--- /dev/null
+++ b/src/lib/massa-react/const.ts
@@ -0,0 +1,17 @@
+export const MASSA = 'Massa';
+
+export const MASSA_STATION_INSTALL = 'https://station.massa.net';
+export const MASSA_STATION_STORE = 'https://station.massa/web/store';
+export const MASSA_WALLET_CREATE_ACCOUNT =
+ 'http://station.massa/plugin/massa-labs/massa-wallet/web-app/account-create';
+export const massaToken = 'MAS';
+export const BEARBY_INSTALL = 'https://bearby.io';
+export enum SUPPORTED_MASSA_WALLETS {
+ MASSASTATION = 'MASSASTATION',
+ BEARBY = 'BEARBY',
+}
+
+export const MASSA_EXPLO_URL = 'https://massexplo.io/tx/';
+export const MASSA_EXPLO_EXTENSION = '?network=buildnet';
+export const MASSA_EXPLORER_URL =
+ 'https://explorer.massa.net/mainnet/operation/';
diff --git a/src/lib/massa-react/hooks/useWriteSmartContract.tsx b/src/lib/massa-react/hooks/useWriteSmartContract.tsx
new file mode 100644
index 00000000..30cd6f49
--- /dev/null
+++ b/src/lib/massa-react/hooks/useWriteSmartContract.tsx
@@ -0,0 +1,169 @@
+import { useState } from 'react';
+
+import {
+ Client,
+ EOperationStatus,
+ ICallData,
+ MAX_GAS_CALL,
+} from '@massalabs/massa-web3';
+import { toast, ToastContent } from '../../../components';
+import { OperationToast } from '../../ConnectMassaWallets/components/OperationToast';
+import { logSmartContractEvents } from '../utils';
+import Intl from '../i18n';
+
+interface ToasterMessage {
+ pending: string;
+ success: string;
+ error: string;
+ timeout?: string;
+}
+
+function minBigInt(a: bigint, b: bigint) {
+ return a < b ? a : b;
+}
+
+export function useWriteSmartContract(client?: Client, isMainnet?: boolean) {
+ const [isPending, setIsPending] = useState(false);
+ const [isOpPending, setIsOpPending] = useState(false);
+ const [isSuccess, setIsSuccess] = useState(false);
+ const [isError, setIsError] = useState(false);
+ const [opId, setOpId] = useState(undefined);
+
+ function callSmartContract(
+ targetFunction: string,
+ targetAddress: string,
+ parameter: number[],
+ messages: ToasterMessage,
+ coins = BigInt(0),
+ ) {
+ if (!client) {
+ throw new Error('Massa client not found');
+ }
+ if (isOpPending) {
+ throw new Error('Operation is already pending');
+ }
+ setIsSuccess(false);
+ setIsError(false);
+ setIsOpPending(false);
+ setIsPending(true);
+ let operationId: string | undefined;
+ let toastId: string | undefined;
+
+ const callData = {
+ targetAddress,
+ targetFunction,
+ parameter,
+ coins,
+ } as ICallData;
+
+ client
+ .smartContracts()
+ .readSmartContract(callData)
+ .then((response) => {
+ const gasCost = BigInt(response.info.gas_cost);
+ return minBigInt(gasCost + (gasCost * 20n) / 100n, MAX_GAS_CALL);
+ })
+ .then((maxGas: bigint) => {
+ callData.maxGas = maxGas;
+ return client.smartContracts().callSmartContract(callData);
+ })
+ .then((opId) => {
+ operationId = opId;
+ setOpId(operationId);
+ setIsOpPending(true);
+ toastId = toast.loading(
+ (t) => (
+
+
+
+ ),
+ {
+ duration: Infinity,
+ },
+ );
+ return client
+ .smartContracts()
+ .awaitMultipleRequiredOperationStatus(operationId, [
+ EOperationStatus.SPECULATIVE_ERROR,
+ EOperationStatus.FINAL_ERROR,
+ EOperationStatus.FINAL_SUCCESS,
+ ]);
+ })
+ .then((status: EOperationStatus) => {
+ if (status !== EOperationStatus.FINAL_SUCCESS) {
+ throw new Error('Operation failed', { cause: { status } });
+ }
+ setIsSuccess(true);
+ setIsOpPending(false);
+ setIsPending(false);
+ toast.dismiss(toastId);
+ toast.success((t) => (
+
+
+
+ ));
+ })
+ .catch((error) => {
+ console.error(error);
+ toast.dismiss(toastId);
+ setIsError(true);
+ setIsOpPending(false);
+ setIsPending(false);
+
+ if (!operationId) {
+ console.error('Operation ID not found');
+ toast.error((t) => (
+
+
+
+ ));
+ return;
+ }
+
+ if (
+ [
+ EOperationStatus.FINAL_ERROR,
+ EOperationStatus.SPECULATIVE_ERROR,
+ ].includes(error.cause?.status)
+ ) {
+ toast.error((t) => (
+
+
+
+ ));
+ logSmartContractEvents(client, operationId);
+ } else {
+ toast.error((t) => (
+
+
+
+ ));
+ }
+ });
+ }
+
+ return {
+ opId,
+ isOpPending,
+ isPending,
+ isSuccess,
+ isError,
+ callSmartContract,
+ };
+}
diff --git a/src/lib/massa-react/i18n/en_US.json b/src/lib/massa-react/i18n/en_US.json
new file mode 100644
index 00000000..8a9411ed
--- /dev/null
+++ b/src/lib/massa-react/i18n/en_US.json
@@ -0,0 +1,8 @@
+{
+ "steps": {
+ "failed-timeout": "Operation failed due to timeout, please retry with more fees."
+ },
+ "balance": {
+ "error": "We couldn't fetch your balance! Please, try again!"
+ }
+}
diff --git a/src/lib/massa-react/i18n/index.ts b/src/lib/massa-react/i18n/index.ts
new file mode 100644
index 00000000..e49a2319
--- /dev/null
+++ b/src/lib/massa-react/i18n/index.ts
@@ -0,0 +1,7 @@
+import I18n from '../../i18n/i18n';
+import enUs from './en_US.json';
+
+const Intl = new I18n({ EN_us: enUs });
+Object.freeze(Intl);
+
+export default Intl;
diff --git a/src/lib/massa-react/utils.ts b/src/lib/massa-react/utils.ts
new file mode 100644
index 00000000..cb3a5ee1
--- /dev/null
+++ b/src/lib/massa-react/utils.ts
@@ -0,0 +1,72 @@
+import { Client } from '@massalabs/massa-web3';
+import { IAccount, IAccountBalanceResponse } from '@massalabs/wallet-provider';
+
+import {
+ MASSA_EXPLO_EXTENSION,
+ MASSA_EXPLO_URL,
+ MASSA_EXPLORER_URL,
+} from './const';
+import Intl from './i18n';
+import { toast } from '../../components';
+
+export function logSmartContractEvents(
+ client: Client,
+ operationId: string,
+): void {
+ client
+ .smartContracts()
+ .getFilteredScOutputEvents({
+ emitter_address: null,
+ start: null,
+ end: null,
+ original_caller_address: null,
+ original_operation_id: operationId,
+ is_final: null,
+ })
+ .then((events) => {
+ events.map((l) =>
+ console.error(`opId ${operationId}: execution error ${l.data}`),
+ );
+ });
+}
+
+export function generateExplorerLink(opId: string, isMainnet = true): string {
+ const buildnetExplorerUrl = `${MASSA_EXPLO_URL}${opId}${MASSA_EXPLO_EXTENSION}`;
+ const mainnetExplorerUrl = `${MASSA_EXPLORER_URL}${opId}`;
+ const explorerUrl = isMainnet ? mainnetExplorerUrl : buildnetExplorerUrl;
+
+ return explorerUrl;
+}
+
+/**
+ * Masks the middle of an address with a specified character.
+ * @param str - The address to mask.
+ * @param mask - The character to use for masking. Defaults to `.`.
+ * @returns The masked address.
+ */
+export function maskAddress(str: string, length = 4, mask = '...'): string {
+ const start = length;
+ const end = str?.length - length;
+
+ return str ? str?.substring(0, start) + mask + str?.substring(end) : '';
+}
+
+export function maskNickname(str: string, length = 32): string {
+ if (!str) return '';
+
+ if (str.length <= length) return str;
+
+ return str?.substring(0, length) + '...';
+}
+
+export async function fetchMASBalance(
+ account: IAccount,
+): Promise {
+ try {
+ return account.balance();
+ } catch (error) {
+ console.error('Error while retrieving balance: ', error);
+ toast.error(Intl.t('balance.error'));
+ return { finalBalance: '0', candidateBalance: '0' };
+ }
+}
diff --git a/src/util/useClickOutside.ts b/src/lib/util/hooks/useClickOutside.ts
similarity index 100%
rename from src/util/useClickOutside.ts
rename to src/lib/util/hooks/useClickOutside.ts
diff --git a/src/util/useLocalStorage.ts b/src/lib/util/hooks/useLocalStorage.ts
similarity index 100%
rename from src/util/useLocalStorage.ts
rename to src/lib/util/hooks/useLocalStorage.ts
diff --git a/src/util/parseAmount.test.ts b/src/lib/util/parseAmount.test.ts
similarity index 59%
rename from src/util/parseAmount.test.ts
rename to src/lib/util/parseAmount.test.ts
index 9cb06a13..66e5dd4a 100644
--- a/src/util/parseAmount.test.ts
+++ b/src/lib/util/parseAmount.test.ts
@@ -1,5 +1,6 @@
import {
formatAmount,
+ formatStandard,
roundDecimalPartToOneSignificantDigit,
} from './parseAmount';
@@ -86,3 +87,75 @@ describe('roundDecimalPartToOneSignificantDigit', () => {
expect(roundDecimalPartToOneSignificantDigit('0099')).toEqual('01');
});
});
+
+describe('formatStandard', () => {
+ test('formats an empty string', () => {
+ const result = formatStandard('', 18);
+ expect(result).toEqual('0');
+ });
+
+ test('formats an amount with default parameters', () => {
+ const result = formatStandard('123456789012345678901', 18);
+ expect(result).toEqual('123.456789012345678901');
+ });
+
+ test('formats an amount with less than the specified decimals', () => {
+ const result = formatStandard('12345', 8);
+ expect(result).toEqual('0.00012345');
+ });
+
+ test('adds padding zeroes when necessary', () => {
+ const result = formatStandard('1', 18);
+ expect(result).toEqual('0.000000000000000001');
+ });
+
+ test('handles amount with exact decimals length', () => {
+ const result = formatStandard('1000000000000000000', 18);
+ expect(result).toEqual('1');
+ });
+
+ test('formats an amount with less than the specified decimals and round up', () => {
+ const result = formatStandard('69000', 9);
+ expect(result).toEqual('0.000069');
+ });
+
+ it('formatStandard with min string value', () => {
+ const value = '0000000000';
+
+ const result = formatStandard(value.toString());
+
+ expect(result).toBe('0');
+ });
+
+ it('formatStandard with min bigint value', () => {
+ const value = 0n;
+
+ const result = formatStandard(value.toString());
+
+ expect(result).toBe('0');
+ });
+
+ it('formatStandard with mid range string value', () => {
+ const value = '10000000000000';
+
+ const result = formatStandard(value.toString());
+
+ expect(result).toBe('10,000');
+ });
+
+ it('formatStandard with mid range bigint value', () => {
+ const value = 10000000000000n;
+
+ const result = formatStandard(value.toString());
+
+ expect(result).toBe('10,000');
+ });
+
+ it('formatStandard with max string value', () => {
+ const value = '922337203600000000000';
+
+ const result = formatStandard(value.toString());
+
+ expect(result).toBe('922,337,203,600');
+ });
+});
diff --git a/src/util/parseAmount.ts b/src/lib/util/parseAmount.ts
similarity index 92%
rename from src/util/parseAmount.ts
rename to src/lib/util/parseAmount.ts
index b6313f33..80dc61b6 100644
--- a/src/util/parseAmount.ts
+++ b/src/lib/util/parseAmount.ts
@@ -7,6 +7,17 @@ export interface FormattedAmount {
amountFormattedFull: string;
}
+function removeTrailingZeros(numStr: string): string {
+ return numStr.replace(/\.?0+$/, '');
+}
+
+// Like format amount but remove the trailing zeros
+export function formatStandard(amount: string, decimals = 9): string {
+ return removeTrailingZeros(
+ formatAmount(amount, decimals).amountFormattedFull,
+ );
+}
+
/**
* reverse format FT amount
*/
diff --git a/src/util/truncate.ts b/src/lib/util/truncate.ts
similarity index 100%
rename from src/util/truncate.ts
rename to src/lib/util/truncate.ts
diff --git a/src/util/utils.ts b/src/lib/util/utils.ts
similarity index 100%
rename from src/util/utils.ts
rename to src/lib/util/utils.ts
diff --git a/src/util/types.ts b/src/util/types.ts
deleted file mode 100644
index fd8dccf3..00000000
--- a/src/util/types.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type Theme = 'theme-light' | 'theme-dark';
diff --git a/tsconfig.json b/tsconfig.json
index 85f3f678..a0a3a462 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,6 +4,7 @@
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"module": "ESNext",
"skipLibCheck": true,
+ "esModuleInterop": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
diff --git a/vite.config.ts b/vite.config.ts
index a46ad84f..927f2438 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -19,5 +19,8 @@ export default ({ mode }) => {
exportAsDefault: true,
}),
],
+ optimizeDeps: {
+ include: ['react-dom', 'dot-object', 'copy-to-clipboard'],
+ },
});
};