diff --git a/package.json b/package.json
index 9e60d39..c86a47e 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "ghost-dao-interface",
"private": true,
- "version": "0.4.4",
+ "version": "0.5.1",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,6 +16,7 @@
"@ethersproject/bignumber": "^5.8.0",
"@ethersproject/units": "^5.8.0",
"@mui/icons-material": "^6.4.7",
+ "@mui/lab": "6.0.1-beta.36",
"@mui/material": "^6.4.7",
"@mui/utils": "^6.4.6",
"@polkadot-api/metadata-builders": "0.13.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 183862c..28d471f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -26,6 +26,9 @@ importers:
'@mui/icons-material':
specifier: ^6.4.7
version: 6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
+ '@mui/lab':
+ specifier: 6.0.1-beta.36
+ version: 6.0.1-beta.36(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@mui/material':
specifier: ^6.4.7
version: 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@@ -525,6 +528,21 @@ packages:
'@ethersproject/units@5.8.0':
resolution: {integrity: sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==}
+ '@floating-ui/core@1.7.4':
+ resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==}
+
+ '@floating-ui/dom@1.7.5':
+ resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==}
+
+ '@floating-ui/react-dom@2.1.7':
+ resolution: {integrity: sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==}
+ peerDependencies:
+ react: '>=16.8.0'
+ react-dom: '>=16.8.0'
+
+ '@floating-ui/utils@0.2.10':
+ resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==}
+
'@humanfs/core@0.19.1':
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
engines: {node: '>=18.18.0'}
@@ -638,6 +656,18 @@ packages:
resolution: {integrity: sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==}
engines: {node: '>=16.0.0'}
+ '@mui/base@5.0.0-beta.70':
+ resolution: {integrity: sha512-Tb/BIhJzb0pa5zv/wu7OdokY9ZKEDqcu1BDFnohyvGCoHuSXbEr90rPq1qeNW3XvTBIbNWHEF7gqge+xpUo6tQ==}
+ engines: {node: '>=14.0.0'}
+ deprecated: This package has been replaced by @base-ui/react
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@mui/core-downloads-tracker@6.4.7':
resolution: {integrity: sha512-XjJrKFNt9zAKvcnoIIBquXyFyhfrHYuttqMsoDS7lM7VwufYG4fAPw4kINjBFg++fqXM2BNAuWR9J7XVIuKIKg==}
@@ -652,6 +682,27 @@ packages:
'@types/react':
optional: true
+ '@mui/lab@6.0.1-beta.36':
+ resolution: {integrity: sha512-af9lDmA9SZGEWF1XXk0EVBpfCITk9IKsvh9lLOZGdYaaHfQeCsqxGEDMvNO66j0P8EYoxpyry84LFCJYuLVtVw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@mui/material': ^6.5.0
+ '@mui/material-pigment-css': ^6.5.0
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ '@mui/material-pigment-css':
+ optional: true
+ '@types/react':
+ optional: true
+
'@mui/material@6.4.7':
resolution: {integrity: sha512-K65StXUeGAtFJ4ikvHKtmDCO5Ab7g0FZUu2J5VpoKD+O6Y3CjLYzRi+TMlI3kaL4CL158+FccMoOd/eaddmeRQ==}
engines: {node: '>=14.0.0'}
@@ -682,6 +733,16 @@ packages:
'@types/react':
optional: true
+ '@mui/private-theming@6.4.9':
+ resolution: {integrity: sha512-LktcVmI5X17/Q5SkwjCcdOLBzt1hXuc14jYa7NPShog0GBDCDvKtcnP0V7a2s6EiVRlv7BzbWEJzH6+l/zaCxw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@mui/styled-engine@6.4.6':
resolution: {integrity: sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==}
engines: {node: '>=14.0.0'}
@@ -695,6 +756,19 @@ packages:
'@emotion/styled':
optional: true
+ '@mui/styled-engine@6.5.0':
+ resolution: {integrity: sha512-8woC2zAqF4qUDSPIBZ8v3sakj+WgweolpyM/FXf8jAx6FMls+IE4Y8VDZc+zS805J7PRz31vz73n2SovKGaYgw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.4.1
+ '@emotion/styled': ^11.3.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+
'@mui/system@6.4.7':
resolution: {integrity: sha512-7wwc4++Ak6tGIooEVA9AY7FhH2p9fvBMORT4vNLMAysH3Yus/9B9RYMbrn3ANgsOyvT3Z7nE+SP8/+3FimQmcg==}
engines: {node: '>=14.0.0'}
@@ -711,6 +785,22 @@ packages:
'@types/react':
optional: true
+ '@mui/system@6.5.0':
+ resolution: {integrity: sha512-XcbBYxDS+h/lgsoGe78ExXFZXtuIlSBpn/KsZq8PtZcIkUNJInkuDqcLd2rVBQrDC1u+rvVovdaWPf2FHKJf3w==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@emotion/react': ^11.5.0
+ '@emotion/styled': ^11.3.0
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@emotion/react':
+ optional: true
+ '@emotion/styled':
+ optional: true
+ '@types/react':
+ optional: true
+
'@mui/types@7.2.21':
resolution: {integrity: sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==}
peerDependencies:
@@ -719,6 +809,14 @@ packages:
'@types/react':
optional: true
+ '@mui/types@7.2.24':
+ resolution: {integrity: sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@mui/utils@6.4.6':
resolution: {integrity: sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==}
engines: {node: '>=14.0.0'}
@@ -729,6 +827,16 @@ packages:
'@types/react':
optional: true
+ '@mui/utils@6.4.9':
+ resolution: {integrity: sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
'@noble/ciphers@1.2.1':
resolution: {integrity: sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==}
engines: {node: ^14.21.3 || >=16}
@@ -3423,6 +3531,23 @@ snapshots:
'@ethersproject/constants': 5.8.0
'@ethersproject/logger': 5.8.0
+ '@floating-ui/core@1.7.4':
+ dependencies:
+ '@floating-ui/utils': 0.2.10
+
+ '@floating-ui/dom@1.7.5':
+ dependencies:
+ '@floating-ui/core': 1.7.4
+ '@floating-ui/utils': 0.2.10
+
+ '@floating-ui/react-dom@2.1.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ dependencies:
+ '@floating-ui/dom': 1.7.5
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+
+ '@floating-ui/utils@0.2.10': {}
+
'@humanfs/core@0.19.1': {}
'@humanfs/node@0.16.6':
@@ -3615,6 +3740,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@mui/base@5.0.0-beta.70(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ dependencies:
+ '@babel/runtime': 7.27.6
+ '@floating-ui/react-dom': 2.1.7(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@mui/types': 7.2.24(@types/react@19.0.10)
+ '@mui/utils': 6.4.9(@types/react@19.0.10)(react@19.0.0)
+ '@popperjs/core': 2.11.8
+ clsx: 2.1.1
+ prop-types: 15.8.1
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+ optionalDependencies:
+ '@types/react': 19.0.10
+
'@mui/core-downloads-tracker@6.4.7': {}
'@mui/icons-material@6.4.7(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
@@ -3625,6 +3764,23 @@ snapshots:
optionalDependencies:
'@types/react': 19.0.10
+ '@mui/lab@6.0.1-beta.36(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
+ dependencies:
+ '@babel/runtime': 7.27.6
+ '@mui/base': 5.0.0-beta.70(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@mui/material': 6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@mui/system': 6.5.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
+ '@mui/types': 7.2.24(@types/react@19.0.10)
+ '@mui/utils': 6.4.9(@types/react@19.0.10)(react@19.0.0)
+ clsx: 2.1.1
+ prop-types: 15.8.1
+ react: 19.0.0
+ react-dom: 19.0.0(react@19.0.0)
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
+ '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
+ '@types/react': 19.0.10
+
'@mui/material@6.4.7(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.9
@@ -3648,16 +3804,38 @@ snapshots:
'@mui/private-theming@6.4.6(@types/react@19.0.10)(react@19.0.0)':
dependencies:
- '@babel/runtime': 7.26.9
+ '@babel/runtime': 7.27.6
'@mui/utils': 6.4.6(@types/react@19.0.10)(react@19.0.0)
prop-types: 15.8.1
react: 19.0.0
optionalDependencies:
'@types/react': 19.0.10
+ '@mui/private-theming@6.4.9(@types/react@19.0.10)(react@19.0.0)':
+ dependencies:
+ '@babel/runtime': 7.27.6
+ '@mui/utils': 6.4.9(@types/react@19.0.10)(react@19.0.0)
+ prop-types: 15.8.1
+ react: 19.0.0
+ optionalDependencies:
+ '@types/react': 19.0.10
+
'@mui/styled-engine@6.4.6(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)':
dependencies:
- '@babel/runtime': 7.26.9
+ '@babel/runtime': 7.27.6
+ '@emotion/cache': 11.14.0
+ '@emotion/serialize': 1.3.3
+ '@emotion/sheet': 1.4.0
+ csstype: 3.1.3
+ prop-types: 15.8.1
+ react: 19.0.0
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
+ '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
+
+ '@mui/styled-engine@6.5.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)':
+ dependencies:
+ '@babel/runtime': 7.27.6
'@emotion/cache': 11.14.0
'@emotion/serialize': 1.3.3
'@emotion/sheet': 1.4.0
@@ -3684,10 +3862,30 @@ snapshots:
'@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
'@types/react': 19.0.10
+ '@mui/system@6.5.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)':
+ dependencies:
+ '@babel/runtime': 7.27.6
+ '@mui/private-theming': 6.4.9(@types/react@19.0.10)(react@19.0.0)
+ '@mui/styled-engine': 6.5.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@emotion/styled@11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0))(react@19.0.0)
+ '@mui/types': 7.2.24(@types/react@19.0.10)
+ '@mui/utils': 6.4.9(@types/react@19.0.10)(react@19.0.0)
+ clsx: 2.1.1
+ csstype: 3.1.3
+ prop-types: 15.8.1
+ react: 19.0.0
+ optionalDependencies:
+ '@emotion/react': 11.14.0(@types/react@19.0.10)(react@19.0.0)
+ '@emotion/styled': 11.14.0(@emotion/react@11.14.0(@types/react@19.0.10)(react@19.0.0))(@types/react@19.0.10)(react@19.0.0)
+ '@types/react': 19.0.10
+
'@mui/types@7.2.21(@types/react@19.0.10)':
optionalDependencies:
'@types/react': 19.0.10
+ '@mui/types@7.2.24(@types/react@19.0.10)':
+ optionalDependencies:
+ '@types/react': 19.0.10
+
'@mui/utils@6.4.6(@types/react@19.0.10)(react@19.0.0)':
dependencies:
'@babel/runtime': 7.26.9
@@ -3700,6 +3898,18 @@ snapshots:
optionalDependencies:
'@types/react': 19.0.10
+ '@mui/utils@6.4.9(@types/react@19.0.10)(react@19.0.0)':
+ dependencies:
+ '@babel/runtime': 7.27.6
+ '@mui/types': 7.2.24(@types/react@19.0.10)
+ '@types/prop-types': 15.7.14
+ clsx: 2.1.1
+ prop-types: 15.8.1
+ react: 19.0.0
+ react-is: 19.0.0
+ optionalDependencies:
+ '@types/react': 19.0.10
+
'@noble/ciphers@1.2.1': {}
'@noble/ciphers@1.3.0': {}
@@ -5042,7 +5252,7 @@ snapshots:
babel-plugin-macros@3.1.0:
dependencies:
- '@babel/runtime': 7.26.9
+ '@babel/runtime': 7.27.6
cosmiconfig: 7.1.0
resolve: 1.22.10
@@ -5238,7 +5448,7 @@ snapshots:
dom-helpers@5.2.1:
dependencies:
- '@babel/runtime': 7.26.9
+ '@babel/runtime': 7.27.6
csstype: 3.1.3
dot-case@3.0.4:
diff --git a/src/App.jsx b/src/App.jsx
index 3363c68..f6b3f03 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -31,6 +31,8 @@ const Wrapper = lazy(() => import("./containers/WethWrapper/WethWrapper"));
const Dex = lazy(() => import("./containers/Dex/Dex"));
const Bridge = lazy(() => import("./containers/Bridge/Bridge"));
const NotFound = lazy(() => import("./containers/NotFound/NotFound"));
+const Governance = lazy(() => import("./containers/Governance/Governance"));
+const ProposalDetails = lazy(() => import("./containers/Governance/ProposalDetails"));
const PREFIX = "App";
@@ -213,6 +215,8 @@ function App() {
}
} />
} />
+ } />
+ } />
>
}
prop !== "barBackground" && prop !== 'barColor' && prop !== 'height'
+})(({ theme, barColor, barBackground, height }) => ({
+ height: height || 8,
+ borderRadius: 4,
+ backgroundColor: barBackground || theme.palette.grey[300],
+ '& .MuiLinearProgress-bar': {
+ backgroundColor: barColor || theme.palette.primary.main
+ }
+}));
+
+const LinearProgressBar = (props) => {
+ return (
+
+
+ {props.target && }
+
+ )
+}
+
+export default LinearProgressBar;
diff --git a/src/components/Sidebar/NavContent.jsx b/src/components/Sidebar/NavContent.jsx
index a4f7ab4..6d0f834 100644
--- a/src/components/Sidebar/NavContent.jsx
+++ b/src/components/Sidebar/NavContent.jsx
@@ -24,6 +24,8 @@ import TelegramIcon from '@mui/icons-material/Telegram';
import HowToVoteIcon from '@mui/icons-material/HowToVote';
import HubIcon from '@mui/icons-material/Hub';
import PublicIcon from '@mui/icons-material/Public';
+import ForkRightIcon from '@mui/icons-material/ForkRight';
+import GavelIcon from '@mui/icons-material/Gavel';
import ForumIcon from '@mui/icons-material/Forum';
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
import BookIcon from '@mui/icons-material/Book';
@@ -177,7 +179,8 @@ const NavContent = ({ chainId, addressChainId }) => {
}
/>
-
+
+
diff --git a/src/containers/Bond/Bonds.jsx b/src/containers/Bond/Bonds.jsx
index 058c831..e880a4b 100644
--- a/src/containers/Bond/Bonds.jsx
+++ b/src/containers/Bond/Bonds.jsx
@@ -1,6 +1,5 @@
import { Box, Tab, Tabs, Container, useMediaQuery } from "@mui/material";
import { useEffect, useState } from "react";
-import { useNavigate } from "react-router-dom";
import ReactGA from "react-ga4";
import Paper from "../../components/Paper/Paper";
@@ -21,7 +20,6 @@ import { useTokenSymbol } from "../../hooks/tokens";
const Bonds = ({ chainId, address, connect }) => {
const [isZoomed] = useState(false);
- const navigate = useNavigate();
const [secondsTo, setSecondsTo] = useState(0);
const isSmallScreen = useMediaQuery("(max-width: 650px)");
@@ -29,7 +27,7 @@ const Bonds = ({ chainId, address, connect }) => {
useEffect(() => {
ReactGA.send({ hitType: "pageview", page: "/bonds" });
- }, [])
+ }, []);
const { liveBonds } = useLiveBonds(chainId);
const totalReserves = useTotalReserves(chainId);
diff --git a/src/containers/Governance/Governance.jsx b/src/containers/Governance/Governance.jsx
new file mode 100644
index 0000000..fe46b63
--- /dev/null
+++ b/src/containers/Governance/Governance.jsx
@@ -0,0 +1,92 @@
+import { useEffect } from "react";
+import ReactGA from "react-ga4";
+
+import { Box, Container, Grid, Divider, Typography, useMediaQuery } from "@mui/material";
+
+import Paper from "../../components/Paper/Paper";
+import PageTitle from "../../components/PageTitle/PageTitle";
+import { PrimaryButton } from "../../components/Button";
+
+import GovernanceInfoText from "./components/GovernanceInfoText";
+import ProposalsList from "./components/ProposalsList";
+import { ProposalsCount, MinQuorumPercentage, ProposalThreshold } from "./components/Metric";
+
+import { useTokenSymbol } from "../../hooks/tokens";
+
+const Governance = ({ connect, config, address, chainId }) => {
+ const isSemiSmallScreen = useMediaQuery("(max-width: 745px)");
+ const isSmallScreen = useMediaQuery("(max-width: 650px)");
+ const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
+
+ const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
+
+ const handleModal = () => {
+ alert("proposal modal here");
+ }
+
+ useEffect(() => {
+ ReactGA.send({ hitType: "pageview", page: "/governance" });
+ }, []);
+
+ return (
+
+
+
+
+
+
+ Proposal Requirements
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Claimes for locked funds could be here
+
+
+
+ handleModal(true)}
+ sx={{ maxWidth: isSemiSmallScreen ? "100%" : "350px" }}
+ >
+ Create Proposal
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Governance;
diff --git a/src/containers/Governance/ProposalDetails.jsx b/src/containers/Governance/ProposalDetails.jsx
new file mode 100644
index 0000000..bff84fa
--- /dev/null
+++ b/src/containers/Governance/ProposalDetails.jsx
@@ -0,0 +1,244 @@
+import { useEffect, useState, useMemo } from "react";
+import ReactGA from "react-ga4";
+import { useParams } from 'react-router-dom';
+
+import { Box, Container, Typography, useMediaQuery, useTheme } from "@mui/material";
+
+import Paper from "../../components/Paper/Paper";
+import PageTitle from "../../components/PageTitle/PageTitle";
+import LinearProgressBar from "../../components/Progress/LinearProgressBar";
+import InfoTooltip from "../../components/Tooltip/InfoTooltip";
+import Chip from "../../components/Chip/Chip";
+import { SecondaryButton } from "../../components/Button";
+
+import { formatNumber } from "../../helpers";
+import { prettifySecondsInDays } from "../../helpers/timeUtil";
+import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
+
+import ProposalDiscussionModal from "./components/ProposalDiscussionModal";
+import ProposalDiscussion from "./components/ProposalDiscussion";
+import { convertStatusToTemplate } from "./helpers";
+
+import { useTokenSymbol, useTotalSupply, useBalance } from "../../hooks/tokens";
+import {
+ useProposalStatus,
+ useProposalProposer,
+ useProposalLocked,
+ useProposalQuorum,
+ useProposalVotes,
+ useProposalSnapshot,
+ useProposalDeadline,
+ useProposalVotingDelay
+} from "../../hooks/governance";
+
+///////////////////////////////////////////////////////
+import Timeline from '@mui/lab/Timeline';
+import TimelineItem from '@mui/lab/TimelineItem';
+import TimelineSeparator from '@mui/lab/TimelineSeparator';
+import TimelineConnector from '@mui/lab/TimelineConnector';
+import TimelineContent from '@mui/lab/TimelineContent';
+import TimelineOppositeContent from '@mui/lab/TimelineOppositeContent';
+import TimelineDot from '@mui/lab/TimelineDot';
+///////////////////////////
+import FastfoodIcon from '@mui/icons-material/Fastfood';
+import LaptopMacIcon from '@mui/icons-material/LaptopMac';
+import HotelIcon from '@mui/icons-material/Hotel';
+import RepeatIcon from '@mui/icons-material/Repeat';
+
+const HUNDRED = new DecimalBigNumber(100n, 0);
+
+const ProposalDetails = ({ chainId, address }) => {
+ const { id } = useParams();
+ const [selectedDiscussionUrl, setSelectedDiscussionUrl] = useState(undefined);
+
+ const isSemiSmallScreen = useMediaQuery("(max-width: 745px)");
+ const isSmallScreen = useMediaQuery("(max-width: 650px)");
+ const isVerySmallScreen = useMediaQuery("(max-width: 379px)");
+
+ const theme = useTheme();
+
+ const { symbol: ghstSymbol } = useTokenSymbol(chainId, "GHST");
+ const { balance } = useBalance(chainId, "GHST", address);
+ const { totalSupply } = useTotalSupply(chainId, "GHST"); // TODO: revisit
+
+ const { status: proposalStatus } = useProposalStatus(chainId, id);
+ const { proposer: proposalProposer } = useProposalProposer(chainId, id);
+ const { locked: proposalLocked } = useProposalLocked(chainId, id);
+ const { quorum: proposalQuorum } = useProposalQuorum(chainId, id);
+ const { forVotes, againstVotes } = useProposalVotes(chainId, id);
+
+ useEffect(() => {
+ ReactGA.send({ hitType: "pageview", page: `/governance/${id}` });
+ }, []);
+
+ const isDiscussionModalOpened = useMemo(() => {
+ return selectedDiscussionUrl !== undefined;
+ }, [selectedDiscussionUrl]);
+
+ return (
+ <>
+ setSelectedDiscussionUrl(undefined)}
+ />
+
+
+
+
+
+
+
+ Progress
+
+
+
+ }
+ topRight={
+ setSelectedDiscussionUrl("dicks")} />
+ }
+ >
+
+
+
+
+ For: {formatNumber(forVotes.toString(), 2)} ({formatNumber(forVotes * HUNDRED / proposalQuorum, 1)}%)
+
+
+ Against: {formatNumber(againstVotes.toString(), 2)} ({formatNumber(againstVotes * HUNDRED / proposalQuorum, 1)}%)
+
+
+
+
+
+
+
+
+ Quorum
+
+
+ {formatNumber(proposalQuorum.toString(), 4)}
+
+
+
+
+ Total
+
+
+ {formatNumber(totalSupply.toString(), 4)}
+
+
+
+
+ Votes
+
+
+ {formatNumber(balance.toString(), 4)}
+
+
+
+
+ alert("For vote casted")}>For
+ alert("Against vote casted")}>Against
+
+
+
+
+
+
+ Timeline
+
+
+ }
+ >
+
+
+
+
+
+
+
+ Executable Code
+
+
+ }
+ >
+ Here will be a list of decoded calldatas
+
+
+
+ >
+ )
+}
+
+const VotingTimeline = ({ proposalId, chainId }) => {
+ const { delay: propsalVotingDelay } = useProposalVotingDelay(chainId, proposalId);
+ const { snapshot: proposalSnapshot } = useProposalSnapshot(chainId, proposalId);
+ const { deadline: proposalDeadline } = useProposalDeadline(chainId, proposalId);
+
+ const voteStarted = useMemo(() => {
+ if (proposalSnapshot && propsalVotingDelay) {
+ return proposalSnapshot > propsalVotingDelay ? proposalSnapshot - propsalVotingDelay : 0;
+ }
+ return 0;
+ }, [proposalSnapshot, propsalVotingDelay]);
+
+ return (
+
+
+
+
+
+ )
+}
+
+const VotingTimelineItem = ({ isFirst, isLast, time, message }) => {
+ return (
+
+
+
+ {!isFirst && }
+
+ {!isLast && }
+
+
+
+ {message}
+ {new Date(time * 1000).toLocaleString()}
+
+
+ )
+}
+
+export default ProposalDetails;
diff --git a/src/containers/Governance/components/GovernanceInfoText.jsx b/src/containers/Governance/components/GovernanceInfoText.jsx
new file mode 100644
index 0000000..114c516
--- /dev/null
+++ b/src/containers/Governance/components/GovernanceInfoText.jsx
@@ -0,0 +1,23 @@
+import { Link, Typography, useTheme } from "@mui/material";
+
+const GovernanceInfoText = () => {
+ const theme = useTheme();
+ return (
+
+ ghostDAO's adaptive governance system algorithmically sets proposal threshold based on activity.
+ Learn more here.
+
+ )
+};
+
+export default GovernanceInfoText;
diff --git a/src/containers/Governance/components/Metric.jsx b/src/containers/Governance/components/Metric.jsx
new file mode 100644
index 0000000..8c39cdd
--- /dev/null
+++ b/src/containers/Governance/components/Metric.jsx
@@ -0,0 +1,53 @@
+import Metric from "../../../components/Metric/Metric";
+
+import { formatCurrency, formatNumber } from "../../../helpers";
+import {
+ useMinQuorum,
+ useProposalThreshold,
+ useProposalCount
+} from "../../../hooks/governance";
+
+export const MinQuorumPercentage = props => {
+ const { percentage } = useMinQuorum(props.chainId);
+
+ const _props = {
+ ...props,
+ label: `Min Quorum`,
+ tooltip: `Minimum quorum needed for proposal to be succeeded.`,
+ };
+
+ if (percentage) _props.metric = `${formatNumber(percentage, 2)}%`;
+ else _props.isLoading = true;
+
+ return ;
+};
+
+export const ProposalThreshold = props => {
+ const { threshold } = useProposalThreshold(props.chainId, props.ghstSymbol);
+
+ const _props = {
+ ...props,
+ label: `$${props.ghstSymbol} Threshold`,
+ tooltip: `Minimum $${props.ghstSymbol} amount to be locked to create proposal.`,
+ };
+
+ if (threshold) _props.metric = `${formatCurrency(threshold.toString(), 0, props.ghstSymbol)}`;
+ else _props.isLoading = true;
+
+ return ;
+}
+
+export const ProposalsCount = props => {
+ const { proposalsCount } = useProposalCount(props.chainId);
+
+ const _props = {
+ ...props,
+ label: `Proposals Count`,
+ tooltip: `How much proposals already passed.`,
+ };
+
+ if (proposalsCount) _props.metric = proposalsCount.toString();
+ else _props.isLoading = true;
+
+ return ;
+}
diff --git a/src/containers/Governance/components/ProposalDiscussion.jsx b/src/containers/Governance/components/ProposalDiscussion.jsx
new file mode 100644
index 0000000..9bf829b
--- /dev/null
+++ b/src/containers/Governance/components/ProposalDiscussion.jsx
@@ -0,0 +1,29 @@
+import { Link } from "@mui/material";
+import GhostStyledIcon from "../../../components/Icon/GhostIcon";
+import ArrowUpIcon from "../../../assets/icons/arrow-up.svg?react";
+
+const ProposalDiscussion = (linkProps) => {
+ return (
+
+ Learn more
+
+
+ )
+}
+
+export default ProposalDiscussion;
diff --git a/src/containers/Governance/components/ProposalDiscussionModal.jsx b/src/containers/Governance/components/ProposalDiscussionModal.jsx
new file mode 100644
index 0000000..ac2e902
--- /dev/null
+++ b/src/containers/Governance/components/ProposalDiscussionModal.jsx
@@ -0,0 +1,64 @@
+import { useState } from "react";
+import { Box, Typography, Link } from "@mui/material";
+
+import Modal from "../../../components/Modal/Modal";
+import { PrimaryButton } from "../../../components/Button";
+
+const ProposalDiscussionModal = ({ isOpened, closeModal, url }) => {
+ const [isCopied, setIsCopied] = useState(false);
+
+ const copyToClipboard = () => {
+ navigator.clipboard.writeText(url)
+ .then(() => {
+ isCopied(true);
+ setTimeout(() => setIsCopied(false), 2000);
+ })
+ .catch(err => console.error(err));
+ }
+
+ return (
+
+ Discussion URL
+
+ }
+ open={isOpened}
+ onClose={closeModal}
+ maxWidth="460px"
+ minHeight="200px"
+ >
+
+
+
+ You are leaving the ghost dao app. Check the link on your own, we are not in charge of your destiny.
+
+
+ {url}
+
+
+
+ window.open(url, '_blank', 'noopener,noreferrer')}
+ >
+ Open
+
+
+
+ )
+}
+
+export default ProposalDiscussionModal;
diff --git a/src/containers/Governance/components/ProposalInfoText.jsx b/src/containers/Governance/components/ProposalInfoText.jsx
new file mode 100644
index 0000000..a2ea4c9
--- /dev/null
+++ b/src/containers/Governance/components/ProposalInfoText.jsx
@@ -0,0 +1,23 @@
+import { Link, Typography, useTheme } from "@mui/material";
+
+const ProposalInfoText = () => {
+ const theme = useTheme();
+ return (
+
+ Important: We display only the 10 most recent proposals. Only one proposal can be active at a time.
+ Learn more here.
+
+ )
+};
+
+export default ProposalInfoText;
diff --git a/src/containers/Governance/components/ProposalsList.jsx b/src/containers/Governance/components/ProposalsList.jsx
new file mode 100644
index 0000000..9f0b567
--- /dev/null
+++ b/src/containers/Governance/components/ProposalsList.jsx
@@ -0,0 +1,316 @@
+import { useState, useMemo } from "react";
+import { useNavigate } from "react-router-dom";
+
+import {
+ Box,
+ Link,
+ Tabs,
+ Tab,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow,
+ Typography,
+ useTheme,
+ useMediaQuery
+} from "@mui/material";
+import { NavLink } from "react-router-dom";
+import { getBlockNumber } from "@wagmi/core";
+
+import { networkAvgBlockSpeed } from "../../../constants";
+import { prettifySecondsInDays } from "../../../helpers/timeUtil";
+
+import Chip from "../../../components/Chip/Chip";
+import Modal from "../../../components/Modal/Modal";
+import Paper from "../../../components/Paper/Paper";
+import LinearProgressBar from "../../../components/Progress/LinearProgressBar";
+import { PrimaryButton, TertiaryButton } from "../../../components/Button";
+
+import ProposalDiscussionModal from "./ProposalDiscussionModal";
+import ProposalDiscussion from "./ProposalDiscussion";
+import ProposalInfoText from "./ProposalInfoText";
+import { convertStatusToTemplate } from "../helpers";
+
+import { useScreenSize } from "../../../hooks/useScreenSize";
+
+import {
+ useProposals,
+} from "../../../hooks/governance";
+
+const MAX_PROPOSALS_TO_SHOW = 10;
+
+const ProposalsList = ({ chainId, config }) => {
+ const isSmallScreen = useScreenSize("md");
+ const navigate = useNavigate();
+
+ const [blockNumber, setBlockNumber] = useState(0n);
+ const [selectedDiscussionUrl, setSelectedDiscussionUrl] = useState(undefined);
+ const [proposalsFilter, setProposalFilter] = useState("active");
+ const { proposals } = useProposals(chainId, MAX_PROPOSALS_TO_SHOW);
+
+ getBlockNumber(config).then(block => setBlockNumber(block));
+
+ const isDiscussionModalOpened = useMemo(() => {
+ return selectedDiscussionUrl !== undefined;
+ }, [selectedDiscussionUrl]);
+
+ const filteredProposals = useMemo(() => {
+ switch (proposalsFilter) {
+ case "voted":
+ return proposals.filter(obj => obj.status === "Succeeded" || obj.status === "Defeated");
+ case "created":
+ return proposals.filter(obj => obj.status === "Executed");
+ default:
+ return proposals;
+ }
+ }, [proposals, proposalsFilter]);
+
+ if (proposals?.length === 0) {
+ return (
+
+ No proposals yet
+
+ );
+ }
+
+ if (isSmallScreen) {
+ return (
+ <>
+ setSelectedDiscussionUrl(undefined)}
+ />
+
+
+
+
+
+
+ {filteredProposals?.map(proposal => (
+ navigate(`/governance/${proposal.id}`)}
+ />
+ ))}
+
+
+ >
+ );
+ }
+
+ return (
+ <>
+ setSelectedDiscussionUrl(undefined)}
+ />
+
+
+
+
+ {filteredProposals?.map(proposal => (
+ navigate(`/governance/${proposal.id}`)}
+ />
+ ))}
+
+
+
+
+
+
+ >
+ );
+}
+
+const ProposalTable = ({ children }) => (
+
+
+
+
+ Proposal ID
+ Status
+ Discussion
+ Vote Ends
+ Voting Stats
+
+
+
+
+ {children}
+
+
+);
+
+const ProposalRow = ({ proposal, setActive, blockNumber, openProposal, chainId }) => {
+ const theme = useTheme();
+
+ return (
+
+
+ GDP-{proposal.id}
+
+
+
+
+
+
+
+ setActive(proposal.discussion)} />
+
+
+
+
+ {convertVoteEnds(
+ proposal.id % 2n === 0n,
+ proposal.voteEnds,
+ blockNumber,
+ chainId
+ )}
+
+
+
+
+
+
+
+
+
+
+ {(proposal.status === "Active" || proposal.status === "Succeeded") && openProposal()}
+ sx={{ maxWidth: "150px" }}
+ >
+ {proposal.status === "Succeeded" ? "Execute" : "Vote"}
+ }
+ {(proposal.status !== "Active" && proposal.status !== "Succeeded") && openProposal()}
+ sx={{ maxWidth: "150px" }}
+ >
+ View
+ }
+
+
+ );
+}
+
+const ProposalCard = ({ proposal, setActive, blockNumber, openProposal, chainId }) => {
+ const theme = useTheme();
+ const isSmallScreen = useMediaQuery('(max-width: 450px)');
+
+ return (
+
+
+
+
+ GIP-{proposal.id}
+
+
+
+ {convertVoteEnds(
+ proposal.id % 2n === 0n,
+ proposal.voteEnds,
+ blockNumber,
+ chainId
+ )}
+
+
+
+ setActive(proposal.discussion)}
+ />
+
+
+
+
+
+
+
+ {(proposal.status === "Active" || proposal.status === "Succeeded") && openProposal()}
+ >
+ {proposal.status === "Succeeded" ? "Execute" : "Vote"}
+ }
+ {(proposal.status !== "Active" && proposal.status !== "Succeeded") && openProposal()}
+ >
+ View
+ }
+
+
+ );
+};
+
+const ProposalFilterTrigger = ({ trigger, setTrigger }) => {
+ return (
+ setTrigger(view)}
+ TabIndicatorProps={{ style: { display: "none" } }}
+ >
+
+
+
+
+ )
+}
+
+const convertVoteEnds = (tmp, voteEnds, blockNumber, chainId) => {
+ const tmpVoteSeconds = Number(voteEnds * networkAvgBlockSpeed(chainId));
+ const tmpSeconds = (tmp ? tmpVoteSeconds : -tmpVoteSeconds);
+
+ const result = prettifySecondsInDays(tmpSeconds);
+ if (result === "now") {
+ return new Date(Date.now()).toLocaleDateString('en-US', {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric'
+ });
+ }
+
+ return `in ${result}`;
+}
+
+export default ProposalsList;
diff --git a/src/containers/Governance/helpers.js b/src/containers/Governance/helpers.js
new file mode 100644
index 0000000..505d17a
--- /dev/null
+++ b/src/containers/Governance/helpers.js
@@ -0,0 +1,14 @@
+export const convertStatusToTemplate = (status) => {
+ switch (status.toUpperCase()) {
+ case "EXECUTED":
+ return 'info';
+ case "CANCELED":
+ return 'warning';
+ case "SUCCEEDED":
+ return 'success';
+ case "DEFEATED":
+ return 'error';
+ default:
+ return 'info';
+ }
+}
diff --git a/src/containers/Stake/StakeContainer.jsx b/src/containers/Stake/StakeContainer.jsx
index 49e3f4a..e404bcc 100644
--- a/src/containers/Stake/StakeContainer.jsx
+++ b/src/containers/Stake/StakeContainer.jsx
@@ -1,5 +1,5 @@
import { Dispatch, SetStateAction, useState, useEffect } from "react";
-import { Box, Container, Grid, Divider, Typography, Link, useMediaQuery, useTheme } from "@mui/material";
+import { Box, Container, Grid, Divider, Typography, useMediaQuery, useTheme } from "@mui/material";
import ReactGA from "react-ga4";
import Paper from "../../components/Paper/Paper";
@@ -47,7 +47,7 @@ export const StakeContainer = ({ chainId, address, connect }) => {
}
return (
-
+
{
+ const numerator = 69n;
+ const denominator = 100n;
+
+ let percentage = 0;
+
+ if (numerator && denominator && denominator > 0n) {
+ percentage = Number(100n * numerator / denominator) / 100;
+ }
+
+ return { numerator, denominator, percentage }
+}
+
+export const useProposalThreshold = (chainId, name) => {
+ const decimals = getTokenDecimals(name);
+ const threshold = new DecimalBigNumber(420_000_000_000_000_000_000n, decimals);
+
+ return { threshold };
+}
+
+export const useProposalCount = (chainId) => {
+ const proposalsCount = 1337n;
+ return { proposalsCount };
+}
+
+export const useProposalStatus = (chainId, proposalId) => {
+ const status = "Succeeded";
+ return { status };
+}
+
+export const useProposalProposer = (chainId, proposalId) => {
+ const proposer = "0x71C7656EC7ab88b098defB751B7401B5f6d8976F";
+ return { proposer };
+}
+
+export const useProposalLocked = (chainId, proposalId) => {
+ const decimals = getTokenDecimals(name);
+ const locked = new DecimalBigNumber(420_000_000_000_000_000_000n, decimals);
+ return { locked }
+}
+
+export const useProposalQuorum = (chainId, proposalId) => {
+ const decimals = getTokenDecimals(name);
+ const quorum = new DecimalBigNumber(1337_000_000_000_000_000_000n, decimals);
+ return { quorum }
+}
+
+export const useProposalVotes = (chainId, proposalId) => {
+ const decimals = getTokenDecimals(name);
+ const forVotes = new DecimalBigNumber(420_000_000_000_000_000_000n, decimals);
+ const againstVotes = new DecimalBigNumber(69_000_000_000_000_000_000n, decimals);
+ return { forVotes, againstVotes }
+}
+
+export const useProposalSnapshot = (chainId, proposalId) => {
+ const snapshot = Math.floor((Date.now() - (3 * 24 * 60 * 60 * 1000)) / 1000);
+ return { snapshot };
+}
+
+export const useProposalDeadline = (chainId, proposalId) => {
+ const deadline = Math.floor(Date.now() / 1000);
+ return { deadline };
+}
+
+export const useProposalVotingDelay = (chainId, proposalId) => {
+ const delay = 1;
+ return { delay };
+}
+
+export const useProposals = (chainId, depth) => {
+ const decimals = getTokenDecimals(name);
+ const { proposalsCount } = useProposalCount(chainId);
+
+ let iterator = proposalsCount ? proposalsCount : 0n;
+ const bigIntDepth = BigInt(depth);
+ const edgeProposalId = iterator > bigIntDepth ? iterator - bigIntDepth : 0n;
+
+ const statuses = [
+ "Active",
+ "Executed",
+ "Canceled",
+ "Succeeded",
+ "Defeated"
+ ];
+ let proposals = [];
+
+ while (iterator > proposalsCount - bigIntDepth) {
+ iterator -= 1n;
+
+ const voteEnds = 50n;
+ const yesVotes = new DecimalBigNumber(1337_000_000_000_000_000_000, decimals);
+ const noVotes = new DecimalBigNumber(420_000_000_000_000_000_000, decimals);
+
+ proposals.push({
+ id: iterator,
+ discussion: "https://google.com",
+ status: statuses[Number(iterator) % statuses.length],
+ voteEnds,
+ yesVotes,
+ noVotes
+ });
+ }
+
+ return { proposals };
+}