diff --git a/.nvmrc b/.nvmrc
index 91f7588a..bb8c76c6 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v18.20.0
+v22.11.0
diff --git a/package.json b/package.json
index e6f2db0c..432d1a4b 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.57",
- "@microsoft/signalr": "^5.0.9",
+ "@microsoft/signalr": "9.0.6",
"@mui/icons-material": "^5.14.14",
"@mui/material": "^5.14.14",
"@mui/x-date-pickers": "^5.0.2",
@@ -47,7 +47,6 @@
"assert-never": "^1.3.0",
"bignumber.js": "^9.0.1",
"blockies-ts": "^1.0.0",
- "caniuse-lite": "",
"connectkit": "^1.8.2",
"crypto-browserify": "^3.12.0",
"dayjs": "^1.11.11",
diff --git a/src/modules/explorer/components/DAOStatsRow.tsx b/src/modules/explorer/components/DAOStatsRow.tsx
index e692e144..2b347043 100644
--- a/src/modules/explorer/components/DAOStatsRow.tsx
+++ b/src/modules/explorer/components/DAOStatsRow.tsx
@@ -145,7 +145,7 @@ const DAOStatsRowTezos = () => {
Current Cycle
- {cycleInfo?.currentCycle}
+ {cycleInfo?.currentCycle ?? "-"}
diff --git a/src/services/bakingBad/context/TZKTSubscriptions.tsx b/src/services/bakingBad/context/TZKTSubscriptions.tsx
index 4384087d..0e3f77c9 100644
--- a/src/services/bakingBad/context/TZKTSubscriptions.tsx
+++ b/src/services/bakingBad/context/TZKTSubscriptions.tsx
@@ -31,16 +31,24 @@ const TZKTSubscriptionsProvider: React.FC = ({ children }) => {
useEffect(() => {
if (network.startsWith("etherlink")) return
;(async () => {
- socketRef.current = new HubConnectionBuilder().withUrl(getUrl(network)).build()
+ socketRef.current = new HubConnectionBuilder().withUrl(getUrl(network)).withAutomaticReconnect().build()
- await socketRef.current.start()
+ try {
+ await socketRef.current.start()
+ } catch (e) {
+ console.warn("TZKT SignalR start failed", e)
+ return
+ }
- // listen for incoming message
socketRef.current.on("blocks", (blockMessage: BlockMessage) => {
setBlock(blockMessage.state)
})
- await socketRef.current.invoke("SubscribeToBlocks")
+ try {
+ await socketRef.current.invoke("SubscribeToBlocks")
+ } catch (e) {
+ console.warn("TZKT SignalR subscribe failed", e)
+ }
})()
return () => {
diff --git a/src/services/services/dao/hooks/useDAO.ts b/src/services/services/dao/hooks/useDAO.ts
index 3c6548c6..916a627d 100644
--- a/src/services/services/dao/hooks/useDAO.ts
+++ b/src/services/services/dao/hooks/useDAO.ts
@@ -10,7 +10,7 @@ import { unpackExtraNumValue, CycleInfo } from "services/contracts/baseDAO"
import { LambdaDAO } from "services/contracts/baseDAO/lambdaDAO"
import { parseUnits } from "services/contracts/utils"
import { getDAO } from "services/services/dao/services"
-import { useBlockchainInfo } from "../../../contracts/baseDAO/hooks/useBlockchainInfo"
+import { getNetworkStats, getNetworkHead } from "../../../bakingBad/stats"
import { fetchLiteData } from "services/services/lite/lite-services"
import { EtherlinkContext } from "services/wagmi/context"
@@ -20,7 +20,6 @@ export const useDAO = (address: string) => {
const [daoData, setDaoData] = useState(null)
const [cycleInfo, setCycleInfo] = useState()
const { network } = useTezos()
- const { data: blockchainInfo } = useBlockchainInfo()
const {
daos: etherlinkOnchainDAOs,
selectDao: selectEtherlinkDao,
@@ -120,26 +119,61 @@ export const useDAO = (address: string) => {
useEffect(() => {
;(async () => {
- if ((data as any)?.address === "onchain-etherlink") {
- console.log("No cycle info for etherlink")
- return
- } else if (data && blockchainInfo) {
- const blockTimeAverage = blockchainInfo.constants.timeBetweenBlocks
- const blocksFromStart = block - data.data.start_level
- const periodsFromStart = Math.floor(blocksFromStart / Number(data.data.period))
- const type = periodsFromStart % 2 == 0 ? "voting" : "proposing"
- const blocksLeft = Number(data.data.period) - (blocksFromStart % Number(data.data.period))
+ if (!data) return
+ const daoNetwork = data.data.network as Network
+ if ((data as any)?.address === "onchain-etherlink" || daoNetwork?.startsWith("etherlink")) return
- setCycleInfo({
- blocksLeft,
- type,
- timeEstimateForNextBlock: blockTimeAverage,
- currentCycle: periodsFromStart,
- currentLevel: block
- })
+ let effectiveBlock = 0
+ if (network === daoNetwork && block > 0) {
+ effectiveBlock = block
+ } else {
+ try {
+ effectiveBlock = await getNetworkHead(daoNetwork)
+ } catch (e) {
+ return
+ }
}
+ if (effectiveBlock <= 0) return
+
+ let blockTimeAverage = 30
+ try {
+ const stats = await getNetworkStats(daoNetwork)
+ blockTimeAverage = stats.constants.timeBetweenBlocks
+ } catch {}
+
+ const period = Number(data.data.period)
+ // Include flush delay in the total cycle length
+ const proposalFlushLevel = Number(data.data.proposal_flush_level)
+ const proposalExpiredLevel = Number(data.data.proposal_expired_level)
+ const flushDelayBlocks = Math.max(proposalFlushLevel - 2 * period, 0)
+ const proposalBlocksToExpire = Math.max(proposalExpiredLevel - proposalFlushLevel, 0)
+ const totalCycleBlocks = period + flushDelayBlocks + proposalBlocksToExpire
+ // Debug logs for cycle calculation inputs
+ console.log("useDAO.ts cycle inputs", {
+ CurrentBlock: effectiveBlock,
+ BlockAtWhichDaoMinted: data.data.start_level,
+ TotalDaoLifeCycleBlocks: totalCycleBlocks
+ })
+ const blocksFromStart = effectiveBlock - data.data.start_level
+ if (blocksFromStart < 0) return
+ if (totalCycleBlocks <= 0) return
+ // Use full cycle (voting period + flush delay) for cycle count
+ const cyclesFromStart = Math.floor(blocksFromStart / totalCycleBlocks)
+ // Keep UI period type based on the current voting/proposing period only
+ const periodsFromStartForType = Math.floor(blocksFromStart / period)
+ const type = periodsFromStartForType % 2 === 0 ? "voting" : "proposing"
+ // Blocks left in the current voting/proposal period
+ const blocksLeft = period - (blocksFromStart % period)
+
+ setCycleInfo({
+ blocksLeft,
+ type,
+ timeEstimateForNextBlock: blockTimeAverage,
+ currentCycle: cyclesFromStart,
+ currentLevel: effectiveBlock
+ })
})()
- }, [data, blockchainInfo, block, network])
+ }, [data, block, network])
useEffect(() => {
const dao = etherlinkDaoSelected
diff --git a/yarn.lock b/yarn.lock
index ad84f74e..914f887f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3235,16 +3235,16 @@
semver "^7.5.4"
uuid "^9.0.1"
-"@microsoft/signalr@^5.0.9":
- version "5.0.17"
- resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-5.0.17.tgz#c6d3038538b8e21b95a012a7eaa22f44d5cc72f4"
- integrity sha512-zTjFxjh67WWCe35ZipsqkktM5mM+MsckyyI2ZvFmYWR7ibpUoAyZI1DFdYfwXfsyBdlykDaW84o9lrB+9tDpaA==
+"@microsoft/signalr@9.0.6":
+ version "9.0.6"
+ resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-9.0.6.tgz#67dd074941c2ec2b857f607504c920a0c6274e27"
+ integrity sha512-DrhgzFWI9JE4RPTsHYRxh4yr+OhnwKz8bnJe7eIi7mLLjqhJpEb62CiUy/YbFvLqLzcGzlzz1QWgVAW0zyipMQ==
dependencies:
abort-controller "^3.0.0"
- eventsource "^1.0.7"
- fetch-cookie "^0.7.3"
+ eventsource "^2.0.2"
+ fetch-cookie "^2.0.3"
node-fetch "^2.6.7"
- ws "^6.0.0"
+ ws "^7.5.10"
"@motionone/animation@^10.12.0", "@motionone/animation@^10.15.1", "@motionone/animation@^10.18.0":
version "10.18.0"
@@ -5967,11 +5967,6 @@ astral-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
-async-limiter@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
- integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
-
async-mutex@^0.2.6:
version "0.2.6"
resolved "https://registry.yarnpkg.com/async-mutex/-/async-mutex-0.2.6.tgz#0d7a3deb978bc2b984d5908a2038e1ae2e54ff40"
@@ -6655,20 +6650,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
-caniuse-lite@:
- version "1.0.30001651"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138"
- integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==
-
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001663:
- version "1.0.30001668"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz#98e214455329f54bf7a4d70b49c9794f0fbedbed"
- integrity sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw==
-
-caniuse-lite@^1.0.30001599:
- version "1.0.30001600"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz#93a3ee17a35aa6a9f0c6ef1b2ab49507d1ab9079"
- integrity sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001663:
+ version "1.0.30001741"
+ resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001741.tgz"
+ integrity sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==
case-sensitive-paths-webpack-plugin@^2.4.0:
version "2.4.0"
@@ -8305,11 +8290,6 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
-es6-denodeify@^0.1.1:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f"
- integrity sha512-731Rf4NqlPvhkT1pIF7r8vZxESJlWocNpXLuyPlVnfEGXlwuJaMvU5WpyyDjpudDC2cgXVX849xljzvQqBg1QQ==
-
escalade@^3.1.1, escalade@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
@@ -8829,10 +8809,10 @@ events@3.3.0, events@^3.2.0, events@^3.3.0:
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
-eventsource@^1.0.7:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.2.tgz#bc75ae1c60209e7cb1541231980460343eaea7c2"
- integrity sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA==
+eventsource@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508"
+ integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==
evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
version "1.0.3"
@@ -9063,13 +9043,13 @@ fb-watchman@^2.0.0:
dependencies:
bser "2.1.1"
-fetch-cookie@^0.7.3:
- version "0.7.3"
- resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.7.3.tgz#b8d023f421dd2b2f4a0eca9cd7318a967ed4eed8"
- integrity sha512-rZPkLnI8x5V+zYAiz8QonAHsTb4BY+iFowFBI1RFn0zrO343AVp9X7/yUj/9wL6Ef/8fLls8b/vGtzUvmyAUGA==
+fetch-cookie@^2.0.3:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-2.2.0.tgz#01086b6b5b1c3e08f15ffd8647b02ca100377365"
+ integrity sha512-h9AgfjURuCgA2+2ISl8GbavpUdR+WGAM2McW/ovn4tVccegp8ZqCKWSBR8uRdM8dDNlx5WdKRWxBYUwteLDCNQ==
dependencies:
- es6-denodeify "^0.1.1"
- tough-cookie "^2.3.3"
+ set-cookie-parser "^2.4.8"
+ tough-cookie "^4.0.0"
fflate@^0.4.8:
version "0.4.8"
@@ -14319,7 +14299,7 @@ pseudomap@^1.0.2:
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==
-psl@^1.1.28, psl@^1.1.33:
+psl@^1.1.33:
version "1.9.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
@@ -15458,6 +15438,11 @@ set-blocking@^2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
+set-cookie-parser@^2.4.8:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943"
+ integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==
+
set-function-length@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
@@ -16431,14 +16416,6 @@ toposort@^2.0.2:
resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==
-tough-cookie@^2.3.3:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
- integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
- dependencies:
- psl "^1.1.28"
- punycode "^2.1.1"
-
tough-cookie@^4.0.0:
version "4.1.4"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36"
@@ -17695,14 +17672,7 @@ ws@8.17.1, ws@~8.17.1:
resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
-ws@^6.0.0:
- version "6.2.2"
- resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e"
- integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==
- dependencies:
- async-limiter "~1.0.0"
-
-ws@^7.4.6:
+ws@^7.4.6, ws@^7.5.10:
version "7.5.10"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9"
integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==