├── .env.local.example ├── .env.mainnet ├── .env.sepolia ├── .gitignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── config.ts ├── dao.ts ├── env.d.ts ├── eventProcessors.ts ├── events │ ├── core.ts │ ├── governor.ts │ ├── limitOrders.ts │ ├── nft.ts │ ├── oracle.ts │ ├── positions.ts │ ├── staker.ts │ ├── tokenRegistry.ts │ └── twamm.ts ├── index.ts ├── logger.ts ├── parse.test.ts ├── parse.ts ├── poolKeyHash.ts └── processor.ts └── tsconfig.json /.env.local.example: -------------------------------------------------------------------------------- 1 | DNA_TOKEN="token_from_apibara" 2 | NO_BLOCKS_TIMEOUT_MS="300000" # Default 5 minutes - exit if no blocks received -------------------------------------------------------------------------------- /.env.mainnet: -------------------------------------------------------------------------------- 1 | LOG_LEVEL="info" 2 | 3 | CORE_ADDRESS="0x00000005dd3D2F4429AF886cD1a3b08289DBcEa99A294197E9eB43b0e0325b4b" 4 | POSITIONS_ADDRESS="0x02e0af29598b407c8716b17f6d2795eca1b471413fa03fb145a5e33722184067" 5 | NFT_ADDRESS="0x07b696af58c967c1b14c9dde0ace001720635a660a8e90c565ea459345318b30" 6 | TOKEN_REGISTRY_ADDRESS="0x006f55e718ae592b22117c3e3b557b6b2b5f827ddcd7e6fdebd1a4ce7462c93e" 7 | TOKEN_REGISTRY_V2_ADDRESS="0x0013e25867b6eef62703735aa4cfa7754e72f4e94a56c9d3d9ad8ebe86cee4aa" 8 | TOKEN_REGISTRY_V3_ADDRESS="0x064bdb4094881140bc39340146c5fcc5a187a98aec5a53f448ac702e5de5067e" 9 | TWAMM_ADDRESS="0x043e4f09c32d13d43a880e85f69f7de93ceda62d6cf2581a582c6db635548fdc" 10 | ORACLE_ADDRESS="0x005e470ff654d834983a46b8f29dfa99963d5044b993cb7b9c92243a69dab38f" 11 | LIMIT_ORDERS_ADDRESS="0x050ed6ab03aef492cd062e25facf40ceef63294c53d12b514226f8fb4753266e" 12 | 13 | STAKER_ADDRESS="0x02a3ed03046e1042e193651e3da6d3c973e3d45c624442be936a374380a78bb5" 14 | GOVERNOR_ADDRESS="0x053499f7aa2706395060fe72d00388803fb2dcc111429891ad7b2d9dcea29acd" 15 | 16 | STARTING_CURSOR_BLOCK_NUMBER="165389" 17 | 18 | APIBARA_URL="starknet.preview.apibara.org" 19 | 20 | REFRESH_RATE_ANALYTICAL_VIEWS=300000 21 | 22 | PG_CONNECTION_STRING="postgresql://postgres:postgres@localhost:5432/mainnet" 23 | -------------------------------------------------------------------------------- /.env.sepolia: -------------------------------------------------------------------------------- 1 | LOG_LEVEL="info" 2 | 3 | CORE_ADDRESS="0x0444a09d96389aa7148f1aada508e30b71299ffe650d9c97fdaae38cb9a23384" 4 | POSITIONS_ADDRESS="0x06a2aee84bb0ed5dded4384ddd0e40e9c1372b818668375ab8e3ec08807417e5" 5 | NFT_ADDRESS="0x04afc78d6fec3b122fc1f60276f074e557749df1a77a93416451be72c435120f" 6 | TOKEN_REGISTRY_ADDRESS="0x0293c0d738eff5aa65619069d437eba2bcb320fb8003f37c9708afcdbe8739c8" 7 | TOKEN_REGISTRY_V2_ADDRESS="0x0" 8 | TOKEN_REGISTRY_V3_ADDRESS="0x04484f91f0d2482bad844471ca8dc8e846d3a0211792322e72f21f0f44be63e5" 9 | TWAMM_ADDRESS="0x073ec792c33b52d5f96940c2860d512b3884f2127d25e023eb9d44a678e4b971" 10 | ORACLE_ADDRESS="0x003ccf3ee24638dd5f1a51ceb783e120695f53893f6fd947cc2dcabb3f86dc65" 11 | LIMIT_ORDERS_ADDRESS="0x00c4c863f6de467b91ce974be48cc17ad7209d0d600926e82845a43a7848b822" 12 | 13 | STAKER_ADDRESS="0x0359c9a32c758a162a6c59a9cff93f09a2eb2dbe82cba9ecbdd64aa4314f8687" 14 | GOVERNOR_ADDRESS="0x048bb83134ce6a312d1b41b0b3deccc4ce9a9d280e6c68c0eb1c517259c89d74" 15 | 16 | STARTING_CURSOR_BLOCK_NUMBER="21323" 17 | 18 | APIBARA_URL="starknet-sepolia.preview.apibara.org" 19 | 20 | REFRESH_RATE_ANALYTICAL_VIEWS=300000 21 | 22 | PG_CONNECTION_STRING="postgresql://postgres:postgres@localhost:5432/sepolia" 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env.sepolia.local 2 | .env.mainnet.local 3 | .env.local 4 | *.cursor.json 5 | dist/ 6 | node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ekubo, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `@ekubo/indexer` 2 | 3 | Service for indexing Ekubo events into a Postgres database. 4 | 5 | ## Overview 6 | 7 | The indexer focuses on producing an always-consistent realtime view of Ekubo events, using the Apibara service to get a stream of relevant data. 8 | 9 | Events are not transformed by the indexer, simply cataloged for later use such as in materialized views or complex analytical queries. 10 | 11 | ## Syncing a new node 12 | 13 | It can take weeks to sync a new mainnet node, so it's recommended to start from a backup of our production database. 14 | 15 | Join the [Discord](https://discord.ekubo.org) and ask in the `#devs` channel to get the latest export of the data. -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ekubo/indexer", 3 | "version": "0.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@ekubo/indexer", 9 | "version": "0.0.1", 10 | "dependencies": { 11 | "@apibara/protocol": "^2.1.0-beta.34", 12 | "@apibara/starknet": "^2.1.0-beta.34", 13 | "dotenv": "^16.4.7", 14 | "jiti": "^2.4.2", 15 | "pg": "^8.13.1", 16 | "tadaaa": "^1.0.1", 17 | "winston": "^3.17.0" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^22.10.7", 21 | "@types/pg": "^8.11.10", 22 | "typescript": "^5.7.3", 23 | "vitest": "^3.0.2" 24 | }, 25 | "engines": { 26 | "node": "^22.10.0" 27 | } 28 | }, 29 | "node_modules/@adraffy/ens-normalize": { 30 | "version": "1.11.0", 31 | "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz", 32 | "integrity": "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==" 33 | }, 34 | "node_modules/@apibara/protocol": { 35 | "version": "2.1.0-beta.34", 36 | "resolved": "https://registry.npmjs.org/@apibara/protocol/-/protocol-2.1.0-beta.34.tgz", 37 | "integrity": "sha512-FlIrKSa00bro6nGLJXgN+damD96x3fOu5pC2oo72agVWqpOWRGvmdMZNuX+l3+B5mDQi/GMqDedGTC8xxbUXXQ==", 38 | "dependencies": { 39 | "long": "^5.2.3", 40 | "nice-grpc": "^2.1.8", 41 | "nice-grpc-common": "^2.0.2", 42 | "protobufjs": "^7.3.0", 43 | "viem": "^2.13.2" 44 | } 45 | }, 46 | "node_modules/@apibara/starknet": { 47 | "version": "2.1.0-beta.34", 48 | "resolved": "https://registry.npmjs.org/@apibara/starknet/-/starknet-2.1.0-beta.34.tgz", 49 | "integrity": "sha512-tzSMdA1ix2iX4nzo+Cd99DA4nT/fuKYqAIZdbWVb74FCJhNQN2fOvtzhYSCRXZ4WH46odm3lA0gd1JZOGO+hcA==", 50 | "dependencies": { 51 | "@apibara/protocol": "2.1.0-beta.34", 52 | "@scure/starknet": "^1.1.0", 53 | "abi-wan-kanabi": "^2.2.4", 54 | "effect": "^3.2.6", 55 | "long": "^5.2.1", 56 | "nice-grpc-common": "^2.0.2", 57 | "protobufjs": "^7.1.2" 58 | } 59 | }, 60 | "node_modules/@colors/colors": { 61 | "version": "1.6.0", 62 | "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", 63 | "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", 64 | "engines": { 65 | "node": ">=0.1.90" 66 | } 67 | }, 68 | "node_modules/@dabh/diagnostics": { 69 | "version": "2.0.3", 70 | "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", 71 | "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", 72 | "dependencies": { 73 | "colorspace": "1.1.x", 74 | "enabled": "2.0.x", 75 | "kuler": "^2.0.0" 76 | } 77 | }, 78 | "node_modules/@esbuild/aix-ppc64": { 79 | "version": "0.24.2", 80 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", 81 | "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", 82 | "cpu": [ 83 | "ppc64" 84 | ], 85 | "dev": true, 86 | "optional": true, 87 | "os": [ 88 | "aix" 89 | ], 90 | "engines": { 91 | "node": ">=18" 92 | } 93 | }, 94 | "node_modules/@esbuild/android-arm": { 95 | "version": "0.24.2", 96 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", 97 | "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", 98 | "cpu": [ 99 | "arm" 100 | ], 101 | "dev": true, 102 | "optional": true, 103 | "os": [ 104 | "android" 105 | ], 106 | "engines": { 107 | "node": ">=18" 108 | } 109 | }, 110 | "node_modules/@esbuild/android-arm64": { 111 | "version": "0.24.2", 112 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", 113 | "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", 114 | "cpu": [ 115 | "arm64" 116 | ], 117 | "dev": true, 118 | "optional": true, 119 | "os": [ 120 | "android" 121 | ], 122 | "engines": { 123 | "node": ">=18" 124 | } 125 | }, 126 | "node_modules/@esbuild/android-x64": { 127 | "version": "0.24.2", 128 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", 129 | "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", 130 | "cpu": [ 131 | "x64" 132 | ], 133 | "dev": true, 134 | "optional": true, 135 | "os": [ 136 | "android" 137 | ], 138 | "engines": { 139 | "node": ">=18" 140 | } 141 | }, 142 | "node_modules/@esbuild/darwin-arm64": { 143 | "version": "0.24.2", 144 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", 145 | "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", 146 | "cpu": [ 147 | "arm64" 148 | ], 149 | "dev": true, 150 | "optional": true, 151 | "os": [ 152 | "darwin" 153 | ], 154 | "engines": { 155 | "node": ">=18" 156 | } 157 | }, 158 | "node_modules/@esbuild/darwin-x64": { 159 | "version": "0.24.2", 160 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", 161 | "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", 162 | "cpu": [ 163 | "x64" 164 | ], 165 | "dev": true, 166 | "optional": true, 167 | "os": [ 168 | "darwin" 169 | ], 170 | "engines": { 171 | "node": ">=18" 172 | } 173 | }, 174 | "node_modules/@esbuild/freebsd-arm64": { 175 | "version": "0.24.2", 176 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", 177 | "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", 178 | "cpu": [ 179 | "arm64" 180 | ], 181 | "dev": true, 182 | "optional": true, 183 | "os": [ 184 | "freebsd" 185 | ], 186 | "engines": { 187 | "node": ">=18" 188 | } 189 | }, 190 | "node_modules/@esbuild/freebsd-x64": { 191 | "version": "0.24.2", 192 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", 193 | "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", 194 | "cpu": [ 195 | "x64" 196 | ], 197 | "dev": true, 198 | "optional": true, 199 | "os": [ 200 | "freebsd" 201 | ], 202 | "engines": { 203 | "node": ">=18" 204 | } 205 | }, 206 | "node_modules/@esbuild/linux-arm": { 207 | "version": "0.24.2", 208 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", 209 | "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", 210 | "cpu": [ 211 | "arm" 212 | ], 213 | "dev": true, 214 | "optional": true, 215 | "os": [ 216 | "linux" 217 | ], 218 | "engines": { 219 | "node": ">=18" 220 | } 221 | }, 222 | "node_modules/@esbuild/linux-arm64": { 223 | "version": "0.24.2", 224 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", 225 | "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", 226 | "cpu": [ 227 | "arm64" 228 | ], 229 | "dev": true, 230 | "optional": true, 231 | "os": [ 232 | "linux" 233 | ], 234 | "engines": { 235 | "node": ">=18" 236 | } 237 | }, 238 | "node_modules/@esbuild/linux-ia32": { 239 | "version": "0.24.2", 240 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", 241 | "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", 242 | "cpu": [ 243 | "ia32" 244 | ], 245 | "dev": true, 246 | "optional": true, 247 | "os": [ 248 | "linux" 249 | ], 250 | "engines": { 251 | "node": ">=18" 252 | } 253 | }, 254 | "node_modules/@esbuild/linux-loong64": { 255 | "version": "0.24.2", 256 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", 257 | "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", 258 | "cpu": [ 259 | "loong64" 260 | ], 261 | "dev": true, 262 | "optional": true, 263 | "os": [ 264 | "linux" 265 | ], 266 | "engines": { 267 | "node": ">=18" 268 | } 269 | }, 270 | "node_modules/@esbuild/linux-mips64el": { 271 | "version": "0.24.2", 272 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", 273 | "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", 274 | "cpu": [ 275 | "mips64el" 276 | ], 277 | "dev": true, 278 | "optional": true, 279 | "os": [ 280 | "linux" 281 | ], 282 | "engines": { 283 | "node": ">=18" 284 | } 285 | }, 286 | "node_modules/@esbuild/linux-ppc64": { 287 | "version": "0.24.2", 288 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", 289 | "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", 290 | "cpu": [ 291 | "ppc64" 292 | ], 293 | "dev": true, 294 | "optional": true, 295 | "os": [ 296 | "linux" 297 | ], 298 | "engines": { 299 | "node": ">=18" 300 | } 301 | }, 302 | "node_modules/@esbuild/linux-riscv64": { 303 | "version": "0.24.2", 304 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", 305 | "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", 306 | "cpu": [ 307 | "riscv64" 308 | ], 309 | "dev": true, 310 | "optional": true, 311 | "os": [ 312 | "linux" 313 | ], 314 | "engines": { 315 | "node": ">=18" 316 | } 317 | }, 318 | "node_modules/@esbuild/linux-s390x": { 319 | "version": "0.24.2", 320 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", 321 | "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", 322 | "cpu": [ 323 | "s390x" 324 | ], 325 | "dev": true, 326 | "optional": true, 327 | "os": [ 328 | "linux" 329 | ], 330 | "engines": { 331 | "node": ">=18" 332 | } 333 | }, 334 | "node_modules/@esbuild/linux-x64": { 335 | "version": "0.24.2", 336 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", 337 | "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", 338 | "cpu": [ 339 | "x64" 340 | ], 341 | "dev": true, 342 | "optional": true, 343 | "os": [ 344 | "linux" 345 | ], 346 | "engines": { 347 | "node": ">=18" 348 | } 349 | }, 350 | "node_modules/@esbuild/netbsd-arm64": { 351 | "version": "0.24.2", 352 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", 353 | "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", 354 | "cpu": [ 355 | "arm64" 356 | ], 357 | "dev": true, 358 | "optional": true, 359 | "os": [ 360 | "netbsd" 361 | ], 362 | "engines": { 363 | "node": ">=18" 364 | } 365 | }, 366 | "node_modules/@esbuild/netbsd-x64": { 367 | "version": "0.24.2", 368 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", 369 | "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", 370 | "cpu": [ 371 | "x64" 372 | ], 373 | "dev": true, 374 | "optional": true, 375 | "os": [ 376 | "netbsd" 377 | ], 378 | "engines": { 379 | "node": ">=18" 380 | } 381 | }, 382 | "node_modules/@esbuild/openbsd-arm64": { 383 | "version": "0.24.2", 384 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", 385 | "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", 386 | "cpu": [ 387 | "arm64" 388 | ], 389 | "dev": true, 390 | "optional": true, 391 | "os": [ 392 | "openbsd" 393 | ], 394 | "engines": { 395 | "node": ">=18" 396 | } 397 | }, 398 | "node_modules/@esbuild/openbsd-x64": { 399 | "version": "0.24.2", 400 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", 401 | "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", 402 | "cpu": [ 403 | "x64" 404 | ], 405 | "dev": true, 406 | "optional": true, 407 | "os": [ 408 | "openbsd" 409 | ], 410 | "engines": { 411 | "node": ">=18" 412 | } 413 | }, 414 | "node_modules/@esbuild/sunos-x64": { 415 | "version": "0.24.2", 416 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", 417 | "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", 418 | "cpu": [ 419 | "x64" 420 | ], 421 | "dev": true, 422 | "optional": true, 423 | "os": [ 424 | "sunos" 425 | ], 426 | "engines": { 427 | "node": ">=18" 428 | } 429 | }, 430 | "node_modules/@esbuild/win32-arm64": { 431 | "version": "0.24.2", 432 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", 433 | "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", 434 | "cpu": [ 435 | "arm64" 436 | ], 437 | "dev": true, 438 | "optional": true, 439 | "os": [ 440 | "win32" 441 | ], 442 | "engines": { 443 | "node": ">=18" 444 | } 445 | }, 446 | "node_modules/@esbuild/win32-ia32": { 447 | "version": "0.24.2", 448 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", 449 | "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", 450 | "cpu": [ 451 | "ia32" 452 | ], 453 | "dev": true, 454 | "optional": true, 455 | "os": [ 456 | "win32" 457 | ], 458 | "engines": { 459 | "node": ">=18" 460 | } 461 | }, 462 | "node_modules/@esbuild/win32-x64": { 463 | "version": "0.24.2", 464 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", 465 | "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", 466 | "cpu": [ 467 | "x64" 468 | ], 469 | "dev": true, 470 | "optional": true, 471 | "os": [ 472 | "win32" 473 | ], 474 | "engines": { 475 | "node": ">=18" 476 | } 477 | }, 478 | "node_modules/@grpc/grpc-js": { 479 | "version": "1.12.5", 480 | "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.5.tgz", 481 | "integrity": "sha512-d3iiHxdpg5+ZcJ6jnDSOT8Z0O0VMVGy34jAnYLUX8yd36b1qn8f1TwOA/Lc7TsOh03IkPJ38eGI5qD2EjNkoEA==", 482 | "dependencies": { 483 | "@grpc/proto-loader": "^0.7.13", 484 | "@js-sdsl/ordered-map": "^4.4.2" 485 | }, 486 | "engines": { 487 | "node": ">=12.10.0" 488 | } 489 | }, 490 | "node_modules/@grpc/proto-loader": { 491 | "version": "0.7.13", 492 | "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", 493 | "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", 494 | "dependencies": { 495 | "lodash.camelcase": "^4.3.0", 496 | "long": "^5.0.0", 497 | "protobufjs": "^7.2.5", 498 | "yargs": "^17.7.2" 499 | }, 500 | "bin": { 501 | "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" 502 | }, 503 | "engines": { 504 | "node": ">=6" 505 | } 506 | }, 507 | "node_modules/@jridgewell/sourcemap-codec": { 508 | "version": "1.5.0", 509 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", 510 | "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", 511 | "dev": true 512 | }, 513 | "node_modules/@js-sdsl/ordered-map": { 514 | "version": "4.4.2", 515 | "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", 516 | "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", 517 | "funding": { 518 | "type": "opencollective", 519 | "url": "https://opencollective.com/js-sdsl" 520 | } 521 | }, 522 | "node_modules/@noble/curves": { 523 | "version": "1.7.0", 524 | "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.7.0.tgz", 525 | "integrity": "sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw==", 526 | "dependencies": { 527 | "@noble/hashes": "1.6.0" 528 | }, 529 | "engines": { 530 | "node": "^14.21.3 || >=16" 531 | }, 532 | "funding": { 533 | "url": "https://paulmillr.com/funding/" 534 | } 535 | }, 536 | "node_modules/@noble/curves/node_modules/@noble/hashes": { 537 | "version": "1.6.0", 538 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.0.tgz", 539 | "integrity": "sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ==", 540 | "engines": { 541 | "node": "^14.21.3 || >=16" 542 | }, 543 | "funding": { 544 | "url": "https://paulmillr.com/funding/" 545 | } 546 | }, 547 | "node_modules/@noble/hashes": { 548 | "version": "1.6.1", 549 | "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.6.1.tgz", 550 | "integrity": "sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w==", 551 | "engines": { 552 | "node": "^14.21.3 || >=16" 553 | }, 554 | "funding": { 555 | "url": "https://paulmillr.com/funding/" 556 | } 557 | }, 558 | "node_modules/@protobufjs/aspromise": { 559 | "version": "1.1.2", 560 | "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", 561 | "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" 562 | }, 563 | "node_modules/@protobufjs/base64": { 564 | "version": "1.1.2", 565 | "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", 566 | "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" 567 | }, 568 | "node_modules/@protobufjs/codegen": { 569 | "version": "2.0.4", 570 | "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", 571 | "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" 572 | }, 573 | "node_modules/@protobufjs/eventemitter": { 574 | "version": "1.1.0", 575 | "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", 576 | "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" 577 | }, 578 | "node_modules/@protobufjs/fetch": { 579 | "version": "1.1.0", 580 | "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", 581 | "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", 582 | "dependencies": { 583 | "@protobufjs/aspromise": "^1.1.1", 584 | "@protobufjs/inquire": "^1.1.0" 585 | } 586 | }, 587 | "node_modules/@protobufjs/float": { 588 | "version": "1.0.2", 589 | "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", 590 | "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" 591 | }, 592 | "node_modules/@protobufjs/inquire": { 593 | "version": "1.1.0", 594 | "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", 595 | "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" 596 | }, 597 | "node_modules/@protobufjs/path": { 598 | "version": "1.1.2", 599 | "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", 600 | "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" 601 | }, 602 | "node_modules/@protobufjs/pool": { 603 | "version": "1.1.0", 604 | "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", 605 | "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" 606 | }, 607 | "node_modules/@protobufjs/utf8": { 608 | "version": "1.1.0", 609 | "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", 610 | "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" 611 | }, 612 | "node_modules/@rollup/rollup-android-arm-eabi": { 613 | "version": "4.30.1", 614 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", 615 | "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", 616 | "cpu": [ 617 | "arm" 618 | ], 619 | "dev": true, 620 | "optional": true, 621 | "os": [ 622 | "android" 623 | ] 624 | }, 625 | "node_modules/@rollup/rollup-android-arm64": { 626 | "version": "4.30.1", 627 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", 628 | "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", 629 | "cpu": [ 630 | "arm64" 631 | ], 632 | "dev": true, 633 | "optional": true, 634 | "os": [ 635 | "android" 636 | ] 637 | }, 638 | "node_modules/@rollup/rollup-darwin-arm64": { 639 | "version": "4.30.1", 640 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", 641 | "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", 642 | "cpu": [ 643 | "arm64" 644 | ], 645 | "dev": true, 646 | "optional": true, 647 | "os": [ 648 | "darwin" 649 | ] 650 | }, 651 | "node_modules/@rollup/rollup-darwin-x64": { 652 | "version": "4.30.1", 653 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", 654 | "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", 655 | "cpu": [ 656 | "x64" 657 | ], 658 | "dev": true, 659 | "optional": true, 660 | "os": [ 661 | "darwin" 662 | ] 663 | }, 664 | "node_modules/@rollup/rollup-freebsd-arm64": { 665 | "version": "4.30.1", 666 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", 667 | "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", 668 | "cpu": [ 669 | "arm64" 670 | ], 671 | "dev": true, 672 | "optional": true, 673 | "os": [ 674 | "freebsd" 675 | ] 676 | }, 677 | "node_modules/@rollup/rollup-freebsd-x64": { 678 | "version": "4.30.1", 679 | "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", 680 | "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", 681 | "cpu": [ 682 | "x64" 683 | ], 684 | "dev": true, 685 | "optional": true, 686 | "os": [ 687 | "freebsd" 688 | ] 689 | }, 690 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 691 | "version": "4.30.1", 692 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", 693 | "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", 694 | "cpu": [ 695 | "arm" 696 | ], 697 | "dev": true, 698 | "optional": true, 699 | "os": [ 700 | "linux" 701 | ] 702 | }, 703 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 704 | "version": "4.30.1", 705 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", 706 | "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", 707 | "cpu": [ 708 | "arm" 709 | ], 710 | "dev": true, 711 | "optional": true, 712 | "os": [ 713 | "linux" 714 | ] 715 | }, 716 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 717 | "version": "4.30.1", 718 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", 719 | "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", 720 | "cpu": [ 721 | "arm64" 722 | ], 723 | "dev": true, 724 | "optional": true, 725 | "os": [ 726 | "linux" 727 | ] 728 | }, 729 | "node_modules/@rollup/rollup-linux-arm64-musl": { 730 | "version": "4.30.1", 731 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", 732 | "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", 733 | "cpu": [ 734 | "arm64" 735 | ], 736 | "dev": true, 737 | "optional": true, 738 | "os": [ 739 | "linux" 740 | ] 741 | }, 742 | "node_modules/@rollup/rollup-linux-loongarch64-gnu": { 743 | "version": "4.30.1", 744 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", 745 | "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", 746 | "cpu": [ 747 | "loong64" 748 | ], 749 | "dev": true, 750 | "optional": true, 751 | "os": [ 752 | "linux" 753 | ] 754 | }, 755 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 756 | "version": "4.30.1", 757 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", 758 | "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", 759 | "cpu": [ 760 | "ppc64" 761 | ], 762 | "dev": true, 763 | "optional": true, 764 | "os": [ 765 | "linux" 766 | ] 767 | }, 768 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 769 | "version": "4.30.1", 770 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", 771 | "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", 772 | "cpu": [ 773 | "riscv64" 774 | ], 775 | "dev": true, 776 | "optional": true, 777 | "os": [ 778 | "linux" 779 | ] 780 | }, 781 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 782 | "version": "4.30.1", 783 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", 784 | "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", 785 | "cpu": [ 786 | "s390x" 787 | ], 788 | "dev": true, 789 | "optional": true, 790 | "os": [ 791 | "linux" 792 | ] 793 | }, 794 | "node_modules/@rollup/rollup-linux-x64-gnu": { 795 | "version": "4.30.1", 796 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", 797 | "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", 798 | "cpu": [ 799 | "x64" 800 | ], 801 | "dev": true, 802 | "optional": true, 803 | "os": [ 804 | "linux" 805 | ] 806 | }, 807 | "node_modules/@rollup/rollup-linux-x64-musl": { 808 | "version": "4.30.1", 809 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", 810 | "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", 811 | "cpu": [ 812 | "x64" 813 | ], 814 | "dev": true, 815 | "optional": true, 816 | "os": [ 817 | "linux" 818 | ] 819 | }, 820 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 821 | "version": "4.30.1", 822 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", 823 | "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", 824 | "cpu": [ 825 | "arm64" 826 | ], 827 | "dev": true, 828 | "optional": true, 829 | "os": [ 830 | "win32" 831 | ] 832 | }, 833 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 834 | "version": "4.30.1", 835 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", 836 | "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", 837 | "cpu": [ 838 | "ia32" 839 | ], 840 | "dev": true, 841 | "optional": true, 842 | "os": [ 843 | "win32" 844 | ] 845 | }, 846 | "node_modules/@rollup/rollup-win32-x64-msvc": { 847 | "version": "4.30.1", 848 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", 849 | "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", 850 | "cpu": [ 851 | "x64" 852 | ], 853 | "dev": true, 854 | "optional": true, 855 | "os": [ 856 | "win32" 857 | ] 858 | }, 859 | "node_modules/@scure/base": { 860 | "version": "1.2.4", 861 | "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.4.tgz", 862 | "integrity": "sha512-5Yy9czTO47mqz+/J8GM6GIId4umdCk1wc1q8rKERQulIoc8VP9pzDcghv10Tl2E7R96ZUx/PhND3ESYUQX8NuQ==", 863 | "funding": { 864 | "url": "https://paulmillr.com/funding/" 865 | } 866 | }, 867 | "node_modules/@scure/bip32": { 868 | "version": "1.6.0", 869 | "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.6.0.tgz", 870 | "integrity": "sha512-82q1QfklrUUdXJzjuRU7iG7D7XiFx5PHYVS0+oeNKhyDLT7WPqs6pBcM2W5ZdwOwKCwoE1Vy1se+DHjcXwCYnA==", 871 | "dependencies": { 872 | "@noble/curves": "~1.7.0", 873 | "@noble/hashes": "~1.6.0", 874 | "@scure/base": "~1.2.1" 875 | }, 876 | "funding": { 877 | "url": "https://paulmillr.com/funding/" 878 | } 879 | }, 880 | "node_modules/@scure/bip39": { 881 | "version": "1.5.0", 882 | "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.5.0.tgz", 883 | "integrity": "sha512-Dop+ASYhnrwm9+HA/HwXg7j2ZqM6yk2fyLWb5znexjctFY3+E+eU8cIWI0Pql0Qx4hPZCijlGq4OL71g+Uz30A==", 884 | "dependencies": { 885 | "@noble/hashes": "~1.6.0", 886 | "@scure/base": "~1.2.1" 887 | }, 888 | "funding": { 889 | "url": "https://paulmillr.com/funding/" 890 | } 891 | }, 892 | "node_modules/@scure/starknet": { 893 | "version": "1.1.0", 894 | "resolved": "https://registry.npmjs.org/@scure/starknet/-/starknet-1.1.0.tgz", 895 | "integrity": "sha512-83g3M6Ix2qRsPN4wqLDqiRZ2GBNbjVWfboJE/9UjfG+MHr6oDSu/CWgy8hsBSJejr09DkkL+l0Ze4KVrlCIdtQ==", 896 | "dependencies": { 897 | "@noble/curves": "~1.7.0", 898 | "@noble/hashes": "~1.6.0" 899 | }, 900 | "funding": { 901 | "url": "https://paulmillr.com/funding/" 902 | } 903 | }, 904 | "node_modules/@standard-schema/spec": { 905 | "version": "1.0.0", 906 | "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", 907 | "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", 908 | "license": "MIT" 909 | }, 910 | "node_modules/@types/estree": { 911 | "version": "1.0.6", 912 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", 913 | "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", 914 | "dev": true 915 | }, 916 | "node_modules/@types/node": { 917 | "version": "22.10.7", 918 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", 919 | "integrity": "sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==", 920 | "dependencies": { 921 | "undici-types": "~6.20.0" 922 | } 923 | }, 924 | "node_modules/@types/pg": { 925 | "version": "8.11.10", 926 | "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.10.tgz", 927 | "integrity": "sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==", 928 | "dev": true, 929 | "dependencies": { 930 | "@types/node": "*", 931 | "pg-protocol": "*", 932 | "pg-types": "^4.0.1" 933 | } 934 | }, 935 | "node_modules/@types/triple-beam": { 936 | "version": "1.3.5", 937 | "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", 938 | "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" 939 | }, 940 | "node_modules/@vitest/expect": { 941 | "version": "3.0.2", 942 | "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.2.tgz", 943 | "integrity": "sha512-dKSHLBcoZI+3pmP5hiZ7I5grNru2HRtEW8Z5Zp4IXog8QYcxhlox7JUPyIIFWfN53+3HW3KPLIl6nSzUGgKSuQ==", 944 | "dev": true, 945 | "dependencies": { 946 | "@vitest/spy": "3.0.2", 947 | "@vitest/utils": "3.0.2", 948 | "chai": "^5.1.2", 949 | "tinyrainbow": "^2.0.0" 950 | }, 951 | "funding": { 952 | "url": "https://opencollective.com/vitest" 953 | } 954 | }, 955 | "node_modules/@vitest/mocker": { 956 | "version": "3.0.2", 957 | "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.2.tgz", 958 | "integrity": "sha512-Hr09FoBf0jlwwSyzIF4Xw31OntpO3XtZjkccpcBf8FeVW3tpiyKlkeUzxS/txzHqpUCNIX157NaTySxedyZLvA==", 959 | "dev": true, 960 | "dependencies": { 961 | "@vitest/spy": "3.0.2", 962 | "estree-walker": "^3.0.3", 963 | "magic-string": "^0.30.17" 964 | }, 965 | "funding": { 966 | "url": "https://opencollective.com/vitest" 967 | }, 968 | "peerDependencies": { 969 | "msw": "^2.4.9", 970 | "vite": "^5.0.0 || ^6.0.0" 971 | }, 972 | "peerDependenciesMeta": { 973 | "msw": { 974 | "optional": true 975 | }, 976 | "vite": { 977 | "optional": true 978 | } 979 | } 980 | }, 981 | "node_modules/@vitest/pretty-format": { 982 | "version": "3.0.2", 983 | "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.2.tgz", 984 | "integrity": "sha512-yBohcBw/T/p0/JRgYD+IYcjCmuHzjC3WLAKsVE4/LwiubzZkE8N49/xIQ/KGQwDRA8PaviF8IRO8JMWMngdVVQ==", 985 | "dev": true, 986 | "dependencies": { 987 | "tinyrainbow": "^2.0.0" 988 | }, 989 | "funding": { 990 | "url": "https://opencollective.com/vitest" 991 | } 992 | }, 993 | "node_modules/@vitest/runner": { 994 | "version": "3.0.2", 995 | "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.2.tgz", 996 | "integrity": "sha512-GHEsWoncrGxWuW8s405fVoDfSLk6RF2LCXp6XhevbtDjdDme1WV/eNmUueDfpY1IX3MJaCRelVCEXsT9cArfEg==", 997 | "dev": true, 998 | "dependencies": { 999 | "@vitest/utils": "3.0.2", 1000 | "pathe": "^2.0.1" 1001 | }, 1002 | "funding": { 1003 | "url": "https://opencollective.com/vitest" 1004 | } 1005 | }, 1006 | "node_modules/@vitest/snapshot": { 1007 | "version": "3.0.2", 1008 | "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.2.tgz", 1009 | "integrity": "sha512-h9s67yD4+g+JoYG0zPCo/cLTabpDqzqNdzMawmNPzDStTiwxwkyYM1v5lWE8gmGv3SVJ2DcxA2NpQJZJv9ym3g==", 1010 | "dev": true, 1011 | "dependencies": { 1012 | "@vitest/pretty-format": "3.0.2", 1013 | "magic-string": "^0.30.17", 1014 | "pathe": "^2.0.1" 1015 | }, 1016 | "funding": { 1017 | "url": "https://opencollective.com/vitest" 1018 | } 1019 | }, 1020 | "node_modules/@vitest/spy": { 1021 | "version": "3.0.2", 1022 | "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.2.tgz", 1023 | "integrity": "sha512-8mI2iUn+PJFMT44e3ISA1R+K6ALVs47W6eriDTfXe6lFqlflID05MB4+rIFhmDSLBj8iBsZkzBYlgSkinxLzSQ==", 1024 | "dev": true, 1025 | "dependencies": { 1026 | "tinyspy": "^3.0.2" 1027 | }, 1028 | "funding": { 1029 | "url": "https://opencollective.com/vitest" 1030 | } 1031 | }, 1032 | "node_modules/@vitest/utils": { 1033 | "version": "3.0.2", 1034 | "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.2.tgz", 1035 | "integrity": "sha512-Qu01ZYZlgHvDP02JnMBRpX43nRaZtNpIzw3C1clDXmn8eakgX6iQVGzTQ/NjkIr64WD8ioqOjkaYRVvHQI5qiw==", 1036 | "dev": true, 1037 | "dependencies": { 1038 | "@vitest/pretty-format": "3.0.2", 1039 | "loupe": "^3.1.2", 1040 | "tinyrainbow": "^2.0.0" 1041 | }, 1042 | "funding": { 1043 | "url": "https://opencollective.com/vitest" 1044 | } 1045 | }, 1046 | "node_modules/abi-wan-kanabi": { 1047 | "version": "2.2.4", 1048 | "resolved": "https://registry.npmjs.org/abi-wan-kanabi/-/abi-wan-kanabi-2.2.4.tgz", 1049 | "integrity": "sha512-0aA81FScmJCPX+8UvkXLki3X1+yPQuWxEkqXBVKltgPAK79J+NB+Lp5DouMXa7L6f+zcRlIA/6XO7BN/q9fnvg==", 1050 | "dependencies": { 1051 | "ansicolors": "^0.3.2", 1052 | "cardinal": "^2.1.1", 1053 | "fs-extra": "^10.0.0", 1054 | "yargs": "^17.7.2" 1055 | }, 1056 | "bin": { 1057 | "generate": "dist/generate.js" 1058 | } 1059 | }, 1060 | "node_modules/abitype": { 1061 | "version": "1.0.7", 1062 | "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.7.tgz", 1063 | "integrity": "sha512-ZfYYSktDQUwc2eduYu8C4wOs+RDPmnRYMh7zNfzeMtGGgb0U+6tLGjixUic6mXf5xKKCcgT5Qp6cv39tOARVFw==", 1064 | "funding": { 1065 | "url": "https://github.com/sponsors/wevm" 1066 | }, 1067 | "peerDependencies": { 1068 | "typescript": ">=5.0.4", 1069 | "zod": "^3 >=3.22.0" 1070 | }, 1071 | "peerDependenciesMeta": { 1072 | "typescript": { 1073 | "optional": true 1074 | }, 1075 | "zod": { 1076 | "optional": true 1077 | } 1078 | } 1079 | }, 1080 | "node_modules/abort-controller-x": { 1081 | "version": "0.4.3", 1082 | "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.4.3.tgz", 1083 | "integrity": "sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==" 1084 | }, 1085 | "node_modules/ansi-regex": { 1086 | "version": "5.0.1", 1087 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1088 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 1089 | "engines": { 1090 | "node": ">=8" 1091 | } 1092 | }, 1093 | "node_modules/ansi-styles": { 1094 | "version": "4.3.0", 1095 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1096 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1097 | "dependencies": { 1098 | "color-convert": "^2.0.1" 1099 | }, 1100 | "engines": { 1101 | "node": ">=8" 1102 | }, 1103 | "funding": { 1104 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1105 | } 1106 | }, 1107 | "node_modules/ansi-styles/node_modules/color-convert": { 1108 | "version": "2.0.1", 1109 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1110 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1111 | "dependencies": { 1112 | "color-name": "~1.1.4" 1113 | }, 1114 | "engines": { 1115 | "node": ">=7.0.0" 1116 | } 1117 | }, 1118 | "node_modules/ansi-styles/node_modules/color-name": { 1119 | "version": "1.1.4", 1120 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1121 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 1122 | }, 1123 | "node_modules/ansicolors": { 1124 | "version": "0.3.2", 1125 | "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", 1126 | "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==" 1127 | }, 1128 | "node_modules/assertion-error": { 1129 | "version": "2.0.1", 1130 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", 1131 | "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", 1132 | "dev": true, 1133 | "engines": { 1134 | "node": ">=12" 1135 | } 1136 | }, 1137 | "node_modules/async": { 1138 | "version": "3.2.6", 1139 | "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", 1140 | "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==" 1141 | }, 1142 | "node_modules/cac": { 1143 | "version": "6.7.14", 1144 | "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", 1145 | "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", 1146 | "dev": true, 1147 | "engines": { 1148 | "node": ">=8" 1149 | } 1150 | }, 1151 | "node_modules/cardinal": { 1152 | "version": "2.1.1", 1153 | "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", 1154 | "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==", 1155 | "dependencies": { 1156 | "ansicolors": "~0.3.2", 1157 | "redeyed": "~2.1.0" 1158 | }, 1159 | "bin": { 1160 | "cdl": "bin/cdl.js" 1161 | } 1162 | }, 1163 | "node_modules/chai": { 1164 | "version": "5.1.2", 1165 | "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", 1166 | "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", 1167 | "dev": true, 1168 | "dependencies": { 1169 | "assertion-error": "^2.0.1", 1170 | "check-error": "^2.1.1", 1171 | "deep-eql": "^5.0.1", 1172 | "loupe": "^3.1.0", 1173 | "pathval": "^2.0.0" 1174 | }, 1175 | "engines": { 1176 | "node": ">=12" 1177 | } 1178 | }, 1179 | "node_modules/check-error": { 1180 | "version": "2.1.1", 1181 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", 1182 | "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", 1183 | "dev": true, 1184 | "engines": { 1185 | "node": ">= 16" 1186 | } 1187 | }, 1188 | "node_modules/cliui": { 1189 | "version": "8.0.1", 1190 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", 1191 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", 1192 | "dependencies": { 1193 | "string-width": "^4.2.0", 1194 | "strip-ansi": "^6.0.1", 1195 | "wrap-ansi": "^7.0.0" 1196 | }, 1197 | "engines": { 1198 | "node": ">=12" 1199 | } 1200 | }, 1201 | "node_modules/color": { 1202 | "version": "3.2.1", 1203 | "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", 1204 | "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", 1205 | "dependencies": { 1206 | "color-convert": "^1.9.3", 1207 | "color-string": "^1.6.0" 1208 | } 1209 | }, 1210 | "node_modules/color-convert": { 1211 | "version": "1.9.3", 1212 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 1213 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 1214 | "dependencies": { 1215 | "color-name": "1.1.3" 1216 | } 1217 | }, 1218 | "node_modules/color-name": { 1219 | "version": "1.1.3", 1220 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 1221 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 1222 | }, 1223 | "node_modules/color-string": { 1224 | "version": "1.9.1", 1225 | "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", 1226 | "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", 1227 | "dependencies": { 1228 | "color-name": "^1.0.0", 1229 | "simple-swizzle": "^0.2.2" 1230 | } 1231 | }, 1232 | "node_modules/colorspace": { 1233 | "version": "1.1.4", 1234 | "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", 1235 | "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", 1236 | "dependencies": { 1237 | "color": "^3.1.3", 1238 | "text-hex": "1.0.x" 1239 | } 1240 | }, 1241 | "node_modules/debug": { 1242 | "version": "4.4.0", 1243 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", 1244 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", 1245 | "dev": true, 1246 | "dependencies": { 1247 | "ms": "^2.1.3" 1248 | }, 1249 | "engines": { 1250 | "node": ">=6.0" 1251 | }, 1252 | "peerDependenciesMeta": { 1253 | "supports-color": { 1254 | "optional": true 1255 | } 1256 | } 1257 | }, 1258 | "node_modules/deep-eql": { 1259 | "version": "5.0.2", 1260 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", 1261 | "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", 1262 | "dev": true, 1263 | "engines": { 1264 | "node": ">=6" 1265 | } 1266 | }, 1267 | "node_modules/dotenv": { 1268 | "version": "16.4.7", 1269 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", 1270 | "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", 1271 | "engines": { 1272 | "node": ">=12" 1273 | }, 1274 | "funding": { 1275 | "url": "https://dotenvx.com" 1276 | } 1277 | }, 1278 | "node_modules/effect": { 1279 | "version": "3.15.0", 1280 | "resolved": "https://registry.npmjs.org/effect/-/effect-3.15.0.tgz", 1281 | "integrity": "sha512-l8eJAz1DVEUg2zgmLR9JGYRc1YrKcf/UziC41pIxUHfMgNKMt/Qg8ENhFvbyc9m6Nhrr/Zkg9XtvU7024KU32A==", 1282 | "license": "MIT", 1283 | "dependencies": { 1284 | "@standard-schema/spec": "^1.0.0", 1285 | "fast-check": "^3.23.1" 1286 | } 1287 | }, 1288 | "node_modules/emoji-regex": { 1289 | "version": "8.0.0", 1290 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 1291 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 1292 | }, 1293 | "node_modules/enabled": { 1294 | "version": "2.0.0", 1295 | "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", 1296 | "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" 1297 | }, 1298 | "node_modules/es-module-lexer": { 1299 | "version": "1.6.0", 1300 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", 1301 | "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", 1302 | "dev": true 1303 | }, 1304 | "node_modules/esbuild": { 1305 | "version": "0.24.2", 1306 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", 1307 | "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", 1308 | "dev": true, 1309 | "hasInstallScript": true, 1310 | "bin": { 1311 | "esbuild": "bin/esbuild" 1312 | }, 1313 | "engines": { 1314 | "node": ">=18" 1315 | }, 1316 | "optionalDependencies": { 1317 | "@esbuild/aix-ppc64": "0.24.2", 1318 | "@esbuild/android-arm": "0.24.2", 1319 | "@esbuild/android-arm64": "0.24.2", 1320 | "@esbuild/android-x64": "0.24.2", 1321 | "@esbuild/darwin-arm64": "0.24.2", 1322 | "@esbuild/darwin-x64": "0.24.2", 1323 | "@esbuild/freebsd-arm64": "0.24.2", 1324 | "@esbuild/freebsd-x64": "0.24.2", 1325 | "@esbuild/linux-arm": "0.24.2", 1326 | "@esbuild/linux-arm64": "0.24.2", 1327 | "@esbuild/linux-ia32": "0.24.2", 1328 | "@esbuild/linux-loong64": "0.24.2", 1329 | "@esbuild/linux-mips64el": "0.24.2", 1330 | "@esbuild/linux-ppc64": "0.24.2", 1331 | "@esbuild/linux-riscv64": "0.24.2", 1332 | "@esbuild/linux-s390x": "0.24.2", 1333 | "@esbuild/linux-x64": "0.24.2", 1334 | "@esbuild/netbsd-arm64": "0.24.2", 1335 | "@esbuild/netbsd-x64": "0.24.2", 1336 | "@esbuild/openbsd-arm64": "0.24.2", 1337 | "@esbuild/openbsd-x64": "0.24.2", 1338 | "@esbuild/sunos-x64": "0.24.2", 1339 | "@esbuild/win32-arm64": "0.24.2", 1340 | "@esbuild/win32-ia32": "0.24.2", 1341 | "@esbuild/win32-x64": "0.24.2" 1342 | } 1343 | }, 1344 | "node_modules/escalade": { 1345 | "version": "3.2.0", 1346 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 1347 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 1348 | "engines": { 1349 | "node": ">=6" 1350 | } 1351 | }, 1352 | "node_modules/esprima": { 1353 | "version": "4.0.1", 1354 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 1355 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 1356 | "bin": { 1357 | "esparse": "bin/esparse.js", 1358 | "esvalidate": "bin/esvalidate.js" 1359 | }, 1360 | "engines": { 1361 | "node": ">=4" 1362 | } 1363 | }, 1364 | "node_modules/estree-walker": { 1365 | "version": "3.0.3", 1366 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", 1367 | "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", 1368 | "dev": true, 1369 | "dependencies": { 1370 | "@types/estree": "^1.0.0" 1371 | } 1372 | }, 1373 | "node_modules/eventemitter3": { 1374 | "version": "5.0.1", 1375 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", 1376 | "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" 1377 | }, 1378 | "node_modules/expect-type": { 1379 | "version": "1.1.0", 1380 | "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.1.0.tgz", 1381 | "integrity": "sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA==", 1382 | "dev": true, 1383 | "engines": { 1384 | "node": ">=12.0.0" 1385 | } 1386 | }, 1387 | "node_modules/fast-check": { 1388 | "version": "3.23.2", 1389 | "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", 1390 | "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", 1391 | "funding": [ 1392 | { 1393 | "type": "individual", 1394 | "url": "https://github.com/sponsors/dubzzz" 1395 | }, 1396 | { 1397 | "type": "opencollective", 1398 | "url": "https://opencollective.com/fast-check" 1399 | } 1400 | ], 1401 | "license": "MIT", 1402 | "dependencies": { 1403 | "pure-rand": "^6.1.0" 1404 | }, 1405 | "engines": { 1406 | "node": ">=8.0.0" 1407 | } 1408 | }, 1409 | "node_modules/fecha": { 1410 | "version": "4.2.3", 1411 | "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", 1412 | "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" 1413 | }, 1414 | "node_modules/fn.name": { 1415 | "version": "1.1.0", 1416 | "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", 1417 | "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" 1418 | }, 1419 | "node_modules/fs-extra": { 1420 | "version": "10.1.0", 1421 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", 1422 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", 1423 | "dependencies": { 1424 | "graceful-fs": "^4.2.0", 1425 | "jsonfile": "^6.0.1", 1426 | "universalify": "^2.0.0" 1427 | }, 1428 | "engines": { 1429 | "node": ">=12" 1430 | } 1431 | }, 1432 | "node_modules/fsevents": { 1433 | "version": "2.3.3", 1434 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1435 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1436 | "dev": true, 1437 | "hasInstallScript": true, 1438 | "optional": true, 1439 | "os": [ 1440 | "darwin" 1441 | ], 1442 | "engines": { 1443 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1444 | } 1445 | }, 1446 | "node_modules/get-caller-file": { 1447 | "version": "2.0.5", 1448 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", 1449 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 1450 | "engines": { 1451 | "node": "6.* || 8.* || >= 10.*" 1452 | } 1453 | }, 1454 | "node_modules/graceful-fs": { 1455 | "version": "4.2.11", 1456 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 1457 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" 1458 | }, 1459 | "node_modules/inherits": { 1460 | "version": "2.0.4", 1461 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1462 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1463 | }, 1464 | "node_modules/is-arrayish": { 1465 | "version": "0.3.2", 1466 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", 1467 | "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" 1468 | }, 1469 | "node_modules/is-fullwidth-code-point": { 1470 | "version": "3.0.0", 1471 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 1472 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 1473 | "engines": { 1474 | "node": ">=8" 1475 | } 1476 | }, 1477 | "node_modules/is-stream": { 1478 | "version": "2.0.1", 1479 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", 1480 | "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", 1481 | "engines": { 1482 | "node": ">=8" 1483 | }, 1484 | "funding": { 1485 | "url": "https://github.com/sponsors/sindresorhus" 1486 | } 1487 | }, 1488 | "node_modules/isows": { 1489 | "version": "1.0.6", 1490 | "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz", 1491 | "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==", 1492 | "funding": [ 1493 | { 1494 | "type": "github", 1495 | "url": "https://github.com/sponsors/wevm" 1496 | } 1497 | ], 1498 | "peerDependencies": { 1499 | "ws": "*" 1500 | } 1501 | }, 1502 | "node_modules/jiti": { 1503 | "version": "2.4.2", 1504 | "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", 1505 | "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", 1506 | "bin": { 1507 | "jiti": "lib/jiti-cli.mjs" 1508 | } 1509 | }, 1510 | "node_modules/jsonfile": { 1511 | "version": "6.1.0", 1512 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 1513 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 1514 | "dependencies": { 1515 | "universalify": "^2.0.0" 1516 | }, 1517 | "optionalDependencies": { 1518 | "graceful-fs": "^4.1.6" 1519 | } 1520 | }, 1521 | "node_modules/kuler": { 1522 | "version": "2.0.0", 1523 | "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", 1524 | "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" 1525 | }, 1526 | "node_modules/lodash.camelcase": { 1527 | "version": "4.3.0", 1528 | "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", 1529 | "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" 1530 | }, 1531 | "node_modules/logform": { 1532 | "version": "2.7.0", 1533 | "resolved": "https://registry.npmjs.org/logform/-/logform-2.7.0.tgz", 1534 | "integrity": "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==", 1535 | "dependencies": { 1536 | "@colors/colors": "1.6.0", 1537 | "@types/triple-beam": "^1.3.2", 1538 | "fecha": "^4.2.0", 1539 | "ms": "^2.1.1", 1540 | "safe-stable-stringify": "^2.3.1", 1541 | "triple-beam": "^1.3.0" 1542 | }, 1543 | "engines": { 1544 | "node": ">= 12.0.0" 1545 | } 1546 | }, 1547 | "node_modules/long": { 1548 | "version": "5.2.4", 1549 | "resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz", 1550 | "integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==" 1551 | }, 1552 | "node_modules/loupe": { 1553 | "version": "3.1.2", 1554 | "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", 1555 | "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", 1556 | "dev": true 1557 | }, 1558 | "node_modules/magic-string": { 1559 | "version": "0.30.17", 1560 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", 1561 | "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", 1562 | "dev": true, 1563 | "dependencies": { 1564 | "@jridgewell/sourcemap-codec": "^1.5.0" 1565 | } 1566 | }, 1567 | "node_modules/ms": { 1568 | "version": "2.1.3", 1569 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1570 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 1571 | }, 1572 | "node_modules/nanoid": { 1573 | "version": "3.3.8", 1574 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", 1575 | "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", 1576 | "dev": true, 1577 | "funding": [ 1578 | { 1579 | "type": "github", 1580 | "url": "https://github.com/sponsors/ai" 1581 | } 1582 | ], 1583 | "bin": { 1584 | "nanoid": "bin/nanoid.cjs" 1585 | }, 1586 | "engines": { 1587 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1588 | } 1589 | }, 1590 | "node_modules/nice-grpc": { 1591 | "version": "2.1.10", 1592 | "resolved": "https://registry.npmjs.org/nice-grpc/-/nice-grpc-2.1.10.tgz", 1593 | "integrity": "sha512-Nujs/4wWJvE5OSxWPp3M5H+zHJAgsWMo38bMNfKQP1VDeCChp7MiKTkhJBV5JZvrBIkPhYQCLIbfvVqEoSuTuA==", 1594 | "dependencies": { 1595 | "@grpc/grpc-js": "^1.10.8", 1596 | "abort-controller-x": "^0.4.0", 1597 | "nice-grpc-common": "^2.0.2" 1598 | } 1599 | }, 1600 | "node_modules/nice-grpc-common": { 1601 | "version": "2.0.2", 1602 | "resolved": "https://registry.npmjs.org/nice-grpc-common/-/nice-grpc-common-2.0.2.tgz", 1603 | "integrity": "sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==", 1604 | "dependencies": { 1605 | "ts-error": "^1.0.6" 1606 | } 1607 | }, 1608 | "node_modules/obuf": { 1609 | "version": "1.1.2", 1610 | "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", 1611 | "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", 1612 | "dev": true 1613 | }, 1614 | "node_modules/one-time": { 1615 | "version": "1.0.0", 1616 | "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", 1617 | "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", 1618 | "dependencies": { 1619 | "fn.name": "1.x.x" 1620 | } 1621 | }, 1622 | "node_modules/ox": { 1623 | "version": "0.6.5", 1624 | "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.5.tgz", 1625 | "integrity": "sha512-vmnH8KvMDwFZDbNY1mq2CBRBWIgSliZB/dFV0xKp+DfF/dJkTENt6nmA+DzHSSAgL/GO2ydjkXWvlndJgSY4KQ==", 1626 | "funding": [ 1627 | { 1628 | "type": "github", 1629 | "url": "https://github.com/sponsors/wevm" 1630 | } 1631 | ], 1632 | "dependencies": { 1633 | "@adraffy/ens-normalize": "^1.10.1", 1634 | "@noble/curves": "^1.6.0", 1635 | "@noble/hashes": "^1.5.0", 1636 | "@scure/bip32": "^1.5.0", 1637 | "@scure/bip39": "^1.4.0", 1638 | "abitype": "^1.0.6", 1639 | "eventemitter3": "5.0.1" 1640 | }, 1641 | "peerDependencies": { 1642 | "typescript": ">=5.4.0" 1643 | }, 1644 | "peerDependenciesMeta": { 1645 | "typescript": { 1646 | "optional": true 1647 | } 1648 | } 1649 | }, 1650 | "node_modules/pathe": { 1651 | "version": "2.0.2", 1652 | "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz", 1653 | "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==", 1654 | "dev": true 1655 | }, 1656 | "node_modules/pathval": { 1657 | "version": "2.0.0", 1658 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", 1659 | "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", 1660 | "dev": true, 1661 | "engines": { 1662 | "node": ">= 14.16" 1663 | } 1664 | }, 1665 | "node_modules/pg": { 1666 | "version": "8.13.1", 1667 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", 1668 | "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", 1669 | "dependencies": { 1670 | "pg-connection-string": "^2.7.0", 1671 | "pg-pool": "^3.7.0", 1672 | "pg-protocol": "^1.7.0", 1673 | "pg-types": "^2.1.0", 1674 | "pgpass": "1.x" 1675 | }, 1676 | "engines": { 1677 | "node": ">= 8.0.0" 1678 | }, 1679 | "optionalDependencies": { 1680 | "pg-cloudflare": "^1.1.1" 1681 | }, 1682 | "peerDependencies": { 1683 | "pg-native": ">=3.0.1" 1684 | }, 1685 | "peerDependenciesMeta": { 1686 | "pg-native": { 1687 | "optional": true 1688 | } 1689 | } 1690 | }, 1691 | "node_modules/pg-cloudflare": { 1692 | "version": "1.1.1", 1693 | "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", 1694 | "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", 1695 | "optional": true 1696 | }, 1697 | "node_modules/pg-connection-string": { 1698 | "version": "2.7.0", 1699 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", 1700 | "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==" 1701 | }, 1702 | "node_modules/pg-int8": { 1703 | "version": "1.0.1", 1704 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 1705 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", 1706 | "engines": { 1707 | "node": ">=4.0.0" 1708 | } 1709 | }, 1710 | "node_modules/pg-numeric": { 1711 | "version": "1.0.2", 1712 | "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", 1713 | "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", 1714 | "dev": true, 1715 | "engines": { 1716 | "node": ">=4" 1717 | } 1718 | }, 1719 | "node_modules/pg-pool": { 1720 | "version": "3.7.0", 1721 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", 1722 | "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", 1723 | "peerDependencies": { 1724 | "pg": ">=8.0" 1725 | } 1726 | }, 1727 | "node_modules/pg-protocol": { 1728 | "version": "1.7.0", 1729 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", 1730 | "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==" 1731 | }, 1732 | "node_modules/pg-types": { 1733 | "version": "4.0.2", 1734 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", 1735 | "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", 1736 | "dev": true, 1737 | "dependencies": { 1738 | "pg-int8": "1.0.1", 1739 | "pg-numeric": "1.0.2", 1740 | "postgres-array": "~3.0.1", 1741 | "postgres-bytea": "~3.0.0", 1742 | "postgres-date": "~2.1.0", 1743 | "postgres-interval": "^3.0.0", 1744 | "postgres-range": "^1.1.1" 1745 | }, 1746 | "engines": { 1747 | "node": ">=10" 1748 | } 1749 | }, 1750 | "node_modules/pg/node_modules/pg-types": { 1751 | "version": "2.2.0", 1752 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 1753 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 1754 | "dependencies": { 1755 | "pg-int8": "1.0.1", 1756 | "postgres-array": "~2.0.0", 1757 | "postgres-bytea": "~1.0.0", 1758 | "postgres-date": "~1.0.4", 1759 | "postgres-interval": "^1.1.0" 1760 | }, 1761 | "engines": { 1762 | "node": ">=4" 1763 | } 1764 | }, 1765 | "node_modules/pg/node_modules/postgres-array": { 1766 | "version": "2.0.0", 1767 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 1768 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", 1769 | "engines": { 1770 | "node": ">=4" 1771 | } 1772 | }, 1773 | "node_modules/pg/node_modules/postgres-bytea": { 1774 | "version": "1.0.0", 1775 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 1776 | "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", 1777 | "engines": { 1778 | "node": ">=0.10.0" 1779 | } 1780 | }, 1781 | "node_modules/pg/node_modules/postgres-date": { 1782 | "version": "1.0.7", 1783 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 1784 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", 1785 | "engines": { 1786 | "node": ">=0.10.0" 1787 | } 1788 | }, 1789 | "node_modules/pg/node_modules/postgres-interval": { 1790 | "version": "1.2.0", 1791 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 1792 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 1793 | "dependencies": { 1794 | "xtend": "^4.0.0" 1795 | }, 1796 | "engines": { 1797 | "node": ">=0.10.0" 1798 | } 1799 | }, 1800 | "node_modules/pgpass": { 1801 | "version": "1.0.5", 1802 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", 1803 | "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", 1804 | "dependencies": { 1805 | "split2": "^4.1.0" 1806 | } 1807 | }, 1808 | "node_modules/picocolors": { 1809 | "version": "1.1.1", 1810 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 1811 | "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 1812 | "dev": true 1813 | }, 1814 | "node_modules/postcss": { 1815 | "version": "8.5.1", 1816 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", 1817 | "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==", 1818 | "dev": true, 1819 | "funding": [ 1820 | { 1821 | "type": "opencollective", 1822 | "url": "https://opencollective.com/postcss/" 1823 | }, 1824 | { 1825 | "type": "tidelift", 1826 | "url": "https://tidelift.com/funding/github/npm/postcss" 1827 | }, 1828 | { 1829 | "type": "github", 1830 | "url": "https://github.com/sponsors/ai" 1831 | } 1832 | ], 1833 | "dependencies": { 1834 | "nanoid": "^3.3.8", 1835 | "picocolors": "^1.1.1", 1836 | "source-map-js": "^1.2.1" 1837 | }, 1838 | "engines": { 1839 | "node": "^10 || ^12 || >=14" 1840 | } 1841 | }, 1842 | "node_modules/postgres-array": { 1843 | "version": "3.0.2", 1844 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", 1845 | "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", 1846 | "dev": true, 1847 | "engines": { 1848 | "node": ">=12" 1849 | } 1850 | }, 1851 | "node_modules/postgres-bytea": { 1852 | "version": "3.0.0", 1853 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", 1854 | "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", 1855 | "dev": true, 1856 | "dependencies": { 1857 | "obuf": "~1.1.2" 1858 | }, 1859 | "engines": { 1860 | "node": ">= 6" 1861 | } 1862 | }, 1863 | "node_modules/postgres-date": { 1864 | "version": "2.1.0", 1865 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", 1866 | "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", 1867 | "dev": true, 1868 | "engines": { 1869 | "node": ">=12" 1870 | } 1871 | }, 1872 | "node_modules/postgres-interval": { 1873 | "version": "3.0.0", 1874 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", 1875 | "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", 1876 | "dev": true, 1877 | "engines": { 1878 | "node": ">=12" 1879 | } 1880 | }, 1881 | "node_modules/postgres-range": { 1882 | "version": "1.1.4", 1883 | "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", 1884 | "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", 1885 | "dev": true 1886 | }, 1887 | "node_modules/protobufjs": { 1888 | "version": "7.4.0", 1889 | "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", 1890 | "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", 1891 | "hasInstallScript": true, 1892 | "dependencies": { 1893 | "@protobufjs/aspromise": "^1.1.2", 1894 | "@protobufjs/base64": "^1.1.2", 1895 | "@protobufjs/codegen": "^2.0.4", 1896 | "@protobufjs/eventemitter": "^1.1.0", 1897 | "@protobufjs/fetch": "^1.1.0", 1898 | "@protobufjs/float": "^1.0.2", 1899 | "@protobufjs/inquire": "^1.1.0", 1900 | "@protobufjs/path": "^1.1.2", 1901 | "@protobufjs/pool": "^1.1.0", 1902 | "@protobufjs/utf8": "^1.1.0", 1903 | "@types/node": ">=13.7.0", 1904 | "long": "^5.0.0" 1905 | }, 1906 | "engines": { 1907 | "node": ">=12.0.0" 1908 | } 1909 | }, 1910 | "node_modules/pure-rand": { 1911 | "version": "6.1.0", 1912 | "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", 1913 | "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", 1914 | "funding": [ 1915 | { 1916 | "type": "individual", 1917 | "url": "https://github.com/sponsors/dubzzz" 1918 | }, 1919 | { 1920 | "type": "opencollective", 1921 | "url": "https://opencollective.com/fast-check" 1922 | } 1923 | ], 1924 | "license": "MIT" 1925 | }, 1926 | "node_modules/readable-stream": { 1927 | "version": "3.6.2", 1928 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", 1929 | "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", 1930 | "dependencies": { 1931 | "inherits": "^2.0.3", 1932 | "string_decoder": "^1.1.1", 1933 | "util-deprecate": "^1.0.1" 1934 | }, 1935 | "engines": { 1936 | "node": ">= 6" 1937 | } 1938 | }, 1939 | "node_modules/redeyed": { 1940 | "version": "2.1.1", 1941 | "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", 1942 | "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==", 1943 | "dependencies": { 1944 | "esprima": "~4.0.0" 1945 | } 1946 | }, 1947 | "node_modules/require-directory": { 1948 | "version": "2.1.1", 1949 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 1950 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", 1951 | "engines": { 1952 | "node": ">=0.10.0" 1953 | } 1954 | }, 1955 | "node_modules/rollup": { 1956 | "version": "4.30.1", 1957 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", 1958 | "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", 1959 | "dev": true, 1960 | "dependencies": { 1961 | "@types/estree": "1.0.6" 1962 | }, 1963 | "bin": { 1964 | "rollup": "dist/bin/rollup" 1965 | }, 1966 | "engines": { 1967 | "node": ">=18.0.0", 1968 | "npm": ">=8.0.0" 1969 | }, 1970 | "optionalDependencies": { 1971 | "@rollup/rollup-android-arm-eabi": "4.30.1", 1972 | "@rollup/rollup-android-arm64": "4.30.1", 1973 | "@rollup/rollup-darwin-arm64": "4.30.1", 1974 | "@rollup/rollup-darwin-x64": "4.30.1", 1975 | "@rollup/rollup-freebsd-arm64": "4.30.1", 1976 | "@rollup/rollup-freebsd-x64": "4.30.1", 1977 | "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", 1978 | "@rollup/rollup-linux-arm-musleabihf": "4.30.1", 1979 | "@rollup/rollup-linux-arm64-gnu": "4.30.1", 1980 | "@rollup/rollup-linux-arm64-musl": "4.30.1", 1981 | "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", 1982 | "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", 1983 | "@rollup/rollup-linux-riscv64-gnu": "4.30.1", 1984 | "@rollup/rollup-linux-s390x-gnu": "4.30.1", 1985 | "@rollup/rollup-linux-x64-gnu": "4.30.1", 1986 | "@rollup/rollup-linux-x64-musl": "4.30.1", 1987 | "@rollup/rollup-win32-arm64-msvc": "4.30.1", 1988 | "@rollup/rollup-win32-ia32-msvc": "4.30.1", 1989 | "@rollup/rollup-win32-x64-msvc": "4.30.1", 1990 | "fsevents": "~2.3.2" 1991 | } 1992 | }, 1993 | "node_modules/safe-buffer": { 1994 | "version": "5.2.1", 1995 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1996 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 1997 | "funding": [ 1998 | { 1999 | "type": "github", 2000 | "url": "https://github.com/sponsors/feross" 2001 | }, 2002 | { 2003 | "type": "patreon", 2004 | "url": "https://www.patreon.com/feross" 2005 | }, 2006 | { 2007 | "type": "consulting", 2008 | "url": "https://feross.org/support" 2009 | } 2010 | ] 2011 | }, 2012 | "node_modules/safe-stable-stringify": { 2013 | "version": "2.5.0", 2014 | "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", 2015 | "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", 2016 | "engines": { 2017 | "node": ">=10" 2018 | } 2019 | }, 2020 | "node_modules/siginfo": { 2021 | "version": "2.0.0", 2022 | "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", 2023 | "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", 2024 | "dev": true 2025 | }, 2026 | "node_modules/simple-swizzle": { 2027 | "version": "0.2.2", 2028 | "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", 2029 | "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", 2030 | "dependencies": { 2031 | "is-arrayish": "^0.3.1" 2032 | } 2033 | }, 2034 | "node_modules/source-map-js": { 2035 | "version": "1.2.1", 2036 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 2037 | "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 2038 | "dev": true, 2039 | "engines": { 2040 | "node": ">=0.10.0" 2041 | } 2042 | }, 2043 | "node_modules/split2": { 2044 | "version": "4.2.0", 2045 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", 2046 | "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", 2047 | "engines": { 2048 | "node": ">= 10.x" 2049 | } 2050 | }, 2051 | "node_modules/stack-trace": { 2052 | "version": "0.0.10", 2053 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", 2054 | "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", 2055 | "engines": { 2056 | "node": "*" 2057 | } 2058 | }, 2059 | "node_modules/stackback": { 2060 | "version": "0.0.2", 2061 | "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", 2062 | "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", 2063 | "dev": true 2064 | }, 2065 | "node_modules/std-env": { 2066 | "version": "3.8.0", 2067 | "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.0.tgz", 2068 | "integrity": "sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==", 2069 | "dev": true 2070 | }, 2071 | "node_modules/string_decoder": { 2072 | "version": "1.3.0", 2073 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 2074 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 2075 | "dependencies": { 2076 | "safe-buffer": "~5.2.0" 2077 | } 2078 | }, 2079 | "node_modules/string-width": { 2080 | "version": "4.2.3", 2081 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 2082 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 2083 | "dependencies": { 2084 | "emoji-regex": "^8.0.0", 2085 | "is-fullwidth-code-point": "^3.0.0", 2086 | "strip-ansi": "^6.0.1" 2087 | }, 2088 | "engines": { 2089 | "node": ">=8" 2090 | } 2091 | }, 2092 | "node_modules/strip-ansi": { 2093 | "version": "6.0.1", 2094 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 2095 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 2096 | "dependencies": { 2097 | "ansi-regex": "^5.0.1" 2098 | }, 2099 | "engines": { 2100 | "node": ">=8" 2101 | } 2102 | }, 2103 | "node_modules/tadaaa": { 2104 | "version": "1.0.1", 2105 | "resolved": "https://registry.npmjs.org/tadaaa/-/tadaaa-1.0.1.tgz", 2106 | "integrity": "sha512-tBJZ7XC3TgD1lz6BatNpzj+ABNiI/X04ZBYaLbxFmU02B76wRvur1Y4wUljQune37BTB3ITf6905rcAH7sUpFg==" 2107 | }, 2108 | "node_modules/text-hex": { 2109 | "version": "1.0.0", 2110 | "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", 2111 | "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" 2112 | }, 2113 | "node_modules/tinybench": { 2114 | "version": "2.9.0", 2115 | "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", 2116 | "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", 2117 | "dev": true 2118 | }, 2119 | "node_modules/tinyexec": { 2120 | "version": "0.3.2", 2121 | "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", 2122 | "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", 2123 | "dev": true 2124 | }, 2125 | "node_modules/tinypool": { 2126 | "version": "1.0.2", 2127 | "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", 2128 | "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", 2129 | "dev": true, 2130 | "engines": { 2131 | "node": "^18.0.0 || >=20.0.0" 2132 | } 2133 | }, 2134 | "node_modules/tinyrainbow": { 2135 | "version": "2.0.0", 2136 | "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", 2137 | "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", 2138 | "dev": true, 2139 | "engines": { 2140 | "node": ">=14.0.0" 2141 | } 2142 | }, 2143 | "node_modules/tinyspy": { 2144 | "version": "3.0.2", 2145 | "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", 2146 | "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", 2147 | "dev": true, 2148 | "engines": { 2149 | "node": ">=14.0.0" 2150 | } 2151 | }, 2152 | "node_modules/triple-beam": { 2153 | "version": "1.4.1", 2154 | "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", 2155 | "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", 2156 | "engines": { 2157 | "node": ">= 14.0.0" 2158 | } 2159 | }, 2160 | "node_modules/ts-error": { 2161 | "version": "1.0.6", 2162 | "resolved": "https://registry.npmjs.org/ts-error/-/ts-error-1.0.6.tgz", 2163 | "integrity": "sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==" 2164 | }, 2165 | "node_modules/typescript": { 2166 | "version": "5.7.3", 2167 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", 2168 | "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", 2169 | "devOptional": true, 2170 | "bin": { 2171 | "tsc": "bin/tsc", 2172 | "tsserver": "bin/tsserver" 2173 | }, 2174 | "engines": { 2175 | "node": ">=14.17" 2176 | } 2177 | }, 2178 | "node_modules/undici-types": { 2179 | "version": "6.20.0", 2180 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", 2181 | "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" 2182 | }, 2183 | "node_modules/universalify": { 2184 | "version": "2.0.1", 2185 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", 2186 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", 2187 | "engines": { 2188 | "node": ">= 10.0.0" 2189 | } 2190 | }, 2191 | "node_modules/util-deprecate": { 2192 | "version": "1.0.2", 2193 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2194 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 2195 | }, 2196 | "node_modules/viem": { 2197 | "version": "2.22.9", 2198 | "resolved": "https://registry.npmjs.org/viem/-/viem-2.22.9.tgz", 2199 | "integrity": "sha512-2yy46qYhcdo8GZggQ3Zoq9QCahI0goddzpVI/vSnTpcClQBSDxYRCuAqRzzLqjvJ7hS0UYgplC7eRkM2sYgflw==", 2200 | "funding": [ 2201 | { 2202 | "type": "github", 2203 | "url": "https://github.com/sponsors/wevm" 2204 | } 2205 | ], 2206 | "dependencies": { 2207 | "@noble/curves": "1.7.0", 2208 | "@noble/hashes": "1.6.1", 2209 | "@scure/bip32": "1.6.0", 2210 | "@scure/bip39": "1.5.0", 2211 | "abitype": "1.0.7", 2212 | "isows": "1.0.6", 2213 | "ox": "0.6.5", 2214 | "ws": "8.18.0" 2215 | }, 2216 | "peerDependencies": { 2217 | "typescript": ">=5.0.4" 2218 | }, 2219 | "peerDependenciesMeta": { 2220 | "typescript": { 2221 | "optional": true 2222 | } 2223 | } 2224 | }, 2225 | "node_modules/vite": { 2226 | "version": "6.0.7", 2227 | "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz", 2228 | "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==", 2229 | "dev": true, 2230 | "dependencies": { 2231 | "esbuild": "^0.24.2", 2232 | "postcss": "^8.4.49", 2233 | "rollup": "^4.23.0" 2234 | }, 2235 | "bin": { 2236 | "vite": "bin/vite.js" 2237 | }, 2238 | "engines": { 2239 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 2240 | }, 2241 | "funding": { 2242 | "url": "https://github.com/vitejs/vite?sponsor=1" 2243 | }, 2244 | "optionalDependencies": { 2245 | "fsevents": "~2.3.3" 2246 | }, 2247 | "peerDependencies": { 2248 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 2249 | "jiti": ">=1.21.0", 2250 | "less": "*", 2251 | "lightningcss": "^1.21.0", 2252 | "sass": "*", 2253 | "sass-embedded": "*", 2254 | "stylus": "*", 2255 | "sugarss": "*", 2256 | "terser": "^5.16.0", 2257 | "tsx": "^4.8.1", 2258 | "yaml": "^2.4.2" 2259 | }, 2260 | "peerDependenciesMeta": { 2261 | "@types/node": { 2262 | "optional": true 2263 | }, 2264 | "jiti": { 2265 | "optional": true 2266 | }, 2267 | "less": { 2268 | "optional": true 2269 | }, 2270 | "lightningcss": { 2271 | "optional": true 2272 | }, 2273 | "sass": { 2274 | "optional": true 2275 | }, 2276 | "sass-embedded": { 2277 | "optional": true 2278 | }, 2279 | "stylus": { 2280 | "optional": true 2281 | }, 2282 | "sugarss": { 2283 | "optional": true 2284 | }, 2285 | "terser": { 2286 | "optional": true 2287 | }, 2288 | "tsx": { 2289 | "optional": true 2290 | }, 2291 | "yaml": { 2292 | "optional": true 2293 | } 2294 | } 2295 | }, 2296 | "node_modules/vite-node": { 2297 | "version": "3.0.2", 2298 | "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.2.tgz", 2299 | "integrity": "sha512-hsEQerBAHvVAbv40m3TFQe/lTEbOp7yDpyqMJqr2Tnd+W58+DEYOt+fluQgekOePcsNBmR77lpVAnIU2Xu4SvQ==", 2300 | "dev": true, 2301 | "dependencies": { 2302 | "cac": "^6.7.14", 2303 | "debug": "^4.4.0", 2304 | "es-module-lexer": "^1.6.0", 2305 | "pathe": "^2.0.1", 2306 | "vite": "^5.0.0 || ^6.0.0" 2307 | }, 2308 | "bin": { 2309 | "vite-node": "vite-node.mjs" 2310 | }, 2311 | "engines": { 2312 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 2313 | }, 2314 | "funding": { 2315 | "url": "https://opencollective.com/vitest" 2316 | } 2317 | }, 2318 | "node_modules/vitest": { 2319 | "version": "3.0.2", 2320 | "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.2.tgz", 2321 | "integrity": "sha512-5bzaHakQ0hmVVKLhfh/jXf6oETDBtgPo8tQCHYB+wftNgFJ+Hah67IsWc8ivx4vFL025Ow8UiuTf4W57z4izvQ==", 2322 | "dev": true, 2323 | "dependencies": { 2324 | "@vitest/expect": "3.0.2", 2325 | "@vitest/mocker": "3.0.2", 2326 | "@vitest/pretty-format": "^3.0.2", 2327 | "@vitest/runner": "3.0.2", 2328 | "@vitest/snapshot": "3.0.2", 2329 | "@vitest/spy": "3.0.2", 2330 | "@vitest/utils": "3.0.2", 2331 | "chai": "^5.1.2", 2332 | "debug": "^4.4.0", 2333 | "expect-type": "^1.1.0", 2334 | "magic-string": "^0.30.17", 2335 | "pathe": "^2.0.1", 2336 | "std-env": "^3.8.0", 2337 | "tinybench": "^2.9.0", 2338 | "tinyexec": "^0.3.2", 2339 | "tinypool": "^1.0.2", 2340 | "tinyrainbow": "^2.0.0", 2341 | "vite": "^5.0.0 || ^6.0.0", 2342 | "vite-node": "3.0.2", 2343 | "why-is-node-running": "^2.3.0" 2344 | }, 2345 | "bin": { 2346 | "vitest": "vitest.mjs" 2347 | }, 2348 | "engines": { 2349 | "node": "^18.0.0 || ^20.0.0 || >=22.0.0" 2350 | }, 2351 | "funding": { 2352 | "url": "https://opencollective.com/vitest" 2353 | }, 2354 | "peerDependencies": { 2355 | "@edge-runtime/vm": "*", 2356 | "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", 2357 | "@vitest/browser": "3.0.2", 2358 | "@vitest/ui": "3.0.2", 2359 | "happy-dom": "*", 2360 | "jsdom": "*" 2361 | }, 2362 | "peerDependenciesMeta": { 2363 | "@edge-runtime/vm": { 2364 | "optional": true 2365 | }, 2366 | "@types/node": { 2367 | "optional": true 2368 | }, 2369 | "@vitest/browser": { 2370 | "optional": true 2371 | }, 2372 | "@vitest/ui": { 2373 | "optional": true 2374 | }, 2375 | "happy-dom": { 2376 | "optional": true 2377 | }, 2378 | "jsdom": { 2379 | "optional": true 2380 | } 2381 | } 2382 | }, 2383 | "node_modules/why-is-node-running": { 2384 | "version": "2.3.0", 2385 | "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", 2386 | "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", 2387 | "dev": true, 2388 | "dependencies": { 2389 | "siginfo": "^2.0.0", 2390 | "stackback": "0.0.2" 2391 | }, 2392 | "bin": { 2393 | "why-is-node-running": "cli.js" 2394 | }, 2395 | "engines": { 2396 | "node": ">=8" 2397 | } 2398 | }, 2399 | "node_modules/winston": { 2400 | "version": "3.17.0", 2401 | "resolved": "https://registry.npmjs.org/winston/-/winston-3.17.0.tgz", 2402 | "integrity": "sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==", 2403 | "dependencies": { 2404 | "@colors/colors": "^1.6.0", 2405 | "@dabh/diagnostics": "^2.0.2", 2406 | "async": "^3.2.3", 2407 | "is-stream": "^2.0.0", 2408 | "logform": "^2.7.0", 2409 | "one-time": "^1.0.0", 2410 | "readable-stream": "^3.4.0", 2411 | "safe-stable-stringify": "^2.3.1", 2412 | "stack-trace": "0.0.x", 2413 | "triple-beam": "^1.3.0", 2414 | "winston-transport": "^4.9.0" 2415 | }, 2416 | "engines": { 2417 | "node": ">= 12.0.0" 2418 | } 2419 | }, 2420 | "node_modules/winston-transport": { 2421 | "version": "4.9.0", 2422 | "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.9.0.tgz", 2423 | "integrity": "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==", 2424 | "dependencies": { 2425 | "logform": "^2.7.0", 2426 | "readable-stream": "^3.6.2", 2427 | "triple-beam": "^1.3.0" 2428 | }, 2429 | "engines": { 2430 | "node": ">= 12.0.0" 2431 | } 2432 | }, 2433 | "node_modules/wrap-ansi": { 2434 | "version": "7.0.0", 2435 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 2436 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 2437 | "dependencies": { 2438 | "ansi-styles": "^4.0.0", 2439 | "string-width": "^4.1.0", 2440 | "strip-ansi": "^6.0.0" 2441 | }, 2442 | "engines": { 2443 | "node": ">=10" 2444 | }, 2445 | "funding": { 2446 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 2447 | } 2448 | }, 2449 | "node_modules/ws": { 2450 | "version": "8.18.0", 2451 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", 2452 | "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", 2453 | "engines": { 2454 | "node": ">=10.0.0" 2455 | }, 2456 | "peerDependencies": { 2457 | "bufferutil": "^4.0.1", 2458 | "utf-8-validate": ">=5.0.2" 2459 | }, 2460 | "peerDependenciesMeta": { 2461 | "bufferutil": { 2462 | "optional": true 2463 | }, 2464 | "utf-8-validate": { 2465 | "optional": true 2466 | } 2467 | } 2468 | }, 2469 | "node_modules/xtend": { 2470 | "version": "4.0.2", 2471 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 2472 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 2473 | "engines": { 2474 | "node": ">=0.4" 2475 | } 2476 | }, 2477 | "node_modules/y18n": { 2478 | "version": "5.0.8", 2479 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", 2480 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", 2481 | "engines": { 2482 | "node": ">=10" 2483 | } 2484 | }, 2485 | "node_modules/yargs": { 2486 | "version": "17.7.2", 2487 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", 2488 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", 2489 | "dependencies": { 2490 | "cliui": "^8.0.1", 2491 | "escalade": "^3.1.1", 2492 | "get-caller-file": "^2.0.5", 2493 | "require-directory": "^2.1.1", 2494 | "string-width": "^4.2.3", 2495 | "y18n": "^5.0.5", 2496 | "yargs-parser": "^21.1.1" 2497 | }, 2498 | "engines": { 2499 | "node": ">=12" 2500 | } 2501 | }, 2502 | "node_modules/yargs-parser": { 2503 | "version": "21.1.1", 2504 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", 2505 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", 2506 | "engines": { 2507 | "node": ">=12" 2508 | } 2509 | } 2510 | } 2511 | } 2512 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ekubo/indexer", 3 | "private": true, 4 | "version": "0.0.1", 5 | "main": "index.js", 6 | "description": "Indexes Ekubo data", 7 | "scripts": { 8 | "start": "NETWORK=mainnet jiti src/index.ts", 9 | "start:sepolia": "NETWORK=sepolia jiti src/index.ts", 10 | "test": "vitest" 11 | }, 12 | "author": "Moody Salem", 13 | "type": "module", 14 | "engines": { 15 | "node": "^22.10.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "^22.10.7", 19 | "@types/pg": "^8.11.10", 20 | "typescript": "^5.7.3", 21 | "vitest": "^3.0.2" 22 | }, 23 | "dependencies": { 24 | "@apibara/protocol": "^2.1.0-beta.34", 25 | "@apibara/starknet": "^2.1.0-beta.34", 26 | "dotenv": "^16.4.7", 27 | "jiti": "^2.4.2", 28 | "pg": "^8.13.1", 29 | "tadaaa": "^1.0.1", 30 | "winston": "^3.17.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import { config } from "dotenv"; 2 | 3 | config({ path: `./.env.local` }); 4 | config({ path: `./.env.${process.env.NETWORK}.local` }); 5 | config({ path: `./.env.${process.env.NETWORK}` }); 6 | config({ path: `./.env` }); 7 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace NodeJS { 2 | export interface ProcessEnv { 3 | LOG_LEVEL: string; 4 | 5 | CORE_ADDRESS: `0x${string}`; 6 | POSITIONS_ADDRESS: `0x${string}`; 7 | NFT_ADDRESS: `0x${string}`; 8 | TWAMM_ADDRESS: `0x${string}`; 9 | STAKER_ADDRESS: `0x${string}`; 10 | GOVERNOR_ADDRESS: `0x${string}`; 11 | ORACLE_ADDRESS: `0x${string}`; 12 | LIMIT_ORDERS_ADDRESS: `0x${string}`; 13 | 14 | TOKEN_REGISTRY_ADDRESS: `0x${string}`; 15 | TOKEN_REGISTRY_V2_ADDRESS: `0x${string}`; 16 | TOKEN_REGISTRY_V3_ADDRESS: `0x${string}`; 17 | 18 | STARTING_CURSOR_BLOCK_NUMBER: string; 19 | 20 | REFRESH_RATE_ANALYTICAL_VIEWS: string; 21 | 22 | NETWORK: "mainnet" | "sepolia" | string; 23 | 24 | APIBARA_URL: string; 25 | DNA_TOKEN: string; 26 | 27 | PG_CONNECTION_STRING: string; 28 | 29 | NO_BLOCKS_TIMEOUT_MS: string; // Time in milliseconds before exiting if no blocks are received 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/eventProcessors.ts: -------------------------------------------------------------------------------- 1 | import type { EventProcessor } from "./processor"; 2 | import { logger } from "./logger"; 3 | import { parseTransferEvent } from "./events/nft"; 4 | import type { TransferEvent } from "./events/nft"; 5 | import { 6 | parseFeesAccumulatedEvent, 7 | parsePoolInitializedEvent, 8 | parsePositionFeesCollectedEvent, 9 | parsePositionUpdatedEvent, 10 | parseProtocolFeesPaidEvent, 11 | parseProtocolFeesWithdrawnEvent, 12 | parseSwappedEvent, 13 | } from "./events/core"; 14 | import type { 15 | FeesAccumulatedEvent, 16 | PoolInitializationEvent, 17 | PositionFeesCollectedEvent, 18 | PositionUpdatedEvent, 19 | ProtocolFeesPaidEvent, 20 | ProtocolFeesWithdrawnEvent, 21 | SwappedEvent, 22 | } from "./events/core"; 23 | import { 24 | parseLegacyPositionMintedEvent, 25 | parsePositionMintedWithReferrerEvent, 26 | } from "./events/positions"; 27 | import type { 28 | LegacyPositionMintedEvent, 29 | PositionMintedWithReferrer, 30 | } from "./events/positions"; 31 | import { 32 | parseOrderProceedsWithdrawn, 33 | parseOrderUpdated, 34 | parseVirtualOrdersExecuted, 35 | } from "./events/twamm"; 36 | import type { 37 | OrderProceedsWithdrawnEvent, 38 | OrderUpdatedEvent, 39 | VirtualOrdersExecutedEvent, 40 | } from "./events/twamm"; 41 | import { parseStakedEvent, parseWithdrawnEvent } from "./events/staker"; 42 | import type { StakedEvent, WithdrawnEvent } from "./events/staker"; 43 | import { 44 | parseDescribedEvent, 45 | parseGovernorCanceledEvent, 46 | parseGovernorCreationThresholdBreached, 47 | parseGovernorExecutedEvent, 48 | parseGovernorProposedEvent, 49 | parseGovernorReconfigured, 50 | parseGovernorVotedEvent, 51 | } from "./events/governor"; 52 | import type { 53 | DescribedEvent, 54 | GovernorCanceledEvent, 55 | GovernorCreationThresholdBreached, 56 | GovernorExecutedEvent, 57 | GovernorProposedEvent, 58 | GovernorReconfiguredEvent, 59 | GovernorVotedEvent, 60 | } from "./events/governor"; 61 | import { 62 | parseRegistrationEvent, 63 | parseRegistrationEventV3, 64 | } from "./events/tokenRegistry"; 65 | import type { 66 | TokenRegistrationEvent, 67 | TokenRegistrationEventV3, 68 | } from "./events/tokenRegistry"; 69 | import { parseSnapshotEvent } from "./events/oracle"; 70 | import type { SnapshotEvent } from "./events/oracle"; 71 | import { parseOrderClosed, parseOrderPlaced } from "./events/limitOrders"; 72 | import type { OrderClosedEvent, OrderPlacedEvent } from "./events/limitOrders"; 73 | 74 | export const EVENT_PROCESSORS = [ 75 | >{ 76 | filter: { 77 | fromAddress: process.env.POSITIONS_ADDRESS, 78 | keys: [ 79 | // PositionMinted 80 | "0x2a9157ea1542bfe11220258bf15d8aa02d791e7f94426446ec85b94159929f", 81 | ], 82 | }, 83 | parser: parseLegacyPositionMintedEvent, 84 | handle: async (dao, { key, parsed }) => { 85 | logger.debug("PositionMinted", { parsed, key }); 86 | if (parsed.referrer !== null && parsed.referrer !== 0n) { 87 | await dao.insertPositionMintedWithReferrerEvent( 88 | { id: parsed.id, referrer: parsed.referrer ?? 0n }, 89 | key, 90 | ); 91 | } 92 | }, 93 | }, 94 | >{ 95 | filter: { 96 | fromAddress: process.env.POSITIONS_ADDRESS, 97 | keys: [ 98 | // PositionMintedWithReferrer 99 | "0x0289e57bf153052470392b578fad8d64393d2b5307e0cf1bf59f7967db3480fd", 100 | ], 101 | }, 102 | parser: parsePositionMintedWithReferrerEvent, 103 | async handle(dao, { parsed, key }): Promise { 104 | logger.debug("Referral", { parsed, key }); 105 | await dao.insertPositionMintedWithReferrerEvent(parsed, key); 106 | }, 107 | }, 108 | >{ 109 | filter: { 110 | fromAddress: process.env.NFT_ADDRESS, 111 | keys: [ 112 | // Transfer 113 | "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9", 114 | ], 115 | }, 116 | parser: parseTransferEvent, 117 | async handle(dao, { parsed, key }): Promise { 118 | logger.debug("NFT transferred", { parsed, key }); 119 | await dao.insertPositionTransferEvent(parsed, key); 120 | }, 121 | }, 122 | >{ 123 | filter: { 124 | fromAddress: process.env.CORE_ADDRESS, 125 | keys: [ 126 | // PositionUpdated 127 | "0x03a7adca3546c213ce791fabf3b04090c163e419c808c9830fb343a4a395946e", 128 | ], 129 | }, 130 | parser: parsePositionUpdatedEvent, 131 | async handle(dao, { parsed, key }): Promise { 132 | logger.debug("PositionUpdated", { parsed, key }); 133 | await dao.insertPositionUpdatedEvent(parsed, key); 134 | }, 135 | }, 136 | >{ 137 | filter: { 138 | fromAddress: process.env.CORE_ADDRESS, 139 | keys: [ 140 | // PositionFeesCollected 141 | "0x96982abd597114bdaa4a60612f87fabfcc7206aa12d61c50e7ba1e6c291100", 142 | ], 143 | }, 144 | parser: parsePositionFeesCollectedEvent, 145 | async handle(dao, { parsed, key }): Promise { 146 | logger.debug("PositionFeesCollected", { parsed, key }); 147 | await dao.insertPositionFeesCollectedEvent(parsed, key); 148 | }, 149 | }, 150 | >{ 151 | filter: { 152 | fromAddress: process.env.CORE_ADDRESS, 153 | keys: [ 154 | // Swapped 155 | "0x157717768aca88da4ac4279765f09f4d0151823d573537fbbeb950cdbd9a870", 156 | ], 157 | }, 158 | parser: parseSwappedEvent, 159 | async handle(dao, { parsed, key }): Promise { 160 | logger.debug("Swapped", { parsed, key }); 161 | await dao.insertSwappedEvent(parsed, key); 162 | }, 163 | }, 164 | >{ 165 | filter: { 166 | fromAddress: process.env.CORE_ADDRESS, 167 | keys: [ 168 | // PoolInitialized 169 | "0x025ccf80ee62b2ca9b97c76ccea317c7f450fd6efb6ed6ea56da21d7bb9da5f1", 170 | ], 171 | }, 172 | parser: parsePoolInitializedEvent, 173 | async handle(dao, { parsed, key }): Promise { 174 | logger.debug("PoolInitialized", { parsed, key }); 175 | await dao.insertInitializationEvent(parsed, key); 176 | }, 177 | }, 178 | >{ 179 | filter: { 180 | fromAddress: process.env.CORE_ADDRESS, 181 | keys: [ 182 | // ProtocolFeesWithdrawn 183 | "0x291697c8230383d5c3cc8dc39443356a7da6b0735605fb0ee0f7bfbb7b824a", 184 | ], 185 | }, 186 | parser: parseProtocolFeesWithdrawnEvent, 187 | async handle(dao, { parsed, key }): Promise { 188 | logger.debug("ProtocolFeesWithdrawn", { parsed, key }); 189 | await dao.insertProtocolFeesWithdrawn(parsed, key); 190 | }, 191 | }, 192 | >{ 193 | filter: { 194 | fromAddress: process.env.CORE_ADDRESS, 195 | keys: [ 196 | // ProtocolFeesPaid 197 | "0x5dacf59794364ad1555bb3c9b2346afa81e57e5c19bb6bae0d22721c96c4e5", 198 | ], 199 | }, 200 | parser: parseProtocolFeesPaidEvent, 201 | async handle(dao, { parsed, key }): Promise { 202 | logger.debug("ProtocolFeesPaid", { parsed, key }); 203 | await dao.insertProtocolFeesPaid(parsed, key); 204 | }, 205 | }, 206 | >{ 207 | filter: { 208 | fromAddress: process.env.CORE_ADDRESS, 209 | keys: [ 210 | // FeesAccumulated 211 | "0x0237e5e0677822acfc9117ed0f7ba4810b2c6b539a2359e8d73f9025d56957aa", 212 | ], 213 | }, 214 | parser: parseFeesAccumulatedEvent, 215 | async handle(dao, { parsed, key }): Promise { 216 | logger.debug("FeesAccumulated", { parsed, key }); 217 | await dao.insertFeesAccumulatedEvent(parsed, key); 218 | }, 219 | }, 220 | >{ 221 | filter: { 222 | fromAddress: process.env.TOKEN_REGISTRY_ADDRESS, 223 | keys: [ 224 | // Registration 225 | "0x3ea44da5af08f985c5ac763fa2573381d77aeee47d9a845f0c6764cb805d74", 226 | ], 227 | }, 228 | parser: parseRegistrationEvent, 229 | async handle(dao, { parsed, key }): Promise { 230 | logger.debug("Registration from V1 Registry", { parsed, key }); 231 | await dao.insertRegistration(parsed, key); 232 | }, 233 | }, 234 | >{ 235 | filter: { 236 | fromAddress: process.env.TOKEN_REGISTRY_V2_ADDRESS, 237 | keys: [ 238 | // Registration 239 | "0x3ea44da5af08f985c5ac763fa2573381d77aeee47d9a845f0c6764cb805d74", 240 | ], 241 | }, 242 | parser: parseRegistrationEvent, 243 | async handle(dao, { parsed, key }): Promise { 244 | logger.debug("Registration from V2 Registry", { 245 | parsed, 246 | key, 247 | }); 248 | await dao.insertRegistration(parsed, key); 249 | }, 250 | }, 251 | >{ 252 | filter: { 253 | fromAddress: process.env.TOKEN_REGISTRY_V3_ADDRESS, 254 | keys: [ 255 | // Registration 256 | "0x3ea44da5af08f985c5ac763fa2573381d77aeee47d9a845f0c6764cb805d74", 257 | ], 258 | }, 259 | parser: parseRegistrationEventV3, 260 | async handle(dao, { parsed, key }): Promise { 261 | logger.debug("Registration event from V3 Registry", { parsed, key }); 262 | await dao.insertRegistrationV3(parsed, key); 263 | }, 264 | }, 265 | >{ 266 | filter: { 267 | fromAddress: process.env.TWAMM_ADDRESS, 268 | keys: [ 269 | // OrderUpdated 270 | "0xb670ed7b7ee8ccb350963a7dea39493daff6e7a43ab021a0e4ac2d652d359e", 271 | ], 272 | }, 273 | parser: parseOrderUpdated, 274 | async handle(dao, { parsed, key }): Promise { 275 | logger.debug("OrderUpdated", { parsed, key }); 276 | await dao.insertTWAMMOrderUpdatedEvent(parsed, key); 277 | }, 278 | }, 279 | >{ 280 | filter: { 281 | fromAddress: process.env.TWAMM_ADDRESS, 282 | keys: [ 283 | // OrderProceedsWithdrawn 284 | "0x3e074150c5906b2e323cea942b41f67f3639fcae5dc1fe4cf19c6801dff89b5", 285 | ], 286 | }, 287 | parser: parseOrderProceedsWithdrawn, 288 | async handle(dao, { parsed, key }): Promise { 289 | logger.debug("OrderProceedsWithdrawn", { parsed, key }); 290 | await dao.insertTWAMMOrderProceedsWithdrawnEvent(parsed, key); 291 | }, 292 | }, 293 | >{ 294 | filter: { 295 | fromAddress: process.env.TWAMM_ADDRESS, 296 | keys: [ 297 | // VirtualOrdersExecuted 298 | "0x29416aa69fb4a5270dd3c2b3e6d05f457dc0dbf96f423db1f86c5b7b2e6840f", 299 | ], 300 | }, 301 | parser: parseVirtualOrdersExecuted, 302 | async handle(dao, { parsed, key }): Promise { 303 | logger.debug("VirtualOrdersExecuted", { parsed, key }); 304 | await dao.insertTWAMMVirtualOrdersExecutedEvent(parsed, key); 305 | }, 306 | }, 307 | >{ 308 | filter: { 309 | fromAddress: process.env.STAKER_ADDRESS, 310 | keys: [ 311 | // Staked 312 | "0x024fdaadc324c3bb8e59febfb2e8a399331e58193489e54ac40fec46745a9ebe", 313 | ], 314 | }, 315 | parser: parseStakedEvent, 316 | async handle(dao, { parsed, key }): Promise { 317 | logger.debug("StakerStakedEvent", { parsed, key }); 318 | await dao.insertStakerStakedEvent(parsed, key); 319 | }, 320 | }, 321 | >{ 322 | filter: { 323 | fromAddress: process.env.STAKER_ADDRESS, 324 | keys: [ 325 | // Withdrawn 326 | "0x036a4d15ab9e146faab90d4abc1c0cad17c4ded24551c781ba100392b5a70248", 327 | ], 328 | }, 329 | parser: parseWithdrawnEvent, 330 | async handle(dao, { parsed, key }): Promise { 331 | logger.debug("StakerWithdrawnEvent", { parsed, key }); 332 | await dao.insertStakerWithdrawnEvent(parsed, key); 333 | }, 334 | }, 335 | >{ 336 | filter: { 337 | fromAddress: process.env.GOVERNOR_ADDRESS, 338 | keys: [ 339 | // Proposed 340 | "0x02a98c37f5b13fe14803e72b284c81be9ebbedc6cf74ed8d1489ed74951cba3f", 341 | ], 342 | }, 343 | parser: parseGovernorProposedEvent, 344 | async handle(dao, { parsed, key }): Promise { 345 | logger.debug("GovernorProposed", { parsed, key }); 346 | await dao.insertGovernorProposedEvent(parsed, key); 347 | }, 348 | }, 349 | >{ 350 | filter: { 351 | fromAddress: process.env.GOVERNOR_ADDRESS, 352 | keys: [ 353 | // Canceled 354 | "0xad1f80a0e6ac2d42f6ce99670de84817aef2368cd22a19f85fcb721f689192", 355 | ], 356 | }, 357 | parser: parseGovernorCanceledEvent, 358 | async handle(dao, { parsed, key }): Promise { 359 | logger.debug("GovernorCanceled", { parsed, key }); 360 | await dao.insertGovernorCanceledEvent(parsed, key); 361 | }, 362 | }, 363 | >{ 364 | filter: { 365 | fromAddress: process.env.GOVERNOR_ADDRESS, 366 | keys: [ 367 | // CreationThresholdBreached 368 | "0xda0eb1cb71bdbfac21648d8b87024714f7eb6207978c7eb359a20144a99baf", 369 | ], 370 | }, 371 | parser: parseGovernorCreationThresholdBreached, 372 | async handle(dao, { parsed, key }): Promise { 373 | logger.debug("GovernorCreationThresholdBreached", { parsed, key }); 374 | // just use the canceled table 375 | await dao.insertGovernorCanceledEvent(parsed, key); 376 | }, 377 | }, 378 | >{ 379 | filter: { 380 | fromAddress: process.env.GOVERNOR_ADDRESS, 381 | keys: [ 382 | // Voted 383 | "0x5c9afac1c510b50d3e0004024ba7b8e190864f1543dd8025d08f88410fb162", 384 | ], 385 | }, 386 | parser: parseGovernorVotedEvent, 387 | async handle(dao, { parsed, key }): Promise { 388 | logger.debug("GovernorVoted", { parsed, key }); 389 | await dao.insertGovernorVotedEvent(parsed, key); 390 | }, 391 | }, 392 | >{ 393 | filter: { 394 | fromAddress: process.env.GOVERNOR_ADDRESS, 395 | keys: [ 396 | // Executed 397 | "0x01f4317aae43f6c24b2b85c6d8b21d5fa0a28cee0476cd52ca5d60d4787aab78", 398 | ], 399 | }, 400 | parser: parseGovernorExecutedEvent, 401 | async handle(dao, { parsed, key }): Promise { 402 | logger.debug("GovernorExecuted", { parsed, key }); 403 | await dao.insertGovernorExecutedEvent(parsed, key); 404 | }, 405 | }, 406 | >{ 407 | filter: { 408 | fromAddress: process.env.GOVERNOR_ADDRESS, 409 | keys: [ 410 | // Described 411 | "0x8643a1c8a461189d5b77de7576b06aa9148c9127101228f02816d13768e7a9", 412 | ], 413 | }, 414 | parser: parseDescribedEvent, 415 | async handle(dao, { parsed, key }): Promise { 416 | logger.debug("GovernorProposalDescribed", { parsed, key }); 417 | await dao.insertGovernorProposalDescribedEvent(parsed, key); 418 | }, 419 | }, 420 | >{ 421 | filter: { 422 | fromAddress: process.env.GOVERNOR_ADDRESS, 423 | keys: [ 424 | // Reconfigured 425 | "0x02b9973fd701ab68169e139e241db74576eca4e885bad73d016982a59f1ac9fb", 426 | ], 427 | }, 428 | parser: parseGovernorReconfigured, 429 | async handle(dao, { parsed, key }): Promise { 430 | logger.debug("GovernorReconfigured", { parsed, key }); 431 | await dao.insertGovernorReconfiguredEvent(parsed, key); 432 | }, 433 | }, 434 | >{ 435 | filter: { 436 | fromAddress: process.env.ORACLE_ADDRESS, 437 | keys: [ 438 | // SnapshotEvent 439 | "0x0385e1b60fdfb8aeee9212a69cdb72415cef7b24ec07a60cdd65b65d0582238b", 440 | ], 441 | }, 442 | parser: parseSnapshotEvent, 443 | async handle(dao, { parsed, key }): Promise { 444 | logger.debug("Snapshot", { parsed, key }); 445 | await dao.insertOracleSnapshotEvent(parsed, key); 446 | }, 447 | }, 448 | >{ 449 | filter: { 450 | fromAddress: process.env.LIMIT_ORDERS_ADDRESS, 451 | keys: [ 452 | // OrderPlaced 453 | "0x03b935dbbdb7f463a394fc8729e7e26e30edebbc3bd5617bf1d7cf9e1ce6f7cb", 454 | ], 455 | }, 456 | parser: parseOrderPlaced, 457 | async handle(dao, { parsed, key }): Promise { 458 | logger.debug("OrderPlaced", { parsed, key }); 459 | await dao.insertOrderPlacedEvent(parsed, key); 460 | }, 461 | }, 462 | >{ 463 | filter: { 464 | fromAddress: process.env.LIMIT_ORDERS_ADDRESS, 465 | keys: [ 466 | // OrderClosed 467 | "0x0196e77c6eab92283e3fc303198bb0a523c0c7d93b4de1d8bf636eab7517c4ae", 468 | ], 469 | }, 470 | parser: parseOrderClosed, 471 | async handle(dao, { parsed, key }): Promise { 472 | logger.debug("OrderClosed", { parsed, key }); 473 | await dao.insertOrderClosedEvent(parsed, key); 474 | }, 475 | }, 476 | ] as const; 477 | -------------------------------------------------------------------------------- /src/events/core.ts: -------------------------------------------------------------------------------- 1 | import { 2 | combineParsers, 3 | parseAddress, 4 | parseBoolean, 5 | parseI129, 6 | parseU128, 7 | parseU256, 8 | } from "../parse"; 9 | import type { GetParserType } from "../parse"; 10 | 11 | export const parsePoolKey = combineParsers({ 12 | token0: { index: 0, parser: parseAddress }, 13 | token1: { index: 1, parser: parseAddress }, 14 | fee: { index: 2, parser: parseU128 }, 15 | tick_spacing: { index: 3, parser: parseU128 }, 16 | extension: { index: 4, parser: parseAddress }, 17 | }); 18 | export type PoolKey = GetParserType; 19 | export const parseBounds = combineParsers({ 20 | lower: { index: 0, parser: parseI129 }, 21 | upper: { index: 1, parser: parseI129 }, 22 | }); 23 | export type Bounds = GetParserType; 24 | const parseUpdatePositionParams = combineParsers({ 25 | salt: { index: 0, parser: parseU128 }, 26 | bounds: { index: 1, parser: parseBounds }, 27 | liquidity_delta: { index: 2, parser: parseI129 }, 28 | }); 29 | export type UpdatePositionParameters = GetParserType< 30 | typeof parseUpdatePositionParams 31 | >; 32 | export const parseDelta = combineParsers({ 33 | amount0: { index: 0, parser: parseI129 }, 34 | amount1: { index: 1, parser: parseI129 }, 35 | }); 36 | export type Delta = GetParserType; 37 | export const parsePositionUpdatedEvent = combineParsers({ 38 | locker: { index: 0, parser: parseAddress }, 39 | pool_key: { index: 1, parser: parsePoolKey }, 40 | params: { index: 2, parser: parseUpdatePositionParams }, 41 | delta: { index: 3, parser: parseDelta }, 42 | }); 43 | export type PositionUpdatedEvent = GetParserType< 44 | typeof parsePositionUpdatedEvent 45 | >; 46 | export const parsePositionKey = combineParsers({ 47 | salt: { index: 0, parser: parseU128 }, 48 | owner: { index: 1, parser: parseAddress }, 49 | bounds: { index: 2, parser: parseBounds }, 50 | }); 51 | export const parsePositionFeesCollectedEvent = combineParsers({ 52 | pool_key: { index: 1, parser: parsePoolKey }, 53 | position_key: { index: 2, parser: parsePositionKey }, 54 | delta: { index: 3, parser: parseDelta }, 55 | }); 56 | export type PositionFeesCollectedEvent = GetParserType< 57 | typeof parsePositionFeesCollectedEvent 58 | >; 59 | export const parseProtocolFeesWithdrawnEvent = combineParsers({ 60 | recipient: { index: 0, parser: parseAddress }, 61 | token: { index: 1, parser: parseAddress }, 62 | amount: { index: 2, parser: parseU128 }, 63 | }); 64 | export type ProtocolFeesWithdrawnEvent = GetParserType< 65 | typeof parseProtocolFeesWithdrawnEvent 66 | >; 67 | const parseSwapParameters = combineParsers({ 68 | amount: { index: 0, parser: parseI129 }, 69 | is_token1: { index: 1, parser: parseBoolean }, 70 | sqrt_ratio_limit: { index: 2, parser: parseU256 }, 71 | skip_ahead: { index: 3, parser: parseU128 }, 72 | }); 73 | export const parseSwappedEvent = combineParsers({ 74 | locker: { index: 0, parser: parseAddress }, 75 | pool_key: { index: 1, parser: parsePoolKey }, 76 | params: { index: 2, parser: parseSwapParameters }, 77 | delta: { index: 3, parser: parseDelta }, 78 | sqrt_ratio_after: { index: 4, parser: parseU256 }, 79 | tick_after: { index: 5, parser: parseI129 }, 80 | liquidity_after: { index: 6, parser: parseU128 }, 81 | }); 82 | export type SwappedEvent = GetParserType; 83 | export const parsePoolInitializedEvent = combineParsers({ 84 | pool_key: { index: 0, parser: parsePoolKey }, 85 | tick: { index: 1, parser: parseI129 }, 86 | sqrt_ratio: { index: 2, parser: parseU256 }, 87 | }); 88 | export type PoolInitializationEvent = GetParserType< 89 | typeof parsePoolInitializedEvent 90 | >; 91 | export const parseProtocolFeesPaidEvent = combineParsers({ 92 | pool_key: { index: 0, parser: parsePoolKey }, 93 | position_key: { index: 1, parser: parsePositionKey }, 94 | delta: { index: 2, parser: parseDelta }, 95 | }); 96 | export type ProtocolFeesPaidEvent = GetParserType< 97 | typeof parseProtocolFeesPaidEvent 98 | >; 99 | 100 | export const parseFeesAccumulatedEvent = combineParsers({ 101 | pool_key: { index: 0, parser: parsePoolKey }, 102 | amount0: { index: 1, parser: parseU128 }, 103 | amount1: { index: 2, parser: parseU128 }, 104 | }); 105 | export type FeesAccumulatedEvent = GetParserType< 106 | typeof parseFeesAccumulatedEvent 107 | >; 108 | -------------------------------------------------------------------------------- /src/events/governor.ts: -------------------------------------------------------------------------------- 1 | import { 2 | backwardsCompatibleParserAdditionalArgument, 3 | combineParsers, 4 | parseAddress, 5 | parseBoolean, 6 | parseByteArray, 7 | parseFelt252, 8 | parseSpanOf, 9 | parseU128, 10 | parseU64, 11 | } from "../parse"; 12 | import type { GetParserType } from "../parse"; 13 | 14 | export const parseCall = combineParsers({ 15 | to: { index: 0, parser: parseAddress }, 16 | selector: { index: 1, parser: parseFelt252 }, 17 | calldata: { index: 2, parser: parseSpanOf(parseFelt252) }, 18 | }); 19 | export type CallType = GetParserType; 20 | 21 | export const parseGovernorProposedEvent = combineParsers({ 22 | id: { index: 0, parser: parseFelt252 }, 23 | proposer: { index: 1, parser: parseAddress }, 24 | calls: { index: 2, parser: parseSpanOf(parseCall) }, 25 | config_version: { 26 | index: 3, 27 | parser: backwardsCompatibleParserAdditionalArgument(parseU64), 28 | }, 29 | }); 30 | export type GovernorProposedEvent = GetParserType< 31 | typeof parseGovernorProposedEvent 32 | >; 33 | 34 | export const parseGovernorVotedEvent = combineParsers({ 35 | id: { index: 0, parser: parseFelt252 }, 36 | voter: { index: 1, parser: parseAddress }, 37 | weight: { index: 2, parser: parseU128 }, 38 | yea: { index: 3, parser: parseBoolean }, 39 | }); 40 | export type GovernorVotedEvent = GetParserType; 41 | 42 | export const parseGovernorCanceledEvent = combineParsers({ 43 | id: { index: 0, parser: parseFelt252 }, 44 | }); 45 | export type GovernorCanceledEvent = GetParserType< 46 | typeof parseGovernorCanceledEvent 47 | >; 48 | 49 | export const parseGovernorCreationThresholdBreached = combineParsers({ 50 | id: { index: 0, parser: parseFelt252 }, 51 | breach_timestamp: { index: 0, parser: parseU64 }, 52 | }); 53 | export type GovernorCreationThresholdBreached = GetParserType< 54 | typeof parseGovernorCreationThresholdBreached 55 | >; 56 | 57 | export const parseGovernorExecutedEvent = combineParsers({ 58 | id: { index: 0, parser: parseFelt252 }, 59 | result_data: { index: 1, parser: parseSpanOf(parseSpanOf(parseFelt252)) }, 60 | }); 61 | export type GovernorExecutedEvent = GetParserType< 62 | typeof parseGovernorExecutedEvent 63 | >; 64 | 65 | export const parseDescribedEvent = combineParsers({ 66 | id: { index: 0, parser: parseFelt252 }, 67 | description: { index: 1, parser: parseByteArray }, 68 | }); 69 | export type DescribedEvent = GetParserType; 70 | 71 | export const parseGovernorConfig = combineParsers({ 72 | voting_start_delay: { index: 0, parser: parseU64 }, 73 | voting_period: { index: 1, parser: parseU64 }, 74 | voting_weight_smoothing_duration: { index: 2, parser: parseU64 }, 75 | quorum: { index: 3, parser: parseU128 }, 76 | proposal_creation_threshold: { index: 4, parser: parseU128 }, 77 | execution_delay: { index: 5, parser: parseU64 }, 78 | execution_window: { index: 6, parser: parseU64 }, 79 | }); 80 | export type GovernorConfig = GetParserType; 81 | 82 | export const parseGovernorReconfigured = combineParsers({ 83 | new_config: { index: 0, parser: parseGovernorConfig }, 84 | version: { index: 1, parser: parseU64 }, 85 | }); 86 | export type GovernorReconfiguredEvent = GetParserType< 87 | typeof parseGovernorReconfigured 88 | >; 89 | -------------------------------------------------------------------------------- /src/events/limitOrders.ts: -------------------------------------------------------------------------------- 1 | import { 2 | combineParsers, 3 | parseAddress, 4 | parseFelt252, 5 | parseI129, 6 | parseU128, 7 | } from "../parse"; 8 | import type { GetParserType } from "../parse"; 9 | 10 | export const parseLimitOrderKey = combineParsers({ 11 | token0: { index: 0, parser: parseAddress }, 12 | token1: { index: 1, parser: parseAddress }, 13 | tick: { index: 2, parser: parseI129 }, 14 | }); 15 | export type LimitOrderKey = GetParserType; 16 | 17 | export const parseOrderPlaced = combineParsers({ 18 | owner: { index: 0, parser: parseAddress }, 19 | salt: { index: 1, parser: parseFelt252 }, 20 | order_key: { index: 2, parser: parseLimitOrderKey }, 21 | liquidity: { index: 3, parser: parseU128 }, 22 | amount: { index: 4, parser: parseU128 }, 23 | }); 24 | export type OrderPlacedEvent = GetParserType; 25 | 26 | export const parseOrderClosed = combineParsers({ 27 | owner: { index: 0, parser: parseAddress }, 28 | salt: { index: 1, parser: parseFelt252 }, 29 | order_key: { index: 2, parser: parseLimitOrderKey }, 30 | amount0: { index: 3, parser: parseU128 }, 31 | amount1: { index: 4, parser: parseU128 }, 32 | }); 33 | export type OrderClosedEvent = GetParserType; 34 | -------------------------------------------------------------------------------- /src/events/nft.ts: -------------------------------------------------------------------------------- 1 | import { combineParsers, parseAddress, parseU256 } from "../parse"; 2 | import type { GetParserType } from "../parse"; 3 | 4 | export const parseTransferEvent = combineParsers({ 5 | from: { index: 0, parser: parseAddress }, 6 | to: { index: 1, parser: parseAddress }, 7 | id: { index: 2, parser: parseU256 }, 8 | }); 9 | export type TransferEvent = GetParserType; 10 | -------------------------------------------------------------------------------- /src/events/oracle.ts: -------------------------------------------------------------------------------- 1 | import { combineParsers, parseAddress, parseI129, parseU64 } from "../parse"; 2 | import type { GetParserType } from "../parse"; 3 | 4 | export const parseSnapshot = combineParsers({ 5 | block_timestamp: { index: 0, parser: parseU64 }, 6 | tick_cumulative: { index: 1, parser: parseI129 }, 7 | }); 8 | export type Snapshot = GetParserType; 9 | 10 | export const parseSnapshotEvent = combineParsers({ 11 | token0: { index: 0, parser: parseAddress }, 12 | token1: { index: 1, parser: parseAddress }, 13 | index: { index: 2, parser: parseU64 }, 14 | snapshot: { index: 3, parser: parseSnapshot }, 15 | }); 16 | export type SnapshotEvent = GetParserType; 17 | -------------------------------------------------------------------------------- /src/events/positions.ts: -------------------------------------------------------------------------------- 1 | import { 2 | backwardsCompatibleParserAdditionalArgument, 3 | combineParsers, 4 | parseAddress, 5 | parseU64, 6 | } from "../parse"; 7 | import { parseBounds, parsePoolKey } from "./core"; 8 | import type { GetParserType } from "../parse"; 9 | 10 | export const parseLegacyPositionMintedEvent = combineParsers({ 11 | id: { index: 0, parser: parseU64 }, 12 | pool_key: { index: 1, parser: parsePoolKey }, 13 | bounds: { index: 2, parser: parseBounds }, 14 | referrer: { 15 | index: 3, 16 | parser: backwardsCompatibleParserAdditionalArgument(parseAddress), 17 | }, 18 | }); 19 | export type LegacyPositionMintedEvent = GetParserType< 20 | typeof parseLegacyPositionMintedEvent 21 | >; 22 | 23 | export const parsePositionMintedWithReferrerEvent = combineParsers({ 24 | id: { index: 0, parser: parseU64 }, 25 | referrer: { index: 1, parser: parseAddress }, 26 | }); 27 | export type PositionMintedWithReferrer = GetParserType< 28 | typeof parsePositionMintedWithReferrerEvent 29 | >; 30 | -------------------------------------------------------------------------------- /src/events/staker.ts: -------------------------------------------------------------------------------- 1 | import { combineParsers, parseAddress, parseU128 } from "../parse"; 2 | import type { GetParserType } from "../parse"; 3 | 4 | export const parseStakedEvent = combineParsers({ 5 | from: { index: 0, parser: parseAddress }, 6 | amount: { index: 1, parser: parseU128 }, 7 | delegate: { index: 2, parser: parseAddress }, 8 | }); 9 | export type StakedEvent = GetParserType; 10 | 11 | export const parseWithdrawnEvent = combineParsers({ 12 | from: { index: 0, parser: parseAddress }, 13 | delegate: { index: 1, parser: parseAddress }, 14 | to: { index: 2, parser: parseAddress }, 15 | amount: { index: 3, parser: parseU128 }, 16 | }); 17 | export type WithdrawnEvent = GetParserType; 18 | -------------------------------------------------------------------------------- /src/events/tokenRegistry.ts: -------------------------------------------------------------------------------- 1 | import { 2 | combineParsers, 3 | parseAddress, 4 | parseByteArray, 5 | parseFelt252, 6 | parseU128, 7 | parseU8, 8 | } from "../parse"; 9 | import type { GetParserType } from "../parse"; 10 | 11 | export const parseRegistrationEvent = combineParsers({ 12 | address: { index: 0, parser: parseAddress }, 13 | name: { index: 1, parser: parseFelt252 }, 14 | symbol: { index: 2, parser: parseFelt252 }, 15 | decimals: { index: 2, parser: parseU8 }, 16 | total_supply: { index: 2, parser: parseU128 }, 17 | }); 18 | export type TokenRegistrationEvent = GetParserType< 19 | typeof parseRegistrationEvent 20 | >; 21 | 22 | export const parseRegistrationEventV3 = combineParsers({ 23 | address: { index: 0, parser: parseAddress }, 24 | name: { index: 1, parser: parseByteArray }, 25 | symbol: { index: 2, parser: parseByteArray }, 26 | decimals: { index: 2, parser: parseU8 }, 27 | total_supply: { index: 2, parser: parseU128 }, 28 | }); 29 | export type TokenRegistrationEventV3 = GetParserType< 30 | typeof parseRegistrationEventV3 31 | >; 32 | -------------------------------------------------------------------------------- /src/events/twamm.ts: -------------------------------------------------------------------------------- 1 | import { 2 | combineParsers, 3 | parseAddress, 4 | parseFelt252, 5 | parseI129, 6 | parseU128, 7 | parseU64, 8 | } from "../parse"; 9 | import { parseDelta } from "./core"; 10 | import type { GetParserType } from "../parse"; 11 | 12 | export const parseOrderKey = combineParsers({ 13 | sell_token: { index: 0, parser: parseAddress }, 14 | buy_token: { index: 1, parser: parseAddress }, 15 | fee: { index: 2, parser: parseU128 }, 16 | start_time: { index: 3, parser: parseU64 }, 17 | end_time: { index: 4, parser: parseU64 }, 18 | }); 19 | export type OrderKey = GetParserType; 20 | 21 | export const parseOrderUpdated = combineParsers({ 22 | owner: { index: 0, parser: parseAddress }, 23 | salt: { index: 1, parser: parseFelt252 }, 24 | order_key: { index: 2, parser: parseOrderKey }, 25 | sale_rate_delta: { index: 3, parser: parseI129 }, 26 | }); 27 | export type OrderUpdatedEvent = GetParserType; 28 | 29 | export const parseOrderProceedsWithdrawn = combineParsers({ 30 | owner: { index: 0, parser: parseAddress }, 31 | salt: { index: 1, parser: parseFelt252 }, 32 | order_key: { index: 2, parser: parseOrderKey }, 33 | amount: { index: 3, parser: parseU128 }, 34 | }); 35 | export type OrderProceedsWithdrawnEvent = GetParserType< 36 | typeof parseOrderProceedsWithdrawn 37 | >; 38 | 39 | export const parseStateKey = combineParsers({ 40 | token0: { index: 0, parser: parseAddress }, 41 | token1: { index: 1, parser: parseAddress }, 42 | fee: { index: 2, parser: parseU128 }, 43 | }); 44 | export type StateKey = GetParserType; 45 | 46 | export const parseVirtualOrdersExecuted = combineParsers({ 47 | key: { index: 0, parser: parseStateKey }, 48 | token0_sale_rate: { index: 1, parser: parseU128 }, 49 | token1_sale_rate: { index: 2, parser: parseU128 }, 50 | twamm_delta: { index: 3, parser: parseDelta }, 51 | }); 52 | export type VirtualOrdersExecutedEvent = GetParserType< 53 | typeof parseVirtualOrdersExecuted 54 | >; 55 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import "./config"; 2 | import { StarknetStream } from "@apibara/starknet"; 3 | import { createClient, Metadata } from "@apibara/protocol"; 4 | import type { EventKey } from "./processor"; 5 | import { logger } from "./logger"; 6 | import { DAO } from "./dao"; 7 | import { Pool } from "pg"; 8 | import { throttle } from "tadaaa"; 9 | import { EVENT_PROCESSORS } from "./eventProcessors"; 10 | 11 | const pool = new Pool({ 12 | connectionString: process.env.PG_CONNECTION_STRING, 13 | connectionTimeoutMillis: 1000, 14 | }); 15 | 16 | const streamClient = createClient(StarknetStream, process.env.APIBARA_URL, { 17 | defaultCallOptions: { 18 | "*": { 19 | metadata: Metadata({ 20 | Authorization: `Bearer ${process.env.DNA_TOKEN}`, 21 | }), 22 | }, 23 | }, 24 | }); 25 | 26 | // Timer for exiting if no blocks are received within the configured time 27 | const NO_BLOCKS_TIMEOUT_MS = parseInt(process.env.NO_BLOCKS_TIMEOUT_MS || "0"); 28 | let noBlocksTimer: NodeJS.Timeout | null = null; 29 | 30 | // Function to set or reset the no-blocks timer 31 | function resetNoBlocksTimer() { 32 | // Clear existing timer if it exists 33 | if (noBlocksTimer) { 34 | clearTimeout(noBlocksTimer); 35 | } 36 | 37 | // Only set a new timer if the timeout is greater than 0 38 | if (NO_BLOCKS_TIMEOUT_MS > 0) { 39 | noBlocksTimer = setTimeout(() => { 40 | logger.error( 41 | `No blocks received in the last ${msToHumanShort(NO_BLOCKS_TIMEOUT_MS)}. Exiting process.`, 42 | ); 43 | process.exit(1); 44 | }, NO_BLOCKS_TIMEOUT_MS); 45 | } 46 | } 47 | 48 | function msToHumanShort(ms: number): string { 49 | const units = [ 50 | { label: "d", ms: 86400000 }, 51 | { label: "h", ms: 3600000 }, 52 | { label: "min", ms: 60000 }, 53 | { label: "s", ms: 1000 }, 54 | { label: "ms", ms: 1 }, 55 | ]; 56 | 57 | const parts: string[] = []; 58 | 59 | for (const { label, ms: unitMs } of units) { 60 | if (ms >= unitMs) { 61 | const count = Math.floor(ms / unitMs); 62 | ms %= unitMs; 63 | parts.push(`${count}${label}`); 64 | if (parts.length === 3) break; // Limit to 2 components 65 | } 66 | } 67 | 68 | return parts.join(", ") || "0ms"; 69 | } 70 | 71 | const refreshAnalyticalTables = throttle( 72 | async function ( 73 | since: Date = new Date( 74 | Date.now() - parseInt(process.env.REFRESH_RATE_ANALYTICAL_VIEWS) * 2, 75 | ), 76 | ) { 77 | const timer = logger.startTimer(); 78 | logger.info("Started refreshing analytical tables", { 79 | start: timer.start, 80 | since: since.toISOString(), 81 | }); 82 | const client = await pool.connect(); 83 | const dao = new DAO(client); 84 | await dao.beginTransaction(); 85 | await dao.refreshAnalyticalTables({ 86 | since, 87 | }); 88 | await dao.commitTransaction(); 89 | client.release(); 90 | timer.done({ 91 | message: "Refreshed analytical tables", 92 | since: since.toISOString(), 93 | }); 94 | }, 95 | { 96 | delay: parseInt(process.env.REFRESH_RATE_ANALYTICAL_VIEWS), 97 | leading: true, 98 | async onError(err) { 99 | logger.error("Failed to refresh analytical tables", err); 100 | }, 101 | }, 102 | ); 103 | 104 | (async function () { 105 | // first set up the schema 106 | let databaseStartingCursor; 107 | { 108 | const client = await pool.connect(); 109 | const dao = new DAO(client); 110 | 111 | const initializeTimer = logger.startTimer(); 112 | databaseStartingCursor = await dao.initializeSchema(); 113 | initializeTimer.done({ 114 | message: "Initialized schema", 115 | startingCursor: databaseStartingCursor, 116 | }); 117 | client.release(); 118 | } 119 | 120 | refreshAnalyticalTables(new Date(0)); 121 | 122 | // Start the no-blocks timer when application starts 123 | resetNoBlocksTimer(); 124 | 125 | let lastIsHead: boolean = false; 126 | 127 | for await (const message of streamClient.streamData({ 128 | filter: [ 129 | { 130 | events: EVENT_PROCESSORS.map((ep, ix) => ({ 131 | id: ix + 1, 132 | address: ep.filter.fromAddress, 133 | keys: ep.filter.keys, 134 | })), 135 | }, 136 | ], 137 | finality: "pending", 138 | startingCursor: databaseStartingCursor 139 | ? databaseStartingCursor 140 | : { orderKey: BigInt(process.env.STARTING_CURSOR_BLOCK_NUMBER ?? 0) }, 141 | })) { 142 | switch (message._tag) { 143 | case "heartbeat": { 144 | logger.info(`Heartbeat`); 145 | 146 | // Note: We don't reset the no-blocks timer on heartbeats, only when actual blocks are received 147 | break; 148 | } 149 | 150 | case "systemMessage": { 151 | switch (message.systemMessage.output?._tag) { 152 | case "stderr": 153 | logger.error(`System message: ${message.systemMessage.output}`); 154 | break; 155 | case "stdout": 156 | logger.info(`System message: ${message.systemMessage.output}`); 157 | break; 158 | } 159 | break; 160 | } 161 | 162 | case "invalidate": { 163 | let invalidatedCursor = message.invalidate.cursor; 164 | 165 | if (invalidatedCursor) { 166 | logger.warn(`Invalidated cursor`, { 167 | cursor: invalidatedCursor, 168 | }); 169 | 170 | const client = await pool.connect(); 171 | const dao = new DAO(client); 172 | 173 | await dao.beginTransaction(); 174 | await dao.deleteOldBlockNumbers( 175 | Number(invalidatedCursor.orderKey) + 1, 176 | ); 177 | await dao.writeCursor(invalidatedCursor); 178 | await dao.commitTransaction(); 179 | 180 | client.release(); 181 | } 182 | 183 | break; 184 | } 185 | 186 | case "data": { 187 | // Reset the no-blocks timer since we received block data 188 | resetNoBlocksTimer(); 189 | 190 | const blockProcessingTimer = logger.startTimer(); 191 | 192 | const client = await pool.connect(); 193 | const dao = new DAO(client); 194 | 195 | await dao.beginTransaction(); 196 | 197 | let deletedCount: number = 0; 198 | 199 | let eventsProcessed: number = 0; 200 | const isHead = message.data.production === "live"; 201 | 202 | for (const block of message.data.data) { 203 | if (!block) continue; 204 | 205 | const blockNumber = Number(block.header.blockNumber); 206 | deletedCount += await dao.deleteOldBlockNumbers(blockNumber); 207 | 208 | const blockTime = block.header.timestamp; 209 | 210 | await dao.insertBlock({ 211 | hash: BigInt(block.header.blockHash ?? 0), 212 | number: block.header.blockNumber, 213 | time: blockTime, 214 | }); 215 | 216 | for (const event of block.events) { 217 | const eventKey: EventKey = { 218 | blockNumber, 219 | transactionIndex: event.transactionIndex, 220 | eventIndex: event.eventIndexInTransaction, 221 | emitter: BigInt(event.address), 222 | transactionHash: BigInt(event.transactionHash), 223 | }; 224 | 225 | // process each event sequentially through all the event processors in parallel 226 | // assumption is that none of the event processors operate on the same events, i.e. have the same filters 227 | // this assumption could be validated at runtime 228 | await Promise.all( 229 | event.filterIds.map(async (matchingFilterId) => { 230 | eventsProcessed++; 231 | const { parser, handle } = 232 | EVENT_PROCESSORS[matchingFilterId - 1]; 233 | const parsed = parser(event.data, 0).value; 234 | 235 | await handle(dao, { 236 | parsed: parsed as any, 237 | key: eventKey, 238 | }); 239 | }), 240 | ); 241 | } 242 | 243 | // endCursor is what we write so when we restart we delete any pending data 244 | if (message.data.finality !== 'pending') { 245 | await dao.writeCursor(message.data.endCursor); 246 | } 247 | 248 | const refreshOperational = 249 | (isHead && (eventsProcessed > 0 || !lastIsHead)) || 250 | deletedCount > 0; 251 | 252 | // refresh operational views at the end of the batch 253 | if (refreshOperational) { 254 | await dao.refreshOperationalMaterializedView(); 255 | } 256 | 257 | await dao.commitTransaction(); 258 | 259 | blockProcessingTimer.done({ 260 | message: `Processed to block`, 261 | blockNumber, 262 | isHead, 263 | refreshOperational, 264 | eventsProcessed, 265 | blockTimestamp: blockTime, 266 | lag: msToHumanShort( 267 | Math.floor(Date.now() - Number(blockTime.getTime())), 268 | ), 269 | }); 270 | } 271 | 272 | client.release(); 273 | 274 | if (isHead) { 275 | refreshAnalyticalTables(); 276 | } 277 | 278 | lastIsHead = isHead; 279 | 280 | break; 281 | } 282 | 283 | default: { 284 | logger.error(`Unhandled message type: ${message._tag}`); 285 | break; 286 | } 287 | } 288 | } 289 | })() 290 | .then(() => { 291 | logger.info("Stream closed gracefully"); 292 | process.exit(0); 293 | }) 294 | .catch((error) => { 295 | logger.error(error); 296 | process.exit(1); 297 | }); 298 | -------------------------------------------------------------------------------- /src/logger.ts: -------------------------------------------------------------------------------- 1 | import { createLogger, format, transports } from "winston"; 2 | 3 | export const logger = createLogger({ 4 | level: process.env.LOG_LEVEL ?? "info", 5 | format: format.combine( 6 | format.timestamp({ 7 | format: "YYYY-MM-DD HH:mm:ss", 8 | }), 9 | format.errors({ stack: true }), 10 | format.splat(), 11 | format.json(), 12 | ), 13 | defaultMeta: { service: "ekubo-indexer" }, 14 | transports: [new transports.Console()], 15 | }); 16 | 17 | process.on("uncaughtException", function (err) { 18 | logger.error("Uncaught exception", err); 19 | process.exit(1); // Exit the process with failure 20 | }); 21 | 22 | process.on("unhandledRejection", function (err) { 23 | logger.error("Unhandled promise rejection", err); 24 | process.exit(1); // Exit the process with failure 25 | }); 26 | -------------------------------------------------------------------------------- /src/parse.test.ts: -------------------------------------------------------------------------------- 1 | import { parsePoolKey } from "./events/core"; 2 | import { describe, expect, it } from "vitest"; 3 | import { parseByteArray, parseUint8Array } from "./parse"; 4 | 5 | describe("parse", () => { 6 | describe(parsePoolKey, () => { 7 | it("works correctly for random data from 0", () => { 8 | const result = parsePoolKey( 9 | ["0x5", "0x4", "0x3", "0x2", "0x1", "0x0"], 10 | 0, 11 | ); 12 | 13 | expect(result).toEqual({ 14 | next: 5, 15 | value: { 16 | token0: 5n, 17 | token1: 4n, 18 | fee: 0x3n, 19 | tick_spacing: 0x2n, 20 | extension: 1n, 21 | }, 22 | }); 23 | }); 24 | 25 | it("works correctly for random data from random place", () => { 26 | const result = parsePoolKey( 27 | ["0x5", "0x4", "0x3", "0x2", "0x1", "0x2", "0x3", "0x4"], 28 | 3, 29 | ); 30 | 31 | expect(result).toEqual({ 32 | next: 8, 33 | value: { 34 | token0: 2n, 35 | token1: 1n, 36 | fee: 0x2n, 37 | tick_spacing: 0x3n, 38 | extension: 4n, 39 | }, 40 | }); 41 | }); 42 | }); 43 | 44 | describe(parseUint8Array, () => { 45 | it.each([ 46 | { 47 | args: { 48 | data: [0x68656c6c6f20776f726c64n], 49 | startingFrom: 0, 50 | }, 51 | expected: { 52 | value: "hello world", 53 | next: 1, 54 | }, 55 | }, 56 | { 57 | args: { 58 | data: [0x0], 59 | startingFrom: 0, 60 | }, 61 | expected: { 62 | value: "", 63 | next: 1, 64 | }, 65 | }, 66 | { 67 | args: { 68 | data: [0x0, 0x68656c6c6f20776f726c64n], 69 | startingFrom: 1, 70 | }, 71 | expected: { 72 | value: "hello world", 73 | next: 2, 74 | }, 75 | }, 76 | ])( 77 | `parseUint8Array($args.data, $args.startingFrom) = $expected.value`, 78 | ({ args: { data, startingFrom }, expected }) => { 79 | expect( 80 | parseUint8Array( 81 | data.map((x) => `0x${x.toString(16)}`) as readonly `0x${string}`[], 82 | startingFrom, 83 | ), 84 | ).toEqual({ 85 | value: new TextEncoder().encode(expected.value), 86 | next: expected.next, 87 | }); 88 | }, 89 | ); 90 | }); 91 | 92 | describe(parseByteArray, () => { 93 | it.each([ 94 | { 95 | data: [0n, 0x68656c6c6fn, 5n], 96 | startingFrom: 0, 97 | expected: { next: 3, value: "hello" }, 98 | }, 99 | { 100 | data: [123n, 0n, 0x68656c6c6fn, 5n], 101 | startingFrom: 1, 102 | expected: { next: 4, value: "hello" }, 103 | }, 104 | { 105 | data: [ 106 | 1n, 107 | 0x4c6f6e6720737472696e672c206d6f7265207468616e203331206368617261n, 108 | 0x63746572732en, 109 | 6n, 110 | ], 111 | startingFrom: 0, 112 | expected: { next: 4, value: "Long string, more than 31 characters." }, 113 | }, 114 | { 115 | data: [ 116 | 0n, 117 | 1n, 118 | 0x4c6f6e6720737472696e672c206d6f7265207468616e203331206368617261n, 119 | 0x63746572732en, 120 | 6n, 121 | 0n, 122 | ], 123 | startingFrom: 1, 124 | expected: { next: 5, value: "Long string, more than 31 characters." }, 125 | }, 126 | { 127 | data: [ 128 | 0x25a6c62b25db639c2a0fb26678f1ac2870e5fe8b22d3bd3eec09691d6755d8fn, 129 | 0x2n, 130 | 0x2320746573742070726f706f73616c206465736372697074696f6e0a0a6865n, 131 | 0x6c6c6f20776f726c640a0a6060600a636f64650a6060600a0a232320746573n, 132 | 0x740a0a6e6f74207265616c6c79n, 133 | 0x0dn, 134 | ], 135 | startingFrom: 1, 136 | expected: { 137 | next: 6, 138 | value: `# test proposal description 139 | 140 | hello world 141 | 142 | \`\`\` 143 | code 144 | \`\`\` 145 | 146 | ## test 147 | 148 | not really`, 149 | }, 150 | }, 151 | ])( 152 | "parseByteArray($data) = $expected", 153 | ({ data, startingFrom, expected }) => { 154 | expect( 155 | parseByteArray( 156 | data.map((x) => `0x${x.toString(16)}`) as readonly `0x${string}`[], 157 | startingFrom, 158 | ), 159 | ).toEqual(expected); 160 | }, 161 | ); 162 | }); 163 | }); 164 | -------------------------------------------------------------------------------- /src/parse.ts: -------------------------------------------------------------------------------- 1 | export interface Parser { 2 | ( 3 | data: readonly `0x${string}`[], 4 | startingFrom: number, 5 | ): { 6 | value: T; 7 | next: number; 8 | }; 9 | } 10 | 11 | export function parseSpanOf(type: Parser): Parser { 12 | return (data, startingFrom) => { 13 | const numElements = Number(data[startingFrom]); 14 | 15 | const elements: T[] = []; 16 | let index = startingFrom + 1; 17 | 18 | while (elements.length < numElements) { 19 | const { value, next } = type(data, index); 20 | index = next; 21 | elements.push(value); 22 | } 23 | 24 | return { 25 | value: elements, 26 | next: index, 27 | }; 28 | }; 29 | } 30 | 31 | export const parseU128: Parser = (data, startingFrom) => { 32 | return { 33 | value: BigInt(data[startingFrom]), 34 | next: startingFrom + 1, 35 | }; 36 | }; 37 | 38 | export const parseU64 = parseU128; 39 | 40 | export const parseU256: Parser = (data, startingFrom) => { 41 | return { 42 | value: 43 | BigInt(data[startingFrom]) + BigInt(data[startingFrom + 1]) * 2n ** 128n, 44 | next: startingFrom + 2, 45 | }; 46 | }; 47 | 48 | export const parseI129: Parser = (data, startingFrom) => { 49 | return { 50 | value: 51 | BigInt(data[startingFrom]) * 52 | (BigInt(data[startingFrom + 1]) !== 0n ? -1n : 1n), 53 | next: startingFrom + 2, 54 | }; 55 | }; 56 | 57 | export type GetParserType> = 58 | T extends Parser ? U : never; 59 | 60 | export const parseU8: Parser = (data, startingFrom) => { 61 | return { 62 | value: Number(data[startingFrom]), 63 | next: startingFrom + 1, 64 | }; 65 | }; 66 | 67 | export const parseFelt252: Parser = (data, startingFrom) => { 68 | return { 69 | value: BigInt(data[startingFrom]), 70 | next: startingFrom + 1, 71 | }; 72 | }; 73 | 74 | export const parseAddress: Parser = parseFelt252; 75 | 76 | export const parseBoolean: Parser = (data, startingFrom) => { 77 | let num = BigInt(data[startingFrom]); 78 | let value: boolean; 79 | if (num === 0n) { 80 | value = false; 81 | } else { 82 | if (num === 1n) { 83 | value = true; 84 | } else { 85 | throw new Error("Invalid boolean value"); 86 | } 87 | } 88 | return { 89 | value, 90 | next: startingFrom + 1, 91 | }; 92 | }; 93 | 94 | /** 95 | * Returns a parser that will only run if there is additional data in the event to be parsed 96 | * @param parser the parser that it will run if there is additional data 97 | */ 98 | export function backwardsCompatibleParserAdditionalArgument( 99 | parser: Parser, 100 | ): Parser { 101 | return (data, startingFrom) => { 102 | if (startingFrom < data.length) { 103 | return parser(data, startingFrom); 104 | } 105 | return { value: null, next: startingFrom }; 106 | }; 107 | } 108 | 109 | export function combineParsers< 110 | T extends { 111 | [key: string]: unknown; 112 | }, 113 | >(parsers: { 114 | [K in keyof T]: { index: number; parser: Parser }; 115 | }): Parser { 116 | return (data, startingFrom) => 117 | Object.entries(parsers) 118 | .sort(([, { index: index0 }], [, { index: index1 }]) => { 119 | return index0 - index1; 120 | }) 121 | .reduce( 122 | (memo, fieldParser) => { 123 | const { value: parsedValue, next } = fieldParser[1].parser( 124 | data, 125 | memo.next, 126 | ); 127 | memo.value[fieldParser[0] as keyof T] = parsedValue; 128 | memo.next = next; 129 | return memo; 130 | }, 131 | { 132 | value: {} as Partial, 133 | next: startingFrom, 134 | }, 135 | ) as { 136 | value: T; 137 | next: number; 138 | }; 139 | } 140 | 141 | export const parseUint8Array: Parser = (data, startingFrom) => { 142 | const { next, value } = parseFelt252(data, startingFrom); 143 | 144 | const result: number[] = []; 145 | for (let i = 0; i < 31; i++) { 146 | const position = BigInt(i * 8); 147 | const byte = (value & (255n << position)) >> position; 148 | if (byte === 0n) { 149 | break; 150 | } 151 | result.unshift(Number(byte)); 152 | } 153 | 154 | return { 155 | value: new Uint8Array(result), 156 | next, 157 | }; 158 | }; 159 | 160 | const parseByteArrayWords = parseSpanOf(parseUint8Array); 161 | 162 | export const parseByteArray: Parser = (data, startingFrom) => { 163 | const words = parseByteArrayWords(data, startingFrom); 164 | 165 | const value = new TextDecoder().decode( 166 | new Uint8Array( 167 | Buffer.concat([ 168 | ...words.value, 169 | // pending word 170 | parseUint8Array(data, words.next).value, 171 | ]), 172 | ), 173 | ); 174 | 175 | return { 176 | // pending word length is not used 177 | next: words.next + 2, 178 | value, 179 | }; 180 | }; 181 | -------------------------------------------------------------------------------- /src/poolKeyHash.ts: -------------------------------------------------------------------------------- 1 | import type { PoolKey } from "./events/core"; 2 | import { createHash } from "crypto"; 3 | 4 | export function computeKeyHash(pool_key: PoolKey): bigint { 5 | return BigInt( 6 | `0x${createHash("sha256") 7 | .update(pool_key.token0.toString(16).padStart(64, "0"), "hex") 8 | .update(pool_key.token1.toString(16).padStart(64, "0"), "hex") 9 | .update(pool_key.fee.toString(16).padStart(32, "0"), "hex") 10 | .update(pool_key.tick_spacing.toString(16).padStart(32, "0"), "hex") 11 | .update(pool_key.extension.toString(16).padStart(64, "0"), "hex") 12 | .digest("hex")}`, 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/processor.ts: -------------------------------------------------------------------------------- 1 | import type { Parser } from "./parse"; 2 | import { DAO } from "./dao"; 3 | 4 | export interface EventKey { 5 | blockNumber: number; 6 | transactionIndex: number; 7 | eventIndex: number; 8 | emitter: bigint; 9 | transactionHash: bigint; 10 | } 11 | 12 | export interface ParsedEventWithKey { 13 | key: EventKey; 14 | parsed: T; 15 | } 16 | 17 | export interface EventProcessor { 18 | filter: { 19 | keys: `0x${string}`[]; 20 | fromAddress: `0x${string}`; 21 | }; 22 | 23 | parser: Parser; 24 | 25 | handle(dao: DAO, result: ParsedEventWithKey): Promise; 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": ["ESNext"], 5 | "target": "ESNext", 6 | "module": "ESNext", 7 | "moduleDetection": "force", 8 | "jsx": "react-jsx", 9 | "allowJs": true, 10 | 11 | // Bundler mode 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "verbatimModuleSyntax": true, 15 | "noEmit": true, 16 | 17 | // Best practices 18 | "strict": true, 19 | "skipLibCheck": true, 20 | "noFallthroughCasesInSwitch": true, 21 | 22 | // Some stricter flags 23 | "noUnusedLocals": true, 24 | "noUnusedParameters": true, 25 | "noPropertyAccessFromIndexSignature": true 26 | } 27 | } 28 | --------------------------------------------------------------------------------