diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f936df177..1ca4a56f2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -494,7 +494,7 @@ importers: version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))(turbo@2.4.4)(typescript@5.8.2) '@cprussin/jest-config': specifier: 'catalog:' - version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3) + version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(esbuild@0.25.2)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3) '@cprussin/prettier-config': specifier: 'catalog:' version: 2.2.2(prettier@3.5.3) @@ -567,7 +567,7 @@ importers: version: 8.56.0 jest: specifier: ^29.4.0 - version: 29.7.0(@types/node@20.17.30) + version: 29.7.0(@types/node@20.17.30)(ts-node@10.9.2(@types/node@20.17.30)(typescript@5.8.2)) openapi-zod-client: specifier: ^1.18.1 version: 1.18.3(react@19.1.0) @@ -576,7 +576,7 @@ importers: version: 3.5.3 ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.30))(typescript@5.8.2) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.30)(ts-node@10.9.2(@types/node@20.17.30)(typescript@5.8.2)))(typescript@5.8.2) typescript: specifier: 'catalog:' version: 5.8.2 @@ -664,10 +664,10 @@ importers: devDependencies: '@cprussin/eslint-config': specifier: 'catalog:' - version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(turbo@2.4.4)(typescript@5.8.2) + version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))(turbo@2.4.4)(typescript@5.8.2) '@cprussin/jest-config': specifier: 'catalog:' - version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@5.0.10) + version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@5.0.10) '@cprussin/prettier-config': specifier: 'catalog:' version: 2.2.2(prettier@3.5.3) @@ -700,7 +700,7 @@ importers: version: 9.23.0(jiti@1.21.7) jest: specifier: 'catalog:' - version: 29.7.0(@types/node@22.14.0) + version: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) postcss: specifier: 'catalog:' version: 8.5.3 @@ -839,7 +839,7 @@ importers: version: 8.56.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + version: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) pino-pretty: specifier: ^11.2.1 version: 11.3.0 @@ -848,10 +848,10 @@ importers: version: 3.5.3 ts-jest: specifier: ^29.1.1 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.24.2)(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.24.2)(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2) ts-node: specifier: 'catalog:' - version: 10.9.2(@types/node@18.19.86)(typescript@5.8.2) + version: 10.9.2(@types/node@22.14.0)(typescript@5.8.2) typescript: specifier: 'catalog:' version: 5.8.2 @@ -893,13 +893,13 @@ importers: version: 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-react': specifier: 'catalog:' - version: 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) + version: 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/wallet-adapter-react-ui': specifier: 'catalog:' - version: 0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) + version: 0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/wallet-adapter-wallets': specifier: 'catalog:' - version: 0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) + version: 0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) '@solana/web3.js': specifier: 'catalog:' version: 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -1187,10 +1187,10 @@ importers: devDependencies: '@cprussin/eslint-config': specifier: 'catalog:' - version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(turbo@2.4.4)(typescript@5.8.2) + version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))(turbo@2.4.4)(typescript@5.8.2) '@cprussin/jest-config': specifier: 'catalog:' - version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@5.0.10) + version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@5.0.10) '@cprussin/prettier-config': specifier: 'catalog:' version: 2.2.2(prettier@3.5.3) @@ -1211,7 +1211,7 @@ importers: version: 9.23.0(jiti@1.21.7) jest: specifier: 'catalog:' - version: 29.7.0(@types/node@22.14.0) + version: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) prettier: specifier: 'catalog:' version: 3.5.3 @@ -1434,13 +1434,13 @@ importers: version: 3.23.2 jest: specifier: ^29.3.1 - version: 29.7.0(@types/node@22.14.0) + version: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) prettier: specifier: 'catalog:' version: 3.5.3 ts-jest: specifier: ^29.0.3 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0))(typescript@4.9.5) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)))(typescript@4.9.5) governance/xc_admin/packages/xc_admin_frontend: dependencies: @@ -1476,10 +1476,10 @@ importers: version: 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/wallet-adapter-react-ui': specifier: 'catalog:' - version: 0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) + version: 0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/wallet-adapter-wallets': specifier: 'catalog:' - version: 0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) + version: 0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2) '@solana/web3.js': specifier: ^1.73.0 version: 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -1714,10 +1714,10 @@ importers: devDependencies: '@cprussin/eslint-config': specifier: 'catalog:' - version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(turbo@2.4.4)(typescript@5.8.2) + version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))(turbo@2.4.4)(typescript@5.8.2) '@cprussin/jest-config': specifier: 'catalog:' - version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(esbuild@0.25.2)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3) + version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(esbuild@0.25.2)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3) '@cprussin/prettier-config': specifier: 'catalog:' version: 2.2.2(prettier@3.5.3) @@ -1768,7 +1768,7 @@ importers: version: 9.23.0(jiti@1.21.7) jest: specifier: 'catalog:' - version: 29.7.0(@types/node@22.14.0) + version: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) next: specifier: 'catalog:' version: 15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1) @@ -1810,10 +1810,10 @@ importers: devDependencies: '@cprussin/eslint-config': specifier: 'catalog:' - version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(turbo@2.4.4)(typescript@5.8.2) + version: 4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))(turbo@2.4.4)(typescript@5.8.2) '@cprussin/jest-config': specifier: 'catalog:' - version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(esbuild@0.25.2)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3) + version: 2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(esbuild@0.25.2)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3) '@cprussin/prettier-config': specifier: 'catalog:' version: 2.2.2(prettier@3.5.3) @@ -1831,7 +1831,7 @@ importers: version: 9.23.0(jiti@1.21.7) jest: specifier: 'catalog:' - version: 29.7.0(@types/node@22.14.0) + version: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) prettier: specifier: 'catalog:' version: 3.5.3 @@ -1883,13 +1883,13 @@ importers: version: 8.56.0 jest: specifier: ^29.4.0 - version: 29.7.0(@types/node@22.14.0) + version: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) prettier: specifier: 'catalog:' version: 3.5.3 ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0))(typescript@4.9.5) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)))(typescript@4.9.5) typescript: specifier: ^4.6.3 version: 4.9.5 @@ -1920,7 +1920,7 @@ importers: version: 8.56.0 jest: specifier: ^29.4.0 - version: 29.7.0(@types/node@16.18.126) + version: 29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) prettier: specifier: 'catalog:' version: 3.5.3 @@ -1929,7 +1929,7 @@ importers: version: 23.0.171(encoding@0.1.13) ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@16.18.126))(typescript@4.9.5) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)))(typescript@4.9.5) typescript: specifier: ^4.6.3 version: 4.9.5 @@ -2049,13 +2049,13 @@ importers: version: 8.56.0 jest: specifier: ^29.4.1 - version: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + version: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) prettier: specifier: 'catalog:' version: 3.5.3 ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86))(typescript@4.9.5) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)))(typescript@4.9.5) typescript: specifier: ^4.6.3 version: 4.9.5 @@ -2244,6 +2244,9 @@ importers: '@pythnetwork/entropy-sdk-solidity': specifier: workspace:* version: link:../entropy_sdk/solidity + '@pythnetwork/pulse-sdk-solidity': + specifier: workspace:* + version: link:../pulse_sdk/solidity '@pythnetwork/pyth-sdk-solidity': specifier: workspace:* version: link:../sdk/solidity @@ -2348,6 +2351,22 @@ importers: specifier: 'catalog:' version: 1.4.2(prettier@3.5.3) + target_chains/ethereum/pulse_sdk/solidity: + dependencies: + '@pythnetwork/pyth-sdk-solidity': + specifier: workspace:* + version: link:../../sdk/solidity + devDependencies: + abi_generator: + specifier: workspace:* + version: link:../../abi_generator + prettier: + specifier: 'catalog:' + version: 3.5.3 + prettier-plugin-solidity: + specifier: 'catalog:' + version: 1.4.2(prettier@3.5.3) + target_chains/ethereum/sdk/js: dependencies: '@pythnetwork/price-service-client': @@ -2389,13 +2408,13 @@ importers: version: 8.56.0 jest: specifier: ^29.4.1 - version: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + version: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) prettier: specifier: 'catalog:' version: 3.5.3 ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86))(typescript@4.9.5) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)))(typescript@4.9.5) typescript: specifier: ^4.6.3 version: 4.9.5 @@ -2509,7 +2528,7 @@ importers: version: 23.0.171(encoding@0.1.13) ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.25.2)(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2) ts-node: specifier: 'catalog:' version: 10.9.2(@types/node@22.14.0)(typescript@5.8.2) @@ -2552,7 +2571,7 @@ importers: version: 8.56.0 jest: specifier: ^29.4.0 - version: 29.7.0(@types/node@22.14.0) + version: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) prettier: specifier: 'catalog:' version: 3.5.3 @@ -2561,7 +2580,7 @@ importers: version: 23.0.171(encoding@0.1.13) ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0))(typescript@4.9.5) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)))(typescript@4.9.5) typescript: specifier: ^4.6.3 version: 4.9.5 @@ -2588,7 +2607,7 @@ importers: version: 3.5.3 ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.24.2)(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2) ts-node: specifier: 'catalog:' version: 10.9.2(@types/node@18.19.86)(typescript@5.8.2) @@ -2717,7 +2736,7 @@ importers: version: 3.5.3 ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86))(typescript@5.8.2) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2) typescript: specifier: ^5.3.3 version: 5.8.2 @@ -2775,7 +2794,7 @@ importers: version: 3.5.3 ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86))(typescript@5.8.2) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2) typescript: specifier: ^5.3.3 version: 5.8.2 @@ -2874,7 +2893,7 @@ importers: version: 3.5.3 ts-jest: specifier: ^29.0.5 - version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.24.2)(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2) ts-node: specifier: 'catalog:' version: 10.9.2(@types/node@18.19.86)(typescript@5.8.2) @@ -23746,7 +23765,7 @@ snapshots: eslint-plugin-react: 7.37.4(eslint@9.23.0(jiti@1.21.7)) eslint-plugin-react-hooks: 5.2.0(eslint@9.23.0(jiti@1.21.7)) eslint-plugin-storybook: 0.11.6(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2) - eslint-plugin-tailwindcss: 3.18.0(tailwindcss@3.4.17) + eslint-plugin-tailwindcss: 3.18.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2))) eslint-plugin-testing-library: 7.1.1(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2) eslint-plugin-tsdoc: 0.4.0 eslint-plugin-unicorn: 57.0.0(eslint@9.23.0(jiti@1.21.7)) @@ -23803,78 +23822,15 @@ snapshots: - turbo - typescript - '@cprussin/eslint-config@4.0.2(@testing-library/dom@10.4.0)(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(turbo@2.4.4)(typescript@5.8.2)': - dependencies: - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.23.0 - '@next/eslint-plugin-next': 15.2.4 - eslint: 9.23.0(jiti@1.21.7) - eslint-config-prettier: 10.1.1(eslint@9.23.0(jiti@1.21.7)) - eslint-config-turbo: 2.4.4(eslint@9.23.0(jiti@1.21.7))(turbo@2.4.4) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7)) - eslint-plugin-jest: 28.11.0(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2) - eslint-plugin-jest-dom: 5.5.0(@testing-library/dom@10.4.0)(eslint@9.23.0(jiti@1.21.7)) - eslint-plugin-jsonc: 2.20.0(eslint@9.23.0(jiti@1.21.7)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.23.0(jiti@1.21.7)) - eslint-plugin-n: 17.17.0(eslint@9.23.0(jiti@1.21.7)) - eslint-plugin-react: 7.37.4(eslint@9.23.0(jiti@1.21.7)) - eslint-plugin-react-hooks: 5.2.0(eslint@9.23.0(jiti@1.21.7)) - eslint-plugin-storybook: 0.11.6(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2) - eslint-plugin-tailwindcss: 3.18.0(tailwindcss@3.4.17) - eslint-plugin-testing-library: 7.1.1(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2) - eslint-plugin-tsdoc: 0.4.0 - eslint-plugin-unicorn: 57.0.0(eslint@9.23.0(jiti@1.21.7)) - globals: 16.0.0 - tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) - typescript-eslint: 8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2) - transitivePeerDependencies: - - '@eslint/json' - - '@testing-library/dom' - - '@typescript-eslint/eslint-plugin' - - '@typescript-eslint/parser' - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - jest - - supports-color - - ts-node - - turbo - - typescript - - '@cprussin/jest-config@2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(esbuild@0.25.2)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3)': - dependencies: - '@cprussin/jest-runner-eslint': 0.0.1(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)) - '@cprussin/jest-runner-prettier': 1.0.0(jest@29.7.0(@types/node@22.14.0))(prettier@3.5.3) - '@testing-library/jest-dom': 6.6.3 - jest: 29.7.0(@types/node@22.14.0) - jest-environment-jsdom: 29.7.0(bufferutil@4.0.9)(utf-8-validate@6.0.3) - prettier: 3.5.3 - ts-jest: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.25.2)(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2) - typescript: 5.8.2 - optionalDependencies: - next: 15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1) - transitivePeerDependencies: - - '@babel/core' - - '@jest/test-result' - - '@jest/transform' - - '@jest/types' - - babel-jest - - bufferutil - - canvas - - esbuild - - eslint - - jest-runner - - supports-color - - utf-8-validate - - '@cprussin/jest-config@2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@5.0.10)': + '@cprussin/jest-config@2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(esbuild@0.25.2)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3)': dependencies: '@cprussin/jest-runner-eslint': 0.0.1(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))) '@cprussin/jest-runner-prettier': 1.0.0(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(prettier@3.5.3) '@testing-library/jest-dom': 6.6.3 jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) - jest-environment-jsdom: 29.7.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + jest-environment-jsdom: 29.7.0(bufferutil@4.0.9)(utf-8-validate@6.0.3) prettier: 3.5.3 - ts-jest: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2) + ts-jest: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.25.2)(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2) typescript: 5.8.2 optionalDependencies: next: 15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1) @@ -23892,41 +23848,15 @@ snapshots: - supports-color - utf-8-validate - '@cprussin/jest-config@2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@6.0.3)': + '@cprussin/jest-config@2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@5.0.10)': dependencies: '@cprussin/jest-runner-eslint': 0.0.1(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))) '@cprussin/jest-runner-prettier': 1.0.0(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(prettier@3.5.3) '@testing-library/jest-dom': 6.6.3 jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) - jest-environment-jsdom: 29.7.0(bufferutil@4.0.9)(utf-8-validate@6.0.3) - prettier: 3.5.3 - ts-jest: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2) - typescript: 5.8.2 - optionalDependencies: - next: 15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1) - transitivePeerDependencies: - - '@babel/core' - - '@jest/test-result' - - '@jest/transform' - - '@jest/types' - - babel-jest - - bufferutil - - canvas - - esbuild - - eslint - - jest-runner - - supports-color - - utf-8-validate - - '@cprussin/jest-config@2.0.2(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(bufferutil@4.0.9)(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(next@15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1))(prettier@3.5.3)(typescript@5.8.2)(utf-8-validate@5.0.10)': - dependencies: - '@cprussin/jest-runner-eslint': 0.0.1(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0)) - '@cprussin/jest-runner-prettier': 1.0.0(jest@29.7.0(@types/node@22.14.0))(prettier@3.5.3) - '@testing-library/jest-dom': 6.6.3 - jest: 29.7.0(@types/node@22.14.0) jest-environment-jsdom: 29.7.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) prettier: 3.5.3 - ts-jest: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.25.2)(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2) + ts-jest: 29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.25.2)(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2) typescript: 5.8.2 optionalDependencies: next: 15.3.1(@babel/core@7.26.10)(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(sass@1.86.1) @@ -23956,18 +23886,6 @@ snapshots: - '@jest/test-result' - jest-runner - '@cprussin/jest-runner-eslint@0.0.1(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))': - dependencies: - chalk: 4.1.2 - cosmiconfig: 7.1.0 - create-jest-runner: 0.11.2 - dot-prop: 6.0.1 - eslint: 9.23.0(jiti@1.21.7) - jest: 29.7.0(@types/node@22.14.0) - transitivePeerDependencies: - - '@jest/test-result' - - jest-runner - '@cprussin/jest-runner-prettier@1.0.0(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(prettier@3.5.3)': dependencies: create-lite-jest-runner: 1.1.2(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))) @@ -23976,14 +23894,6 @@ snapshots: jest-diff: 29.7.0 prettier: 3.5.3 - '@cprussin/jest-runner-prettier@1.0.0(jest@29.7.0(@types/node@22.14.0))(prettier@3.5.3)': - dependencies: - create-lite-jest-runner: 1.1.2(jest@29.7.0(@types/node@22.14.0)) - emphasize: 5.0.0 - jest: 29.7.0(@types/node@22.14.0) - jest-diff: 29.7.0 - prettier: 3.5.3 - '@cprussin/prettier-config@2.2.2(prettier@3.5.3)': dependencies: prettier: 3.5.3 @@ -26275,6 +26185,76 @@ snapshots: jest-util: 29.7.0 slash: 3.0.0 + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.86 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.86 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2))': dependencies: '@jest/console': 29.7.0 @@ -26345,6 +26325,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 18.19.86 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))': dependencies: '@jest/console': 29.7.0 @@ -28211,11 +28226,11 @@ snapshots: crypto-js: 4.2.0 uuidv4: 6.2.13 - '@particle-network/solana-wallet@1.3.2(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)': + '@particle-network/solana-wallet@1.3.2(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)': dependencies: '@particle-network/auth': 1.3.1 '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - bs58: 6.0.0 + bs58: 5.0.0 '@paulmillr/qr@0.2.1': {} @@ -31500,7 +31515,16 @@ snapshots: '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/wallet-adapter-base-ui@0.1.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)': + '@solana/wallet-adapter-base-ui@0.1.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)': + dependencies: + '@solana/wallet-adapter-react': 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) + '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + react: 19.1.0 + transitivePeerDependencies: + - bs58 + - react-native + + '@solana/wallet-adapter-base-ui@0.1.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)': dependencies: '@solana/wallet-adapter-react': 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) @@ -31618,9 +31642,9 @@ snapshots: '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/wallet-adapter-particle@0.1.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)': + '@solana/wallet-adapter-particle@0.1.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)': dependencies: - '@particle-network/solana-wallet': 1.3.2(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0) + '@particle-network/solana-wallet': 1.3.2(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0) '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -31631,10 +31655,22 @@ snapshots: '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@solana/wallet-adapter-react-ui@0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)': + '@solana/wallet-adapter-react-ui@0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)': + dependencies: + '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) + '@solana/wallet-adapter-base-ui': 0.1.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) + '@solana/wallet-adapter-react': 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) + '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + transitivePeerDependencies: + - bs58 + - react-native + + '@solana/wallet-adapter-react-ui@0.9.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)': dependencies: '@solana/wallet-adapter-base': 0.9.24(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) - '@solana/wallet-adapter-base-ui': 0.1.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) + '@solana/wallet-adapter-base-ui': 0.1.3(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/wallet-adapter-react': 0.15.36(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0) '@solana/web3.js': 1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) react: 19.1.0 @@ -31794,7 +31830,7 @@ snapshots: - utf-8-validate - zod - '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)': + '@solana/wallet-adapter-wallets@0.19.33(@babel/runtime@7.27.0)(@react-native-async-storage/async-storage@1.24.0(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10)))(@solana/sysvars@2.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.2))(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.1.0(react@19.1.0))(react-native@0.78.2(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@types/react@19.1.0)(bufferutil@4.0.9)(react@19.1.0)(utf-8-validate@5.0.10))(react@19.1.0)(tslib@2.8.1)(typescript@5.8.2)(utf-8-validate@5.0.10)(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.24.2)': dependencies: '@solana/wallet-adapter-alpha': 0.1.11(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-avana': 0.1.14(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) @@ -31815,7 +31851,7 @@ snapshots: '@solana/wallet-adapter-nightly': 0.1.17(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-nufi': 0.1.18(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-onto': 0.1.8(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) - '@solana/wallet-adapter-particle': 0.1.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@6.0.0) + '@solana/wallet-adapter-particle': 0.1.13(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10))(bs58@5.0.0) '@solana/wallet-adapter-phantom': 0.9.25(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-safepal': 0.5.19(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) '@solana/wallet-adapter-saifu': 0.1.16(@solana/web3.js@1.98.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)) @@ -37381,13 +37417,28 @@ snapshots: jest-worker: 28.1.3 throat: 6.0.2 - create-jest@29.7.0(@types/node@16.18.126): + create-jest@29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + create-jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@16.18.126) + jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -37426,6 +37477,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)): dependencies: '@jest/types': 29.6.3 @@ -37446,11 +37512,6 @@ snapshots: jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) p-limit: 6.2.0 - create-lite-jest-runner@1.1.2(jest@29.7.0(@types/node@22.14.0)): - dependencies: - jest: 29.7.0(@types/node@22.14.0) - p-limit: 6.2.0 - create-require@1.1.1: {} cross-fetch@2.2.6(encoding@0.1.13): @@ -38560,7 +38621,7 @@ snapshots: '@typescript-eslint/parser': 5.62.0(eslint@8.56.0)(typescript@5.8.2) eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.56.0) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint@8.56.0))(eslint@8.56.0) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint-import-resolver-typescript@3.10.0)(eslint@8.56.0) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.56.0) eslint-plugin-react: 7.37.4(eslint@8.56.0) @@ -38594,7 +38655,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0)(eslint@8.56.0): + eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint@8.56.0))(eslint@8.56.0): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.0(supports-color@8.1.1) @@ -38615,14 +38676,14 @@ snapshots: esquery: 1.6.0 jsonc-eslint-parser: 2.4.0 - eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.56.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 5.62.0(eslint@8.56.0)(typescript@5.8.2) eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0)(eslint@8.56.0) + eslint-import-resolver-typescript: 3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint@8.56.0))(eslint@8.56.0) transitivePeerDependencies: - supports-color @@ -38654,7 +38715,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.56.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0)(eslint@8.56.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.56.0)(typescript@5.8.2))(eslint@8.56.0))(eslint@8.56.0))(eslint@8.56.0) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -38731,17 +38792,6 @@ snapshots: - supports-color - typescript - eslint-plugin-jest@28.11.0(@typescript-eslint/eslint-plugin@8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2): - dependencies: - '@typescript-eslint/utils': 8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2) - eslint: 9.23.0(jiti@1.21.7) - optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.29.0(@typescript-eslint/parser@8.29.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2) - jest: 29.7.0(@types/node@22.14.0) - transitivePeerDependencies: - - supports-color - - typescript - eslint-plugin-jsonc@2.20.0(eslint@9.23.0(jiti@1.21.7)): dependencies: '@eslint-community/eslint-utils': 4.5.1(eslint@9.23.0(jiti@1.21.7)) @@ -38868,17 +38918,17 @@ snapshots: - supports-color - typescript - eslint-plugin-tailwindcss@3.18.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))): + eslint-plugin-tailwindcss@3.18.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2))): dependencies: fast-glob: 3.3.3 postcss: 8.5.3 - tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) - eslint-plugin-tailwindcss@3.18.0(tailwindcss@3.4.17): + eslint-plugin-tailwindcss@3.18.0(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2))): dependencies: fast-glob: 3.3.3 postcss: 8.5.3 - tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) eslint-plugin-testing-library@7.1.1(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2): dependencies: @@ -41587,16 +41637,16 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@16.18.126): + jest-cli@29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@16.18.126) + create-jest: 29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@16.18.126) + jest-config: 29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -41606,16 +41656,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)): + jest-cli@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + create-jest: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -41625,16 +41675,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.17.30): + jest-cli@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.30)(ts-node@10.9.2(@types/node@20.17.30)(typescript@5.8.2)) + create-jest: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.30)(ts-node@10.9.2(@types/node@20.17.30)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -41663,16 +41713,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.14.0): + jest-cli@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) + create-jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -41701,7 +41751,7 @@ snapshots: - supports-color - ts-node - jest-config@29.7.0(@types/node@16.18.126): + jest-config@29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)): dependencies: '@babel/core': 7.26.10 '@jest/test-sequencer': 29.7.0 @@ -41727,6 +41777,69 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 16.18.126 + ts-node: 10.9.2(@types/node@16.18.126)(typescript@4.9.5) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)): + dependencies: + '@babel/core': 7.26.10 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 18.19.86 + ts-node: 10.9.2(@types/node@16.18.126)(typescript@4.9.5) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)): + dependencies: + '@babel/core': 7.26.10 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 18.19.86 + ts-node: 10.9.2(@types/node@18.19.86)(typescript@4.9.5) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -41793,6 +41906,37 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)): + dependencies: + '@babel/core': 7.26.10 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 18.19.86 + ts-node: 10.9.2(@types/node@22.14.0)(typescript@4.9.5) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-config@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)): dependencies: '@babel/core': 7.26.10 @@ -41855,6 +41999,37 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)): + dependencies: + '@babel/core': 7.26.10 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.26.10) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.14.0 + ts-node: 10.9.2(@types/node@22.14.0)(typescript@4.9.5) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-config@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)): dependencies: '@babel/core': 7.26.10 @@ -42159,36 +42334,36 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@16.18.126): + jest@29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@16.18.126) + jest-cli: 29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)): + jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + jest-cli: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@20.17.30): + jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.30) + jest-cli: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -42207,12 +42382,12 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.14.0): + jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@22.14.0) + jest-cli: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -47719,12 +47894,12 @@ snapshots: dependencies: tslib: 2.8.1 - ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.24.2)(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2): + ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.24.2)(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -47740,12 +47915,12 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.26.10) esbuild: 0.24.2 - ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.25.2)(jest@29.7.0(@types/node@22.14.0))(typescript@5.8.2): + ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(esbuild@0.25.2)(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.14.0) + jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -47761,12 +47936,12 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.26.10) esbuild: 0.25.2 - ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@16.18.126))(typescript@4.9.5): + ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)))(typescript@4.9.5): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@16.18.126) + jest: 29.7.0(@types/node@16.18.126)(ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -47781,12 +47956,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.10) - ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86))(typescript@4.9.5): + ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)))(typescript@4.9.5): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)) + jest: 29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -47801,7 +47976,7 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.10) - ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86))(typescript@5.8.2): + ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@18.19.86)(ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2)))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 @@ -47841,52 +48016,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.26.10) - ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@20.17.30))(typescript@5.8.2): + ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)))(typescript@4.9.5): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.30) - jest-util: 29.7.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.7.1 - type-fest: 4.39.0 - typescript: 5.8.2 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.26.10 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.10) - - ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)))(typescript@5.8.2): - dependencies: - bs-logger: 0.2.6 - ejs: 3.1.10 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2)) - jest-util: 29.7.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.7.1 - type-fest: 4.39.0 - typescript: 5.8.2 - yargs-parser: 21.1.1 - optionalDependencies: - '@babel/core': 7.26.10 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.26.10) - - ts-jest@29.3.1(@babel/core@7.26.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.26.10))(jest@29.7.0(@types/node@22.14.0))(typescript@4.9.5): - dependencies: - bs-logger: 0.2.6 - ejs: 3.1.10 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@22.14.0) + jest: 29.7.0(@types/node@22.14.0)(ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -47963,6 +48098,44 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@16.18.126)(typescript@4.9.5): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 16.18.126 + acorn: 8.14.1 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + + ts-node@10.9.2(@types/node@18.19.86)(typescript@4.9.5): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 18.19.86 + acorn: 8.14.1 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + ts-node@10.9.2(@types/node@18.19.86)(typescript@5.8.2): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -47999,6 +48172,25 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@22.14.0)(typescript@4.9.5): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.14.0 + acorn: 8.14.1 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + ts-node@10.9.2(@types/node@22.14.0)(typescript@5.8.2): dependencies: '@cspotcode/source-map-support': 0.8.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a3e9caf68c..7e264d6e20 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -26,6 +26,7 @@ packages: - target_chains/ethereum/contracts - target_chains/ethereum/abi_generator - target_chains/ethereum/entropy_sdk/solidity + - target_chains/ethereum/pulse_sdk/solidity - target_chains/ethereum/sdk/js - target_chains/ethereum/sdk/solidity - target_chains/ethereum/sdk/stylus/pyth-mock-solidity diff --git a/target_chains/ethereum/abi_generator/src/index.js b/target_chains/ethereum/abi_generator/src/index.js index 524e715ebc..de5caadc4f 100644 --- a/target_chains/ethereum/abi_generator/src/index.js +++ b/target_chains/ethereum/abi_generator/src/index.js @@ -25,6 +25,10 @@ function generateAbi(contracts) { sources, settings: { outputSelection, + remappings: [ + // Needed for @pythnetwork/pulse-sdk-solidity since it depends on @pythnetwork/pyth-sdk-solidity + "@pythnetwork/=./node_modules/@pythnetwork/", + ], }, }; @@ -42,9 +46,28 @@ function generateAbi(contracts) { fs.mkdirSync("abis"); } + // Report compilation failures + if (output.errors) { + // We can still generate ABIs with warnings, only throw for errors + const errors = output.errors.filter((e) => e.severity === "error"); + if (errors.length > 0) { + console.error("Compilation errors:"); + for (const error of errors) { + console.error(error.formattedMessage || error.message); + } + throw new Error("Compilation failed due to errors"); + } + } + for (let contract of contracts) { const contractFile = `${contract}.sol`; + if (!output.contracts[contractFile]) { + throw new Error(`Unable to produce ABI for ${contractFile}.`); + } + if (!output.contracts[contractFile][contract]) { + throw new Error(`Unable to produce ABI for ${contractFile}:${contract}.`); + } const abi = output.contracts[contractFile][contract].abi; fs.writeFileSync( `abis/${contract}.json`, diff --git a/target_chains/ethereum/contracts/contracts/pulse/IScheduler.sol b/target_chains/ethereum/contracts/contracts/pulse/IScheduler.sol deleted file mode 100644 index 73a1b7be76..0000000000 --- a/target_chains/ethereum/contracts/contracts/pulse/IScheduler.sol +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; -import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; -import "./SchedulerEvents.sol"; -import "./SchedulerState.sol"; - -interface IScheduler is SchedulerEvents { - /** - * @notice Creates a new subscription - * @dev Requires msg.value to be at least the minimum balance for the subscription (calculated by getMinimumBalance()). - * @param subscriptionParams The parameters for the subscription - * @return subscriptionId The ID of the newly created subscription - */ - function createSubscription( - SchedulerState.SubscriptionParams calldata subscriptionParams - ) external payable returns (uint256 subscriptionId); - - /** - * @notice Gets a subscription's parameters and status - * @param subscriptionId The ID of the subscription - * @return params The subscription parameters - * @return status The subscription status - */ - function getSubscription( - uint256 subscriptionId - ) - external - view - returns ( - SchedulerState.SubscriptionParams memory params, - SchedulerState.SubscriptionStatus memory status - ); - - /** - * @notice Updates an existing subscription - * @dev You can activate or deactivate a subscription by setting isActive to true or false. Reactivating a subscription - * requires the subscription to hold at least the minimum balance (calculated by getMinimumBalance()). - * @dev Any Ether sent with this call (`msg.value`) will be added to the subscription's balance before processing the update. - * @param subscriptionId The ID of the subscription to update - * @param newSubscriptionParams The new parameters for the subscription - */ - function updateSubscription( - uint256 subscriptionId, - SchedulerState.SubscriptionParams calldata newSubscriptionParams - ) external payable; - - /** - * @notice Updates price feeds for a subscription. - * @dev The updateData must contain all price feeds for the subscription, not a subset or superset. - * @dev Internally, the updateData is verified using the Pyth contract and validates update conditions. - * The call will only succeed if the update conditions for the subscription are met. - * @param subscriptionId The ID of the subscription - * @param updateData The price update data from Pyth - */ - function updatePriceFeeds( - uint256 subscriptionId, - bytes[] calldata updateData - ) external; - - /** @notice Returns the price of a price feed without any sanity checks. - * @dev This function returns the most recent price update in this contract without any recency checks. - * This function is unsafe as the returned price update may be arbitrarily far in the past. - * - * Users of this function should check the `publishTime` in the price to ensure that the returned price is - * sufficiently recent for their application. If you are considering using this function, it may be - * safer / easier to use `getPriceNoOlderThan`. - * @return prices - please read the documentation of PythStructs.Price to understand how to use this safely. - */ - function getPricesUnsafe( - uint256 subscriptionId, - bytes32[] calldata priceIds - ) external view returns (PythStructs.Price[] memory prices); - - /** - * @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks. - * @dev This function returns the same price as `getEmaPrice` in the case where the price is available. - * However, if the price is not recent this function returns the latest available price. - * - * The returned price can be from arbitrarily far in the past; this function makes no guarantees that - * the returned price is recent or useful for any particular application. - * - * Users of this function should check the `publishTime` in the price to ensure that the returned price is - * sufficiently recent for their application. If you are considering using this function, it may be - * safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`. - * @return price - please read the documentation of PythStructs.Price to understand how to use this safely. - */ - function getEmaPriceUnsafe( - uint256 subscriptionId, - bytes32[] calldata priceIds - ) external view returns (PythStructs.Price[] memory price); - - /** - * @notice Adds funds to a subscription's balance - * @param subscriptionId The ID of the subscription - */ - function addFunds(uint256 subscriptionId) external payable; - - /** - * @notice Withdraws funds from a subscription's balance. - * @dev A minimum balance must be maintained for active subscriptions. To withdraw past - * the minimum balance limit, deactivate the subscription first. - * @param subscriptionId The ID of the subscription - * @param amount The amount to withdraw - */ - function withdrawFunds(uint256 subscriptionId, uint256 amount) external; - - /** - * @notice Returns the minimum balance an active subscription of a given size needs to hold. - * @param numPriceFeeds The number of price feeds in the subscription. - */ - function getMinimumBalance( - uint8 numPriceFeeds - ) external view returns (uint256 minimumBalanceInWei); - - /** - * @notice Gets all active subscriptions with their parameters, paginated. - * @dev This function has no access control to allow keepers to discover active subscriptions. - * @dev Note that the order of subscription IDs returned may not be sequential and can change - * when subscriptions are deactivated or reactivated. - * @param startIndex The starting index within the list of active subscriptions (NOT the subscription ID). - * @param maxResults The maximum number of results to return starting from startIndex. - * @return subscriptionIds Array of active subscription IDs - * @return subscriptionParams Array of subscription parameters for each active subscription - * @return totalCount Total number of active subscriptions - */ - function getActiveSubscriptions( - uint256 startIndex, - uint256 maxResults - ) - external - view - returns ( - uint256[] memory subscriptionIds, - SchedulerState.SubscriptionParams[] memory subscriptionParams, - uint256 totalCount - ); -} diff --git a/target_chains/ethereum/contracts/contracts/pulse/Scheduler.sol b/target_chains/ethereum/contracts/contracts/pulse/Scheduler.sol index 4aa5e17f97..8f636e84ad 100644 --- a/target_chains/ethereum/contracts/contracts/pulse/Scheduler.sol +++ b/target_chains/ethereum/contracts/contracts/pulse/Scheduler.sol @@ -6,11 +6,13 @@ import "@openzeppelin/contracts/utils/math/SignedMath.sol"; import "@openzeppelin/contracts/utils/math/Math.sol"; import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; import "@pythnetwork/pyth-sdk-solidity/PythErrors.sol"; -import "./IScheduler.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerStructs.sol"; +import "@pythnetwork/pulse-sdk-solidity/IScheduler.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerErrors.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerConstants.sol"; import "./SchedulerState.sol"; -import "./SchedulerErrors.sol"; -abstract contract Scheduler is IScheduler, SchedulerState { +abstract contract Scheduler is IScheduler, SchedulerState, SchedulerConstants { function _initialize( address admin, address pythAddress, @@ -28,7 +30,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { } function createSubscription( - SubscriptionParams memory subscriptionParams + SchedulerStructs.SubscriptionParams memory subscriptionParams ) external payable override returns (uint256 subscriptionId) { _validateSubscriptionParams(subscriptionParams); @@ -39,7 +41,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { // Ensure enough funds were provided if (msg.value < minimumBalance) { - revert InsufficientBalance(); + revert SchedulerErrors.InsufficientBalance(); } // Set subscription to active @@ -51,9 +53,8 @@ abstract contract Scheduler is IScheduler, SchedulerState { _state.subscriptionParams[subscriptionId] = subscriptionParams; // Initialize subscription status - SubscriptionStatus storage status = _state.subscriptionStatuses[ - subscriptionId - ]; + SchedulerStructs.SubscriptionStatus storage status = _state + .subscriptionStatuses[subscriptionId]; status.priceLastUpdatedAt = 0; status.balanceInWei = msg.value; status.totalUpdates = 0; @@ -70,21 +71,19 @@ abstract contract Scheduler is IScheduler, SchedulerState { function updateSubscription( uint256 subscriptionId, - SubscriptionParams memory newParams + SchedulerStructs.SubscriptionParams memory newParams ) external payable override onlyManager(subscriptionId) { - SubscriptionStatus storage currentStatus = _state.subscriptionStatuses[ - subscriptionId - ]; - SubscriptionParams storage currentParams = _state.subscriptionParams[ - subscriptionId - ]; + SchedulerStructs.SubscriptionStatus storage currentStatus = _state + .subscriptionStatuses[subscriptionId]; + SchedulerStructs.SubscriptionParams storage currentParams = _state + .subscriptionParams[subscriptionId]; // Add incoming funds to balance currentStatus.balanceInWei += msg.value; // Updates to permanent subscriptions are not allowed if (currentParams.isPermanent) { - revert CannotUpdatePermanentSubscription(); + revert SchedulerErrors.CannotUpdatePermanentSubscription(); } // If subscription is inactive and will remain inactive, no need to validate parameters @@ -104,7 +103,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { uint8(newParams.priceIds.length) ); if (currentStatus.balanceInWei < minimumBalance) { - revert InsufficientBalance(); + revert SchedulerErrors.InsufficientBalance(); } } @@ -117,7 +116,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { // Check if balance meets minimum requirement if (currentStatus.balanceInWei < minimumBalance) { - revert InsufficientBalance(); + revert SchedulerErrors.InsufficientBalance(); } currentParams.isActive = true; @@ -143,36 +142,37 @@ abstract contract Scheduler is IScheduler, SchedulerState { emit SubscriptionUpdated(subscriptionId); } - /** - * @notice Validates subscription parameters. - * @param params The subscription parameters to validate. - */ + /// @notice Validates subscription parameters. + /// @param params The subscription parameters to validate. function _validateSubscriptionParams( - SubscriptionParams memory params + SchedulerStructs.SubscriptionParams memory params ) internal pure { // No zero‐feed subscriptions if (params.priceIds.length == 0) { - revert EmptyPriceIds(); + revert SchedulerErrors.EmptyPriceIds(); } // Price ID limits and uniqueness - if (params.priceIds.length > MAX_PRICE_IDS_PER_SUBSCRIPTION) { - revert TooManyPriceIds( + if ( + params.priceIds.length > + SchedulerConstants.MAX_PRICE_IDS_PER_SUBSCRIPTION + ) { + revert SchedulerErrors.TooManyPriceIds( params.priceIds.length, - MAX_PRICE_IDS_PER_SUBSCRIPTION + SchedulerConstants.MAX_PRICE_IDS_PER_SUBSCRIPTION ); } for (uint i = 0; i < params.priceIds.length; i++) { for (uint j = i + 1; j < params.priceIds.length; j++) { if (params.priceIds[i] == params.priceIds[j]) { - revert DuplicatePriceId(params.priceIds[i]); + revert SchedulerErrors.DuplicatePriceId(params.priceIds[i]); } } } // Whitelist size limit and uniqueness if (params.readerWhitelist.length > MAX_READER_WHITELIST_SIZE) { - revert TooManyWhitelistedReaders( + revert SchedulerErrors.TooManyWhitelistedReaders( params.readerWhitelist.length, MAX_READER_WHITELIST_SIZE ); @@ -180,7 +180,9 @@ abstract contract Scheduler is IScheduler, SchedulerState { for (uint i = 0; i < params.readerWhitelist.length; i++) { for (uint j = i + 1; j < params.readerWhitelist.length; j++) { if (params.readerWhitelist[i] == params.readerWhitelist[j]) { - revert DuplicateWhitelistAddress(params.readerWhitelist[i]); + revert SchedulerErrors.DuplicateWhitelistAddress( + params.readerWhitelist[i] + ); } } } @@ -190,28 +192,26 @@ abstract contract Scheduler is IScheduler, SchedulerState { !params.updateCriteria.updateOnHeartbeat && !params.updateCriteria.updateOnDeviation ) { - revert InvalidUpdateCriteria(); + revert SchedulerErrors.InvalidUpdateCriteria(); } if ( params.updateCriteria.updateOnHeartbeat && params.updateCriteria.heartbeatSeconds == 0 ) { - revert InvalidUpdateCriteria(); + revert SchedulerErrors.InvalidUpdateCriteria(); } if ( params.updateCriteria.updateOnDeviation && params.updateCriteria.deviationThresholdBps == 0 ) { - revert InvalidUpdateCriteria(); + revert SchedulerErrors.InvalidUpdateCriteria(); } } - /** - * @notice Internal helper to clear stored PriceFeed data for price IDs removed from a subscription. - * @param subscriptionId The ID of the subscription being updated. - * @param currentPriceIds The array of price IDs currently associated with the subscription. - * @param newPriceIds The new array of price IDs for the subscription. - */ + /// @notice Internal helper to clear stored PriceFeed data for price IDs removed from a subscription. + /// @param subscriptionId The ID of the subscription being updated. + /// @param currentPriceIds The array of price IDs currently associated with the subscription. + /// @param newPriceIds The new array of price IDs for the subscription. function _clearRemovedPriceUpdates( uint256 subscriptionId, bytes32[] storage currentPriceIds, @@ -243,15 +243,13 @@ abstract contract Scheduler is IScheduler, SchedulerState { ) external override { uint256 startGas = gasleft(); - SubscriptionStatus storage status = _state.subscriptionStatuses[ - subscriptionId - ]; - SubscriptionParams storage params = _state.subscriptionParams[ - subscriptionId - ]; + SchedulerStructs.SubscriptionStatus storage status = _state + .subscriptionStatuses[subscriptionId]; + SchedulerStructs.SubscriptionParams storage params = _state + .subscriptionParams[subscriptionId]; if (!params.isActive) { - revert InactiveSubscription(); + revert SchedulerErrors.InactiveSubscription(); } // Get the Pyth contract and parse price updates @@ -260,7 +258,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { // If we don't have enough balance, revert if (status.balanceInWei < pythFee) { - revert InsufficientBalance(); + revert SchedulerErrors.InsufficientBalance(); } // Parse the price feed updates with an acceptable timestamp range of [0, now+10s]. @@ -287,7 +285,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { uint64 slot = slots[0]; for (uint8 i = 1; i < slots.length; i++) { if (slots[i] != slot) { - revert PriceSlotMismatch(); + revert SchedulerErrors.PriceSlotMismatch(); } } @@ -311,18 +309,16 @@ abstract contract Scheduler is IScheduler, SchedulerState { emit PricesUpdated(subscriptionId, latestPublishTime); } - /** - * @notice Validates whether the update trigger criteria is met for a subscription. Reverts if not met. - * @param subscriptionId The ID of the subscription (needed for reading previous prices). - * @param params The subscription's parameters struct. - * @param status The subscription's status struct. - * @param priceFeeds The array of price feeds to validate. - * @return The timestamp of the update if the trigger criteria is met, reverts if not met. - */ + /// @notice Validates whether the update trigger criteria is met for a subscription. Reverts if not met. + /// @param subscriptionId The ID of the subscription (needed for reading previous prices). + /// @param params The subscription's parameters struct. + /// @param status The subscription's status struct. + /// @param priceFeeds The array of price feeds to validate. + /// @return The timestamp of the update if the trigger criteria is met, reverts if not met. function _validateShouldUpdatePrices( uint256 subscriptionId, - SubscriptionParams storage params, - SubscriptionStatus storage status, + SchedulerStructs.SubscriptionParams storage params, + SchedulerStructs.SubscriptionStatus storage status, PythStructs.PriceFeed[] memory priceFeeds ) internal view returns (uint256) { // Use the most recent timestamp, as some asset markets may be closed. @@ -345,7 +341,10 @@ abstract contract Scheduler is IScheduler, SchedulerState { // Validate that the update timestamp is not too old if (updateTimestamp < minAllowedTimestamp) { - revert TimestampTooOld(updateTimestamp, block.timestamp); + revert SchedulerErrors.TimestampTooOld( + updateTimestamp, + block.timestamp + ); } // Reject updates if they're older than the latest stored ones @@ -353,7 +352,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { status.priceLastUpdatedAt > 0 && updateTimestamp <= status.priceLastUpdatedAt ) { - revert TimestampOlderThanLastUpdate( + revert SchedulerErrors.TimestampOlderThanLastUpdate( updateTimestamp, status.priceLastUpdatedAt ); @@ -413,28 +412,25 @@ abstract contract Scheduler is IScheduler, SchedulerState { } } - revert UpdateConditionsNotMet(); + revert SchedulerErrors.UpdateConditionsNotMet(); } /// FETCH PRICES - /** - * @notice Internal helper function to retrieve price feeds for a subscription. - * @param subscriptionId The ID of the subscription. - * @param priceIds The specific price IDs requested, or empty array to get all. - * @return priceFeeds An array of PriceFeed structs corresponding to the requested IDs. - */ + /// @notice Internal helper function to retrieve price feeds for a subscription. + /// @param subscriptionId The ID of the subscription. + /// @param priceIds The specific price IDs requested, or empty array to get all. + /// @return priceFeeds An array of PriceFeed structs corresponding to the requested IDs. function _getPricesInternal( uint256 subscriptionId, bytes32[] calldata priceIds ) internal view returns (PythStructs.PriceFeed[] memory priceFeeds) { if (!_state.subscriptionParams[subscriptionId].isActive) { - revert InactiveSubscription(); + revert SchedulerErrors.InactiveSubscription(); } - SubscriptionParams storage params = _state.subscriptionParams[ - subscriptionId - ]; + SchedulerStructs.SubscriptionParams storage params = _state + .subscriptionParams[subscriptionId]; // If no price IDs provided, return all price feeds for the subscription if (priceIds.length == 0) { @@ -448,7 +444,10 @@ abstract contract Scheduler is IScheduler, SchedulerState { ][params.priceIds[i]]; // Check if the price feed exists (price ID is valid and has been updated) if (priceFeed.id == bytes32(0)) { - revert InvalidPriceId(params.priceIds[i], bytes32(0)); + revert SchedulerErrors.InvalidPriceId( + params.priceIds[i], + bytes32(0) + ); } allFeeds[i] = priceFeed; } @@ -467,7 +466,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { // Check if the price feed exists (price ID is valid and has been updated) if (priceFeed.id == bytes32(0)) { - revert InvalidPriceId(priceIds[i], bytes32(0)); + revert SchedulerErrors.InvalidPriceId(priceIds[i], bytes32(0)); } requestedFeeds[i] = priceFeed; } @@ -495,7 +494,29 @@ abstract contract Scheduler is IScheduler, SchedulerState { return prices; } - function getEmaPriceUnsafe( + function getPricesNoOlderThan( + uint256 subscriptionId, + bytes32[] calldata priceIds, + uint256 age_seconds + ) + external + view + override + onlyWhitelistedReader(subscriptionId) + returns (PythStructs.Price[] memory prices) + { + SchedulerStructs.SubscriptionStatus memory status = _state + .subscriptionStatuses[subscriptionId]; + + // Use distance (absolute difference) since pythnet timestamps + // may be slightly ahead of this chain. + if (distance(block.timestamp, status.priceLastUpdatedAt) > age_seconds) + revert PythErrors.StalePrice(); + + prices = this.getPricesUnsafe(subscriptionId, priceIds); + } + + function getEmaPricesUnsafe( uint256 subscriptionId, bytes32[] calldata priceIds ) @@ -516,11 +537,33 @@ abstract contract Scheduler is IScheduler, SchedulerState { return prices; } + function getEmaPricesNoOlderThan( + uint256 subscriptionId, + bytes32[] calldata priceIds, + uint256 age_seconds + ) + external + view + override + onlyWhitelistedReader(subscriptionId) + returns (PythStructs.Price[] memory prices) + { + SchedulerStructs.SubscriptionStatus memory status = _state + .subscriptionStatuses[subscriptionId]; + + // Use distance (absolute difference) since pythnet timestamps + // may be slightly ahead of this chain. + if (distance(block.timestamp, status.priceLastUpdatedAt) > age_seconds) + revert PythErrors.StalePrice(); + + prices = this.getEmaPricesUnsafe(subscriptionId, priceIds); + } + /// BALANCE MANAGEMENT function addFunds(uint256 subscriptionId) external payable override { if (!_state.subscriptionParams[subscriptionId].isActive) { - revert InactiveSubscription(); + revert SchedulerErrors.InactiveSubscription(); } _state.subscriptionStatuses[subscriptionId].balanceInWei += msg.value; @@ -530,20 +573,18 @@ abstract contract Scheduler is IScheduler, SchedulerState { uint256 subscriptionId, uint256 amount ) external override onlyManager(subscriptionId) { - SubscriptionStatus storage status = _state.subscriptionStatuses[ - subscriptionId - ]; - SubscriptionParams storage params = _state.subscriptionParams[ - subscriptionId - ]; + SchedulerStructs.SubscriptionStatus storage status = _state + .subscriptionStatuses[subscriptionId]; + SchedulerStructs.SubscriptionParams storage params = _state + .subscriptionParams[subscriptionId]; // Prevent withdrawals from permanent subscriptions if (params.isPermanent) { - revert CannotUpdatePermanentSubscription(); + revert SchedulerErrors.CannotUpdatePermanentSubscription(); } if (status.balanceInWei < amount) { - revert InsufficientBalance(); + revert SchedulerErrors.InsufficientBalance(); } // If subscription is active, ensure minimum balance is maintained @@ -552,7 +593,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { uint8(params.priceIds.length) ); if (status.balanceInWei - amount < minimumBalance) { - revert InsufficientBalance(); + revert SchedulerErrors.InsufficientBalance(); } } @@ -571,8 +612,8 @@ abstract contract Scheduler is IScheduler, SchedulerState { view override returns ( - SubscriptionParams memory params, - SubscriptionStatus memory status + SchedulerStructs.SubscriptionParams memory params, + SchedulerStructs.SubscriptionStatus memory status ) { return ( @@ -591,7 +632,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { override returns ( uint256[] memory subscriptionIds, - SubscriptionParams[] memory subscriptionParams, + SchedulerStructs.SubscriptionParams[] memory subscriptionParams, uint256 totalCount ) { @@ -599,7 +640,11 @@ abstract contract Scheduler is IScheduler, SchedulerState { // If startIndex is beyond the total count, return empty arrays if (startIndex >= totalCount) { - return (new uint256[](0), new SubscriptionParams[](0), totalCount); + return ( + new uint256[](0), + new SchedulerStructs.SubscriptionParams[](0), + totalCount + ); } // Calculate how many results to return (bounded by maxResults and remaining items) @@ -610,7 +655,9 @@ abstract contract Scheduler is IScheduler, SchedulerState { // Create arrays for subscription IDs and parameters subscriptionIds = new uint256[](resultCount); - subscriptionParams = new SubscriptionParams[](resultCount); + subscriptionParams = new SchedulerStructs.SubscriptionParams[]( + resultCount + ); // Populate the arrays with the requested page of active subscriptions for (uint256 i = 0; i < resultCount; i++) { @@ -624,10 +671,8 @@ abstract contract Scheduler is IScheduler, SchedulerState { return (subscriptionIds, subscriptionParams, totalCount); } - /** - * @notice Returns the minimum balance an active subscription of a given size needs to hold. - * @param numPriceFeeds The number of price feeds in the subscription. - */ + /// @notice Returns the minimum balance an active subscription of a given size needs to hold. + /// @param numPriceFeeds The number of price feeds in the subscription. function getMinimumBalance( uint8 numPriceFeeds ) external view override returns (uint256 minimumBalanceInWei) { @@ -639,7 +684,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { modifier onlyManager(uint256 subscriptionId) { if (_state.subscriptionManager[subscriptionId] != msg.sender) { - revert Unauthorized(); + revert SchedulerErrors.Unauthorized(); } _; } @@ -670,15 +715,13 @@ abstract contract Scheduler is IScheduler, SchedulerState { } if (!isWhitelisted) { - revert Unauthorized(); + revert SchedulerErrors.Unauthorized(); } _; } - /** - * @notice Adds a subscription to the active subscriptions list. - * @param subscriptionId The ID of the subscription to add. - */ + /// @notice Adds a subscription to the active subscriptions list. + /// @param subscriptionId The ID of the subscription to add. function _addToActiveSubscriptions(uint256 subscriptionId) internal { // Only add if not already in the list if (_state.activeSubscriptionIndex[subscriptionId] == 0) { @@ -691,10 +734,8 @@ abstract contract Scheduler is IScheduler, SchedulerState { } } - /** - * @notice Removes a subscription from the active subscriptions list. - * @param subscriptionId The ID of the subscription to remove. - */ + /// @notice Removes a subscription from the active subscriptions list. + /// @param subscriptionId The ID of the subscription to remove. function _removeFromActiveSubscriptions(uint256 subscriptionId) internal { uint256 index = _state.activeSubscriptionIndex[subscriptionId]; @@ -718,11 +759,9 @@ abstract contract Scheduler is IScheduler, SchedulerState { } } - /** - * @notice Internal function to store the parsed price feeds. - * @param subscriptionId The ID of the subscription. - * @param priceFeeds The array of price feeds to store. - */ + /// @notice Internal function to store the parsed price feeds. + /// @param subscriptionId The ID of the subscription. + /// @param priceFeeds The array of price feeds to store. function _storePriceUpdates( uint256 subscriptionId, PythStructs.PriceFeed[] memory priceFeeds @@ -734,16 +773,14 @@ abstract contract Scheduler is IScheduler, SchedulerState { } } - /** - * @notice Internal function to calculate total fees, deduct from balance, and pay the keeper. - * @dev This function sends funds to `msg.sender`, so be sure that this is being called by a keeper. - * @dev Note that the Pyth fee is already paid in the parsePriceFeedUpdatesWithSlots call. - * @param status Storage reference to the subscription's status. - * @param startGas Gas remaining at the start of the parent function call. - * @param numPriceIds Number of price IDs being updated. - */ + /// @notice Internal function to calculate total fees, deduct from balance, and pay the keeper. + /// @dev This function sends funds to `msg.sender`, so be sure that this is being called by a keeper. + /// @dev Note that the Pyth fee is already paid in the parsePriceFeedUpdatesWithSlots call. + /// @param status Storage reference to the subscription's status. + /// @param startGas Gas remaining at the start of the parent function call. + /// @param numPriceIds Number of price IDs being updated. function _processFeesAndPayKeeper( - SubscriptionStatus storage status, + SchedulerStructs.SubscriptionStatus storage status, uint256 startGas, uint256 numPriceIds ) internal { @@ -755,7 +792,7 @@ abstract contract Scheduler is IScheduler, SchedulerState { // Check balance if (status.balanceInWei < totalKeeperFee) { - revert InsufficientBalance(); + revert SchedulerErrors.InsufficientBalance(); } status.balanceInWei -= totalKeeperFee; @@ -764,7 +801,16 @@ abstract contract Scheduler is IScheduler, SchedulerState { // Pay keeper and update status (bool sent, ) = msg.sender.call{value: totalKeeperFee}(""); if (!sent) { - revert KeeperPaymentFailed(); + revert SchedulerErrors.KeeperPaymentFailed(); + } + } + + /// @notice Helper to calculate the distance (absolute difference) between two timestamps. + function distance(uint x, uint y) internal pure returns (uint) { + if (x > y) { + return x - y; + } else { + return y - x; } } } diff --git a/target_chains/ethereum/contracts/contracts/pulse/SchedulerErrors.sol b/target_chains/ethereum/contracts/contracts/pulse/SchedulerErrors.sol deleted file mode 100644 index 899af3a840..0000000000 --- a/target_chains/ethereum/contracts/contracts/pulse/SchedulerErrors.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: Apache 2 - -pragma solidity ^0.8.0; - -// Authorization errors -error Unauthorized(); - -// Subscription state errors -error InactiveSubscription(); -error InsufficientBalance(); -error CannotUpdatePermanentSubscription(); - -// Price feed errors -error InvalidPriceId(bytes32 providedPriceId, bytes32 expectedPriceId); -error InvalidPriceIdsLength(uint256 providedLength, uint256 expectedLength); -error EmptyPriceIds(); -error TooManyPriceIds(uint256 provided, uint256 maximum); -error DuplicatePriceId(bytes32 priceId); -error PriceSlotMismatch(); - -// Update criteria errors -error InvalidUpdateCriteria(); -error UpdateConditionsNotMet(); -error TimestampTooOld( - uint256 providedUpdateTimestamp, - uint256 currentTimestamp -); -error TimestampOlderThanLastUpdate( - uint256 providedUpdateTimestamp, - uint256 lastUpdatedAt -); - -// Whitelist errors -error TooManyWhitelistedReaders(uint256 provided, uint256 maximum); -error DuplicateWhitelistAddress(address addr); - -// Payment errors -error KeeperPaymentFailed(); diff --git a/target_chains/ethereum/contracts/contracts/pulse/SchedulerGovernance.sol b/target_chains/ethereum/contracts/contracts/pulse/SchedulerGovernance.sol index 18f6bf13bc..ac1eb52399 100644 --- a/target_chains/ethereum/contracts/contracts/pulse/SchedulerGovernance.sol +++ b/target_chains/ethereum/contracts/contracts/pulse/SchedulerGovernance.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import "./SchedulerState.sol"; -import "./SchedulerErrors.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerErrors.sol"; /** * @dev `SchedulerGovernance` defines governance capabilities for the Pulse contract. @@ -44,7 +44,8 @@ abstract contract SchedulerGovernance is SchedulerState { * @dev The proposed admin accepts the admin transfer. */ function acceptAdmin() external { - if (msg.sender != _state.proposedAdmin) revert Unauthorized(); + if (msg.sender != _state.proposedAdmin) + revert SchedulerErrors.Unauthorized(); address oldAdmin = _state.admin; _state.admin = msg.sender; diff --git a/target_chains/ethereum/contracts/contracts/pulse/SchedulerState.sol b/target_chains/ethereum/contracts/contracts/pulse/SchedulerState.sol index e4c086348f..43e931bd48 100644 --- a/target_chains/ethereum/contracts/contracts/pulse/SchedulerState.sol +++ b/target_chains/ethereum/contracts/contracts/pulse/SchedulerState.sol @@ -3,30 +3,9 @@ pragma solidity ^0.8.0; import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerStructs.sol"; contract SchedulerState { - /// Maximum number of price feeds per subscription - uint8 public constant MAX_PRICE_IDS_PER_SUBSCRIPTION = 255; - /// Maximum number of addresses in the reader whitelist - uint8 public constant MAX_READER_WHITELIST_SIZE = 255; - - /// Maximum time in the past (relative to current block timestamp) - /// for which a price update timestamp is considered valid - /// when validating the update conditions. - /// @dev Note: We don't use this when parsing update data from the Pyth contract - /// because don't want to reject update data if it contains a price from a market - /// that closed a few days ago, since it will contain a timestamp from the last - /// trading period. We enforce this value ourselves against the maximum - /// timestamp in the provided update data. - uint64 public constant PAST_TIMESTAMP_MAX_VALIDITY_PERIOD = 1 hours; - - /// Maximum time in the future (relative to current block timestamp) - /// for which a price update timestamp is considered valid - uint64 public constant FUTURE_TIMESTAMP_MAX_VALIDITY_PERIOD = 10 seconds; - /// Fixed gas overhead component used in keeper fee calculation. - /// This is a rough estimate of the tx overhead for a keeper to call updatePriceFeeds. - uint256 public constant GAS_OVERHEAD = 30000; - struct State { /// Monotonically increasing counter for subscription IDs uint256 subscriptionNumber; @@ -42,9 +21,9 @@ contract SchedulerState { /// Minimum balance required per price feed in a subscription uint128 minimumBalancePerFeed; /// Sub ID -> subscription parameters (which price feeds, when to update, etc) - mapping(uint256 => SubscriptionParams) subscriptionParams; + mapping(uint256 => SchedulerStructs.SubscriptionParams) subscriptionParams; /// Sub ID -> subscription status (metadata about their sub) - mapping(uint256 => SubscriptionStatus) subscriptionStatuses; + mapping(uint256 => SchedulerStructs.SubscriptionStatus) subscriptionStatuses; /// Sub ID -> price ID -> latest parsed price update for the subscribed feed mapping(uint256 => mapping(bytes32 => PythStructs.PriceFeed)) priceUpdates; /// Sub ID -> manager address @@ -58,29 +37,6 @@ contract SchedulerState { } State internal _state; - struct SubscriptionParams { - bytes32[] priceIds; - address[] readerWhitelist; - bool whitelistEnabled; - bool isActive; - bool isPermanent; - UpdateCriteria updateCriteria; - } - - struct SubscriptionStatus { - uint256 priceLastUpdatedAt; - uint256 balanceInWei; - uint256 totalUpdates; - uint256 totalSpent; - } - - struct UpdateCriteria { - bool updateOnHeartbeat; - uint32 heartbeatSeconds; - bool updateOnDeviation; - uint32 deviationThresholdBps; - } - /** * @dev Returns the minimum balance required per feed in a subscription. */ diff --git a/target_chains/ethereum/contracts/contracts/pulse/SchedulerUpgradeable.sol b/target_chains/ethereum/contracts/contracts/pulse/SchedulerUpgradeable.sol index 114ec6dddd..39d1afec10 100644 --- a/target_chains/ethereum/contracts/contracts/pulse/SchedulerUpgradeable.sol +++ b/target_chains/ethereum/contracts/contracts/pulse/SchedulerUpgradeable.sol @@ -7,7 +7,8 @@ import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import "./Scheduler.sol"; import "./SchedulerGovernance.sol"; -import "./SchedulerErrors.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerErrors.sol"; + contract SchedulerUpgradeable is Initializable, Ownable2StepUpgradeable, @@ -55,7 +56,7 @@ contract SchedulerUpgradeable is /// Authorize actions that both admin and owner can perform function _authorizeAdminAction() internal view override { if (msg.sender != owner() && msg.sender != _state.admin) - revert Unauthorized(); + revert SchedulerErrors.Unauthorized(); } function upgradeTo(address newImplementation) external override onlyProxy { diff --git a/target_chains/ethereum/contracts/forge-test/PulseScheduler.t.sol b/target_chains/ethereum/contracts/forge-test/PulseScheduler.t.sol index ee06ff171f..44f02dcdab 100644 --- a/target_chains/ethereum/contracts/forge-test/PulseScheduler.t.sol +++ b/target_chains/ethereum/contracts/forge-test/PulseScheduler.t.sol @@ -5,13 +5,13 @@ pragma solidity ^0.8.0; import "forge-std/Test.sol"; import "forge-std/console.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import "@pythnetwork/pulse-sdk-solidity/IScheduler.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerStructs.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerEvents.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerErrors.sol"; +import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; import "../contracts/pulse/SchedulerUpgradeable.sol"; -import "../contracts/pulse/IScheduler.sol"; -import "../contracts/pulse/SchedulerState.sol"; -import "../contracts/pulse/SchedulerEvents.sol"; -import "../contracts/pulse/SchedulerErrors.sol"; import "./utils/PulseSchedulerTestUtils.t.sol"; -import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; contract MockReader { address private _scheduler; @@ -32,7 +32,7 @@ contract MockReader { bytes32[] memory priceIds ) external view returns (PythStructs.Price[] memory) { return - IScheduler(_scheduler).getEmaPriceUnsafe(subscriptionId, priceIds); + IScheduler(_scheduler).getEmaPricesUnsafe(subscriptionId, priceIds); } function verifyPriceFeeds( @@ -105,7 +105,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { } function testCreateSubscription() public { - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory params = createDefaultSubscriptionParams(2, address(reader)); bytes32[] memory priceIds = params.priceIds; // Get the generated price IDs @@ -125,8 +125,8 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Verify subscription was added correctly ( - SchedulerState.SubscriptionParams memory storedParams, - SchedulerState.SubscriptionStatus memory status + SchedulerStructs.SubscriptionParams memory storedParams, + SchedulerStructs.SubscriptionStatus memory status ) = scheduler.getSubscription(subscriptionId); assertEq( @@ -176,15 +176,15 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { newReaderWhitelist[0] = address(reader); newReaderWhitelist[1] = address(0x123); - SchedulerState.UpdateCriteria memory newUpdateCriteria = SchedulerState - .UpdateCriteria({ + SchedulerStructs.UpdateCriteria + memory newUpdateCriteria = SchedulerStructs.UpdateCriteria({ updateOnHeartbeat: true, heartbeatSeconds: 120, // Changed from 60 updateOnDeviation: true, deviationThresholdBps: 200 // Changed from 100 }); - SchedulerState.SubscriptionParams memory newParams = SchedulerState + SchedulerStructs.SubscriptionParams memory newParams = SchedulerStructs .SubscriptionParams({ priceIds: newPriceIds, readerWhitelist: newReaderWhitelist, @@ -206,7 +206,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.updateSubscription(subscriptionId, newParams); // Verify subscription was updated correctly - (SchedulerState.SubscriptionParams memory storedParams, ) = scheduler + (SchedulerStructs.SubscriptionParams memory storedParams, ) = scheduler .getSubscription(subscriptionId); assertEq( @@ -279,9 +279,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { } bytes32 removedPriceId = initialPriceIds[numInitialFeeds - 1]; // The ID we removed - (SchedulerState.SubscriptionParams memory currentParams, ) = scheduler + (SchedulerStructs.SubscriptionParams memory currentParams, ) = scheduler .getSubscription(subscriptionId); - SchedulerState.SubscriptionParams memory newParams = currentParams; // Copy existing params + SchedulerStructs.SubscriptionParams memory newParams = currentParams; // Copy existing params newParams.priceIds = newPriceIds; // Update price IDs vm.expectEmit(); // Expect SubscriptionUpdated @@ -294,7 +294,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { removedIdArray[0] = removedPriceId; vm.expectRevert( abi.encodeWithSelector( - InvalidPriceId.selector, + SchedulerErrors.InvalidPriceId.selector, removedPriceId, bytes32(0) ) @@ -330,7 +330,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { function testcreateSubscriptionWithInsufficientFundsReverts() public { uint8 numFeeds = 2; - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory params = createDefaultSubscriptionParams( numFeeds, address(reader) @@ -342,7 +342,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Try to add subscription with insufficient funds - vm.expectRevert(abi.encodeWithSelector(InsufficientBalance.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.InsufficientBalance.selector) + ); scheduler.createSubscription{value: minimumBalance - 1 wei}(params); } @@ -362,7 +364,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { assertEq(activeIds[2], subId3, "Initial: ID 3 should be active"); // --- Deactivate the middle subscription (ID 2) --- - (SchedulerState.SubscriptionParams memory params2, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params2, ) = scheduler .getSubscription(subId2); params2.isActive = false; vm.expectEmit(); @@ -387,7 +389,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // ID 3 takes the place of ID 2 // --- Deactivate the last subscription (ID 3, now at index 1) --- - (SchedulerState.SubscriptionParams memory params3, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params3, ) = scheduler .getSubscription(subId3); params3.isActive = false; vm.expectEmit(); @@ -447,7 +449,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // --- Deactivate all remaining subscriptions --- // Deactivate ID 1 (first element) - (SchedulerState.SubscriptionParams memory params1, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params1, ) = scheduler .getSubscription(subId1); params1.isActive = false; vm.expectEmit(); @@ -523,7 +525,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Get initial balance (which includes minimum balance) - (, SchedulerState.SubscriptionStatus memory initialStatus) = scheduler + (, SchedulerStructs.SubscriptionStatus memory initialStatus) = scheduler .getSubscription(subscriptionId); uint256 initialBalance = initialStatus.balanceInWei; @@ -532,7 +534,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.addFunds{value: fundAmount}(subscriptionId); // Verify funds were added - (, SchedulerState.SubscriptionStatus memory status) = scheduler + (, SchedulerStructs.SubscriptionStatus memory status) = scheduler .getSubscription(subscriptionId); assertEq( @@ -548,7 +550,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler, address(reader) ); - (SchedulerState.SubscriptionParams memory params, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params, ) = scheduler .getSubscription(subscriptionId); uint256 minimumBalance = scheduler.getMinimumBalance( uint8(params.priceIds.length) @@ -565,7 +567,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.withdrawFunds(subscriptionId, extraFunds); // Verify funds were withdrawn - (, SchedulerState.SubscriptionStatus memory status) = scheduler + (, SchedulerStructs.SubscriptionStatus memory status) = scheduler .getSubscription(subscriptionId); assertEq( @@ -580,7 +582,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Try to withdraw below minimum balance - vm.expectRevert(abi.encodeWithSelector(InsufficientBalance.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.InsufficientBalance.selector) + ); scheduler.withdrawFunds(subscriptionId, 1 wei); // Deactivate subscription @@ -607,7 +611,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Verify subscription was created as non-permanent initially - (SchedulerState.SubscriptionParams memory params, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params, ) = scheduler .getSubscription(subscriptionId); assertFalse(params.isPermanent, "Should not be permanent initially"); @@ -616,7 +620,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.updateSubscription(subscriptionId, params); // Verify subscription is now permanent - (SchedulerState.SubscriptionParams memory storedParams, ) = scheduler + (SchedulerStructs.SubscriptionParams memory storedParams, ) = scheduler .getSubscription(subscriptionId); assertTrue( storedParams.isPermanent, @@ -624,11 +628,13 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Test 1: Cannot disable isPermanent flag - SchedulerState.SubscriptionParams memory updatedParams = storedParams; + SchedulerStructs.SubscriptionParams memory updatedParams = storedParams; updatedParams.isPermanent = false; vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.updateSubscription(subscriptionId, updatedParams); @@ -643,7 +649,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { updatedParams.priceIds = reducedPriceIds; vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.updateSubscription(subscriptionId, updatedParams); @@ -656,7 +664,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.addFunds{value: extraFunds}(subscriptionId); vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.withdrawFunds(subscriptionId, 0.1 ether); @@ -674,7 +684,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { updatedParams.priceIds = expandedPriceIds; vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.updateSubscription(subscriptionId, updatedParams); @@ -692,7 +704,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { storedParams.updateCriteria.heartbeatSeconds + 60; vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.updateSubscription(subscriptionId, updatedParams); @@ -700,7 +714,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { updatedParams = storedParams; updatedParams.whitelistEnabled = !storedParams.whitelistEnabled; vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.updateSubscription(subscriptionId, updatedParams); @@ -715,7 +731,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { expandedWhitelist[storedParams.readerWhitelist.length] = address(0x456); updatedParams.readerWhitelist = expandedWhitelist; vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.updateSubscription(subscriptionId, updatedParams); @@ -732,7 +750,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { updatedParams.readerWhitelist = reducedWhitelist; vm.expectRevert( abi.encodeWithSelector( - CannotUpdatePermanentSubscription.selector + SchedulerErrors.CannotUpdatePermanentSubscription.selector ) ); scheduler.updateSubscription(subscriptionId, updatedParams); @@ -742,7 +760,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { updatedParams = storedParams; updatedParams.isActive = false; vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.updateSubscription(subscriptionId, updatedParams); } @@ -755,7 +775,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Verify it's not permanent - (SchedulerState.SubscriptionParams memory params, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params, ) = scheduler .getSubscription(subscriptionId); assertFalse( @@ -774,7 +794,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Verify we can't make it non-permanent again params.isPermanent = false; vm.expectRevert( - abi.encodeWithSelector(CannotUpdatePermanentSubscription.selector) + abi.encodeWithSelector( + SchedulerErrors.CannotUpdatePermanentSubscription.selector + ) ); scheduler.updateSubscription(subscriptionId, params); } @@ -787,7 +809,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Get initial balance - (, SchedulerState.SubscriptionStatus memory initialStatus) = scheduler + (, SchedulerStructs.SubscriptionStatus memory initialStatus) = scheduler .getSubscription(subscriptionId); uint256 initialBalance = initialStatus.balanceInWei; @@ -800,7 +822,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.addFunds{value: fundAmount}(subscriptionId); // Verify funds were added - (, SchedulerState.SubscriptionStatus memory status) = scheduler + (, SchedulerStructs.SubscriptionStatus memory status) = scheduler .getSubscription(subscriptionId); assertEq( @@ -841,7 +863,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.updatePriceFeeds(subscriptionId, updateData1); // Verify first update - (, SchedulerState.SubscriptionStatus memory status1) = scheduler + (, SchedulerStructs.SubscriptionStatus memory status1) = scheduler .getSubscription(subscriptionId); assertEq( status1.priceLastUpdatedAt, @@ -892,7 +914,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.updatePriceFeeds(subscriptionId, updateData2); // Verify second update - (, SchedulerState.SubscriptionStatus memory status2) = scheduler + (, SchedulerStructs.SubscriptionStatus memory status2) = scheduler .getSubscription(subscriptionId); assertEq( status2.priceLastUpdatedAt, @@ -931,7 +953,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Prepare update data - (SchedulerState.SubscriptionParams memory params, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params, ) = scheduler .getSubscription(subscriptionId); ( PythStructs.PriceFeed[] memory priceFeeds, @@ -947,7 +969,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Get state before uint256 pusherBalanceBefore = pusher.balance; - (, SchedulerState.SubscriptionStatus memory statusBefore) = scheduler + (, SchedulerStructs.SubscriptionStatus memory statusBefore) = scheduler .getSubscription(subscriptionId); console.log( "Subscription balance before update:", @@ -959,7 +981,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.updatePriceFeeds(subscriptionId, updateData); // Get state after - (, SchedulerState.SubscriptionStatus memory statusAfter) = scheduler + (, SchedulerStructs.SubscriptionStatus memory statusAfter) = scheduler .getSubscription(subscriptionId); // Calculate total fee deducted from subscription @@ -1042,7 +1064,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.addFunds{value: fundAmount}(subscriptionId); // Get and print the subscription balance before attempting the update - (, SchedulerState.SubscriptionStatus memory status) = scheduler + (, SchedulerStructs.SubscriptionStatus memory status) = scheduler .getSubscription(subscriptionId); console.log( "Subscription balance before update:", @@ -1056,7 +1078,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Expect revert due to insufficient balance for total fee - vm.expectRevert(abi.encodeWithSelector(InsufficientBalance.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.InsufficientBalance.selector) + ); vm.prank(pusher); scheduler.updatePriceFeeds(subscriptionId, updateData); } @@ -1066,7 +1090,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { { // Add a subscription with only heartbeat criteria (60 seconds) uint32 heartbeat = 60; - SchedulerState.UpdateCriteria memory criteria = SchedulerState + SchedulerStructs.UpdateCriteria memory criteria = SchedulerStructs .UpdateCriteria({ updateOnHeartbeat: true, heartbeatSeconds: heartbeat, @@ -1101,7 +1125,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Expect revert because heartbeat condition is not met vm.expectRevert( - abi.encodeWithSelector(UpdateConditionsNotMet.selector) + abi.encodeWithSelector( + SchedulerErrors.UpdateConditionsNotMet.selector + ) ); vm.prank(pusher); scheduler.updatePriceFeeds(subscriptionId, updateData2); @@ -1112,7 +1138,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { { // Add a subscription with only deviation criteria (100 bps / 1%) uint16 deviationBps = 100; - SchedulerState.UpdateCriteria memory criteria = SchedulerState + SchedulerStructs.UpdateCriteria memory criteria = SchedulerStructs .UpdateCriteria({ updateOnHeartbeat: false, heartbeatSeconds: 0, @@ -1163,7 +1189,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Expect revert because deviation condition is not met vm.expectRevert( - abi.encodeWithSelector(UpdateConditionsNotMet.selector) + abi.encodeWithSelector( + SchedulerErrors.UpdateConditionsNotMet.selector + ) ); vm.prank(pusher); scheduler.updatePriceFeeds(subscriptionId, updateData2); @@ -1201,7 +1229,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Expect revert with TimestampOlderThanLastUpdate (checked in _validateShouldUpdatePrices) vm.expectRevert( abi.encodeWithSelector( - TimestampOlderThanLastUpdate.selector, + SchedulerErrors.TimestampOlderThanLastUpdate.selector, publishTime2, publishTime1 ) @@ -1239,7 +1267,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { bytes[] memory updateData = createMockUpdateData(priceFeeds); // Expect revert with PriceSlotMismatch error - vm.expectRevert(abi.encodeWithSelector(PriceSlotMismatch.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.PriceSlotMismatch.selector) + ); // Attempt to update price feeds vm.prank(pusher); @@ -1255,8 +1285,8 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { address(reader) ); ( - SchedulerState.SubscriptionParams memory currentParams, - SchedulerState.SubscriptionStatus memory initialStatus + SchedulerStructs.SubscriptionParams memory currentParams, + SchedulerStructs.SubscriptionStatus memory initialStatus ) = scheduler.getSubscription(subscriptionId); uint256 initialMinimumBalance = scheduler.getMinimumBalance( initialNumFeeds @@ -1269,12 +1299,14 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Prepare new params with more feeds (4) uint8 newNumFeeds = 4; - SchedulerState.SubscriptionParams memory newParams = currentParams; + SchedulerStructs.SubscriptionParams memory newParams = currentParams; newParams.priceIds = createPriceIds(newNumFeeds); // Increase feeds newParams.isActive = true; // Keep it active // Action 1: Try to update with insufficient funds - vm.expectRevert(abi.encodeWithSelector(InsufficientBalance.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.InsufficientBalance.selector) + ); scheduler.updateSubscription(subscriptionId, newParams); // Action 2: Supply enough funds to the updateSubscription call to meet the new minimum balance @@ -1287,7 +1319,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Verification 2: Update should now succeed - (SchedulerState.SubscriptionParams memory updatedParams, ) = scheduler + (SchedulerStructs.SubscriptionParams memory updatedParams, ) = scheduler .getSubscription(subscriptionId); assertEq( updatedParams.priceIds.length, @@ -1307,10 +1339,10 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Prepare params to add feeds (4) but also deactivate uint8 newNumFeeds_deact = 4; ( - SchedulerState.SubscriptionParams memory currentParams_deact, + SchedulerStructs.SubscriptionParams memory currentParams_deact, ) = scheduler.getSubscription(subId_deact); - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory newParams_deact = currentParams_deact; newParams_deact.priceIds = createPriceIds(newNumFeeds_deact); newParams_deact.isActive = false; // Deactivate @@ -1320,7 +1352,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Verification 3: Subscription should be inactive and have 4 feeds ( - SchedulerState.SubscriptionParams memory updatedParams_deact, + SchedulerStructs.SubscriptionParams memory updatedParams_deact, ) = scheduler.getSubscription(subId_deact); assertFalse( @@ -1363,7 +1395,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { } // Check that balance is now below minimum for 1 feed - (, SchedulerState.SubscriptionStatus memory status_reduce) = scheduler + (, SchedulerStructs.SubscriptionStatus memory status_reduce) = scheduler .getSubscription(subId_reduce); uint256 minBalanceForOneFeed = scheduler.getMinimumBalance(1); assertTrue( @@ -1373,16 +1405,18 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Prepare params to reduce feeds from 2 to 1 ( - SchedulerState.SubscriptionParams memory currentParams_reduce, + SchedulerStructs.SubscriptionParams memory currentParams_reduce, ) = scheduler.getSubscription(subId_reduce); - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory newParams_reduce = currentParams_reduce; newParams_reduce.priceIds = new bytes32[](1); newParams_reduce.priceIds[0] = currentParams_reduce.priceIds[0]; // Action 4: Update should fail due to insufficient balance - vm.expectRevert(abi.encodeWithSelector(InsufficientBalance.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.InsufficientBalance.selector) + ); scheduler.updateSubscription(subId_reduce, newParams_reduce); // Add funds to cover minimum balance for 1 feed @@ -1398,7 +1432,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Verify the subscription now has 1 feed ( - SchedulerState.SubscriptionParams memory updatedParams_reduce, + SchedulerStructs.SubscriptionParams memory updatedParams_reduce, ) = scheduler.getSubscription(subId_reduce); assertEq( @@ -1505,7 +1539,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { ); // Get params and modify them - (SchedulerState.SubscriptionParams memory params, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params, ) = scheduler .getSubscription(subscriptionId); params.whitelistEnabled = false; params.readerWhitelist = new address[](0); @@ -1551,7 +1585,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.addFunds{value: 1 ether}(subscriptionId); // Get the price IDs from the created subscription - (SchedulerState.SubscriptionParams memory params, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params, ) = scheduler .getSubscription(subscriptionId); bytes32[] memory priceIds = params.priceIds; @@ -1572,7 +1606,9 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Try to access from a non-whitelisted address (should fail) vm.startPrank(address(0xdead)); bytes32[] memory emptyPriceIds = new bytes32[](0); - vm.expectRevert(abi.encodeWithSelector(Unauthorized.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.Unauthorized.selector) + ); scheduler.getPricesUnsafe(subscriptionId, emptyPriceIds); vm.stopPrank(); @@ -1638,7 +1674,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Get EMA prices bytes32[] memory emptyPriceIds = new bytes32[](0); - PythStructs.Price[] memory emaPrices = scheduler.getEmaPriceUnsafe( + PythStructs.Price[] memory emaPrices = scheduler.getEmaPricesUnsafe( subscriptionId, emptyPriceIds ); @@ -1675,7 +1711,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { bytes32[] memory priceIds = createPriceIds(); address[] memory emptyWhitelist = new address[](0); - SchedulerState.UpdateCriteria memory updateCriteria = SchedulerState + SchedulerStructs.UpdateCriteria memory updateCriteria = SchedulerStructs .UpdateCriteria({ updateOnHeartbeat: true, heartbeatSeconds: 60, @@ -1683,8 +1719,8 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { deviationThresholdBps: 100 }); - SchedulerState.SubscriptionParams memory pusherParams = SchedulerState - .SubscriptionParams({ + SchedulerStructs.SubscriptionParams + memory pusherParams = SchedulerStructs.SubscriptionParams({ priceIds: priceIds, readerWhitelist: emptyWhitelist, whitelistEnabled: false, @@ -1702,7 +1738,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Get active subscriptions directly - should work without any special permissions uint256[] memory activeIds; - SchedulerState.SubscriptionParams[] memory activeParams; + SchedulerStructs.SubscriptionParams[] memory activeParams; uint256 totalCount; (activeIds, activeParams, totalCount) = scheduler @@ -1720,7 +1756,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Verify subscription params for (uint i = 0; i < activeIds.length; i++) { ( - SchedulerState.SubscriptionParams memory storedParams, + SchedulerStructs.SubscriptionParams memory storedParams, ) = scheduler.getSubscription(activeIds[i]); @@ -1778,22 +1814,26 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { uint256 initialSubId = 0; // For update tests // === Empty Price IDs === - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory emptyPriceIdsParams = createDefaultSubscriptionParams( 1, address(reader) ); emptyPriceIdsParams.priceIds = new bytes32[](0); - vm.expectRevert(abi.encodeWithSelector(EmptyPriceIds.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.EmptyPriceIds.selector) + ); scheduler.createSubscription{value: 1 ether}(emptyPriceIdsParams); initialSubId = addTestSubscription(scheduler, address(reader)); // Create a valid one for update test - vm.expectRevert(abi.encodeWithSelector(EmptyPriceIds.selector)); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.EmptyPriceIds.selector) + ); scheduler.updateSubscription(initialSubId, emptyPriceIdsParams); // === Duplicate Price IDs === - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory duplicatePriceIdsParams = createDefaultSubscriptionParams( 2, address(reader) @@ -1802,18 +1842,24 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { duplicatePriceIdsParams.priceIds[1] = duplicateId; vm.expectRevert( - abi.encodeWithSelector(DuplicatePriceId.selector, duplicateId) + abi.encodeWithSelector( + SchedulerErrors.DuplicatePriceId.selector, + duplicateId + ) ); scheduler.createSubscription{value: 1 ether}(duplicatePriceIdsParams); initialSubId = addTestSubscription(scheduler, address(reader)); vm.expectRevert( - abi.encodeWithSelector(DuplicatePriceId.selector, duplicateId) + abi.encodeWithSelector( + SchedulerErrors.DuplicatePriceId.selector, + duplicateId + ) ); scheduler.updateSubscription(initialSubId, duplicatePriceIdsParams); // === Too Many Whitelist Readers === - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory largeWhitelistParams = createDefaultSubscriptionParams( 1, address(reader) @@ -1827,7 +1873,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { vm.expectRevert( abi.encodeWithSelector( - TooManyWhitelistedReaders.selector, + SchedulerErrors.TooManyWhitelistedReaders.selector, largeWhitelist.length, scheduler.MAX_READER_WHITELIST_SIZE() ) @@ -1837,7 +1883,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { initialSubId = addTestSubscription(scheduler, address(reader)); vm.expectRevert( abi.encodeWithSelector( - TooManyWhitelistedReaders.selector, + SchedulerErrors.TooManyWhitelistedReaders.selector, largeWhitelist.length, scheduler.MAX_READER_WHITELIST_SIZE() ) @@ -1845,7 +1891,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.updateSubscription(initialSubId, largeWhitelistParams); // === Duplicate Whitelist Address === - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory duplicateWhitelistParams = createDefaultSubscriptionParams( 1, address(reader) @@ -1857,7 +1903,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { vm.expectRevert( abi.encodeWithSelector( - DuplicateWhitelistAddress.selector, + SchedulerErrors.DuplicateWhitelistAddress.selector, address(reader) ) ); @@ -1866,14 +1912,14 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { initialSubId = addTestSubscription(scheduler, address(reader)); vm.expectRevert( abi.encodeWithSelector( - DuplicateWhitelistAddress.selector, + SchedulerErrors.DuplicateWhitelistAddress.selector, address(reader) ) ); scheduler.updateSubscription(initialSubId, duplicateWhitelistParams); // === Invalid Heartbeat (Zero Seconds) === - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory invalidHeartbeatParams = createDefaultSubscriptionParams( 1, address(reader) @@ -1881,15 +1927,23 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { invalidHeartbeatParams.updateCriteria.updateOnHeartbeat = true; invalidHeartbeatParams.updateCriteria.heartbeatSeconds = 0; // Invalid - vm.expectRevert(abi.encodeWithSelector(InvalidUpdateCriteria.selector)); + vm.expectRevert( + abi.encodeWithSelector( + SchedulerErrors.InvalidUpdateCriteria.selector + ) + ); scheduler.createSubscription{value: 1 ether}(invalidHeartbeatParams); initialSubId = addTestSubscription(scheduler, address(reader)); - vm.expectRevert(abi.encodeWithSelector(InvalidUpdateCriteria.selector)); + vm.expectRevert( + abi.encodeWithSelector( + SchedulerErrors.InvalidUpdateCriteria.selector + ) + ); scheduler.updateSubscription(initialSubId, invalidHeartbeatParams); // === Invalid Deviation (Zero Bps) === - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory invalidDeviationParams = createDefaultSubscriptionParams( 1, address(reader) @@ -1897,11 +1951,19 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { invalidDeviationParams.updateCriteria.updateOnDeviation = true; invalidDeviationParams.updateCriteria.deviationThresholdBps = 0; // Invalid - vm.expectRevert(abi.encodeWithSelector(InvalidUpdateCriteria.selector)); + vm.expectRevert( + abi.encodeWithSelector( + SchedulerErrors.InvalidUpdateCriteria.selector + ) + ); scheduler.createSubscription{value: 1 ether}(invalidDeviationParams); initialSubId = addTestSubscription(scheduler, address(reader)); - vm.expectRevert(abi.encodeWithSelector(InvalidUpdateCriteria.selector)); + vm.expectRevert( + abi.encodeWithSelector( + SchedulerErrors.InvalidUpdateCriteria.selector + ) + ); scheduler.updateSubscription(initialSubId, invalidDeviationParams); } @@ -1947,7 +2009,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { scheduler.updatePriceFeeds(subscriptionId, updateData); // Verify last updated timestamp - (, SchedulerState.SubscriptionStatus memory status) = scheduler + (, SchedulerStructs.SubscriptionStatus memory status) = scheduler .getSubscription(subscriptionId); assertEq( status.priceLastUpdatedAt, @@ -1994,7 +2056,7 @@ contract SchedulerTest is Test, SchedulerEvents, PulseSchedulerTestUtils { // Expect revert with TimestampTooOld (checked in _validateShouldUpdatePrices) vm.expectRevert( abi.encodeWithSelector( - TimestampTooOld.selector, + SchedulerErrors.TimestampTooOld.selector, stalePublishTime1, // The latest timestamp from the update currentTime ) diff --git a/target_chains/ethereum/contracts/forge-test/PulseSchedulerGasBenchmark.t.sol b/target_chains/ethereum/contracts/forge-test/PulseSchedulerGasBenchmark.t.sol index 63783731f4..4d69909698 100644 --- a/target_chains/ethereum/contracts/forge-test/PulseSchedulerGasBenchmark.t.sol +++ b/target_chains/ethereum/contracts/forge-test/PulseSchedulerGasBenchmark.t.sol @@ -7,10 +7,10 @@ import "forge-std/console.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "../contracts/pulse/SchedulerUpgradeable.sol"; -import "../contracts/pulse/IScheduler.sol"; -import "../contracts/pulse/SchedulerState.sol"; -import "../contracts/pulse/SchedulerEvents.sol"; -import "../contracts/pulse/SchedulerErrors.sol"; +import "@pythnetwork/pulse-sdk-solidity/IScheduler.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerStructs.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerEvents.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerErrors.sol"; import "./utils/PulseSchedulerTestUtils.t.sol"; contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils { @@ -54,7 +54,7 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils { // Setup: Create subscription and perform initial update vm.prank(manager); uint256 subscriptionId = _setupSubscriptionWithInitialUpdate(numFeeds); - (SchedulerState.SubscriptionParams memory params, ) = scheduler + (SchedulerStructs.SubscriptionParams memory params, ) = scheduler .getSubscription(subscriptionId); // Advance time to meet heartbeat criteria @@ -161,8 +161,10 @@ contract PulseSchedulerGasBenchmark is Test, PulseSchedulerTestUtils { // Deactivate every other subscription for (uint256 i = 0; i < numSubscriptions; i++) { if (i % 2 == 1) { - (SchedulerState.SubscriptionParams memory params, ) = scheduler - .getSubscription(subscriptionIds[i]); + ( + SchedulerStructs.SubscriptionParams memory params, + + ) = scheduler.getSubscription(subscriptionIds[i]); params.isActive = false; scheduler.updateSubscription(subscriptionIds[i], params); } diff --git a/target_chains/ethereum/contracts/forge-test/PulseSchedulerGovernance.t.sol b/target_chains/ethereum/contracts/forge-test/PulseSchedulerGovernance.t.sol index 77fcc72f1c..4cd48409be 100644 --- a/target_chains/ethereum/contracts/forge-test/PulseSchedulerGovernance.t.sol +++ b/target_chains/ethereum/contracts/forge-test/PulseSchedulerGovernance.t.sol @@ -6,7 +6,7 @@ import "forge-std/Test.sol"; import "forge-std/console.sol"; import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "../contracts/pulse/SchedulerUpgradeable.sol"; -import "../contracts/pulse/SchedulerErrors.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerErrors.sol"; contract SchedulerInvalidMagic is SchedulerUpgradeable { function schedulerUpgradableMagic() public pure override returns (uint32) { return 0x12345678; // Incorrect magic @@ -70,7 +70,9 @@ contract PulseSchedulerGovernanceTest is Test { function testProposeAdminByUnauthorized() public { address unauthorized = address(5); vm.prank(unauthorized); - vm.expectRevert(Unauthorized.selector); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.Unauthorized.selector) + ); scheduler.proposeAdmin(admin2); } @@ -91,7 +93,9 @@ contract PulseSchedulerGovernanceTest is Test { address unauthorized = address(5); vm.prank(unauthorized); - vm.expectRevert(Unauthorized.selector); + vm.expectRevert( + abi.encodeWithSelector(SchedulerErrors.Unauthorized.selector) + ); scheduler.acceptAdmin(); } diff --git a/target_chains/ethereum/contracts/forge-test/utils/PulseSchedulerTestUtils.t.sol b/target_chains/ethereum/contracts/forge-test/utils/PulseSchedulerTestUtils.t.sol index 400eac8bb5..d311bfd3d1 100644 --- a/target_chains/ethereum/contracts/forge-test/utils/PulseSchedulerTestUtils.t.sol +++ b/target_chains/ethereum/contracts/forge-test/utils/PulseSchedulerTestUtils.t.sol @@ -6,6 +6,7 @@ import "forge-std/Test.sol"; import "@openzeppelin/contracts/utils/math/SafeCast.sol"; import "../../contracts/pulse/SchedulerUpgradeable.sol"; import "../../contracts/pulse/SchedulerState.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerStructs.sol"; import "./MockPriceFeedTestUtils.sol"; abstract contract PulseSchedulerTestUtils is Test, MockPriceFeedTestUtils { @@ -14,7 +15,7 @@ abstract contract PulseSchedulerTestUtils is Test, MockPriceFeedTestUtils { SchedulerUpgradeable scheduler, address whitelistedReader ) internal returns (uint256) { - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory params = createDefaultSubscriptionParams( 2, whitelistedReader @@ -31,7 +32,7 @@ abstract contract PulseSchedulerTestUtils is Test, MockPriceFeedTestUtils { uint8 numFeeds, address whitelistedReader ) internal returns (uint256) { - SchedulerState.SubscriptionParams + SchedulerStructs.SubscriptionParams memory params = createDefaultSubscriptionParams( numFeeds, whitelistedReader @@ -45,14 +46,14 @@ abstract contract PulseSchedulerTestUtils is Test, MockPriceFeedTestUtils { /// Helper function to add a test subscription with specific update criteria function addTestSubscriptionWithUpdateCriteria( SchedulerUpgradeable scheduler, - SchedulerState.UpdateCriteria memory updateCriteria, + SchedulerStructs.UpdateCriteria memory updateCriteria, address whitelistedReader ) internal returns (uint256) { bytes32[] memory priceIds = createPriceIds(); address[] memory readerWhitelist = new address[](1); readerWhitelist[0] = whitelistedReader; - SchedulerState.SubscriptionParams memory params = SchedulerState + SchedulerStructs.SubscriptionParams memory params = SchedulerStructs .SubscriptionParams({ priceIds: priceIds, readerWhitelist: readerWhitelist, @@ -72,12 +73,12 @@ abstract contract PulseSchedulerTestUtils is Test, MockPriceFeedTestUtils { function createDefaultSubscriptionParams( uint8 numFeeds, address whitelistedReader - ) internal pure returns (SchedulerState.SubscriptionParams memory) { + ) internal pure returns (SchedulerStructs.SubscriptionParams memory) { bytes32[] memory priceIds = createPriceIds(numFeeds); address[] memory readerWhitelist = new address[](1); readerWhitelist[0] = whitelistedReader; - SchedulerState.UpdateCriteria memory updateCriteria = SchedulerState + SchedulerStructs.UpdateCriteria memory updateCriteria = SchedulerStructs .UpdateCriteria({ updateOnHeartbeat: true, heartbeatSeconds: 60, @@ -86,7 +87,7 @@ abstract contract PulseSchedulerTestUtils is Test, MockPriceFeedTestUtils { }); return - SchedulerState.SubscriptionParams({ + SchedulerStructs.SubscriptionParams({ priceIds: priceIds, readerWhitelist: readerWhitelist, whitelistEnabled: true, diff --git a/target_chains/ethereum/contracts/package.json b/target_chains/ethereum/contracts/package.json index 0a354e174d..49209f1b7b 100644 --- a/target_chains/ethereum/contracts/package.json +++ b/target_chains/ethereum/contracts/package.json @@ -42,6 +42,7 @@ "@nomad-xyz/excessively-safe-call": "^0.0.1-rc.1", "@pythnetwork/contract-manager": "workspace:*", "@pythnetwork/entropy-sdk-solidity": "workspace:*", + "@pythnetwork/pulse-sdk-solidity": "workspace:*", "@pythnetwork/pyth-sdk-solidity": "workspace:*", "@pythnetwork/xc-admin-common": "workspace:*", "dotenv": "^10.0.0", diff --git a/target_chains/ethereum/pulse_sdk/solidity/IScheduler.sol b/target_chains/ethereum/pulse_sdk/solidity/IScheduler.sol new file mode 100644 index 0000000000..1ba78ae02b --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/IScheduler.sol @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +import "@pythnetwork/pyth-sdk-solidity/IPyth.sol"; +import "@pythnetwork/pyth-sdk-solidity/PythStructs.sol"; +import "./SchedulerEvents.sol"; +import "./SchedulerStructs.sol"; + +interface IScheduler is SchedulerEvents { + /// @notice Creates a new subscription + /// @dev Requires msg.value to be at least the minimum balance for the subscription (calculated by getMinimumBalance()). + /// @param subscriptionParams The parameters for the subscription + /// @return subscriptionId The ID of the newly created subscription + function createSubscription( + SchedulerStructs.SubscriptionParams calldata subscriptionParams + ) external payable returns (uint256 subscriptionId); + + /// @notice Gets a subscription's parameters and status + /// @param subscriptionId The ID of the subscription + /// @return params The subscription parameters + /// @return status The subscription status + function getSubscription( + uint256 subscriptionId + ) + external + view + returns ( + SchedulerStructs.SubscriptionParams memory params, + SchedulerStructs.SubscriptionStatus memory status + ); + + /// @notice Updates an existing subscription + /// @dev You can activate or deactivate a subscription by setting isActive to true or false. Reactivating a subscription + /// requires the subscription to hold at least the minimum balance (calculated by getMinimumBalance()). + /// @dev Any Ether sent with this call (`msg.value`) will be added to the subscription's balance before processing the update. + /// @param subscriptionId The ID of the subscription to update + /// @param newSubscriptionParams The new parameters for the subscription + function updateSubscription( + uint256 subscriptionId, + SchedulerStructs.SubscriptionParams calldata newSubscriptionParams + ) external payable; + + /// @notice Updates price feeds for a subscription. + /// @dev The updateData must contain all price feeds for the subscription, not a subset or superset. + /// @dev Internally, the updateData is verified using the Pyth contract and validates update conditions. + /// The call will only succeed if the update conditions for the subscription are met. + /// @param subscriptionId The ID of the subscription + /// @param updateData The price update data from Pyth + function updatePriceFeeds( + uint256 subscriptionId, + bytes[] calldata updateData + ) external; + + /// @notice Returns the price of a price feed without any sanity checks. + /// @dev This function returns the most recent price update in this contract without any recency checks. + /// This function is unsafe as the returned price update may be arbitrarily far in the past. + /// + /// Users of this function should check the `publishTime` in the price to ensure that the returned price is + /// sufficiently recent for their application. If you are considering using this function, it may be + /// safer / easier to use `getPricesNoOlderThan`. + /// @return prices - please read the documentation of PythStructs.Price to understand how to use this safely. + function getPricesUnsafe( + uint256 subscriptionId, + bytes32[] calldata priceIds + ) external view returns (PythStructs.Price[] memory prices); + + /// @notice Returns the price that is no older than `age` seconds of the current time. + /// @dev This function is a sanity-checked version of `getPriceUnsafe` which is useful in + /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently + /// recently. + /// @return prices - please read the documentation of PythStructs.Price to understand how to use this safely. + function getPricesNoOlderThan( + uint256 subscriptionId, + bytes32[] calldata priceIds, + uint256 age + ) external view returns (PythStructs.Price[] memory prices); + + /// @notice Returns the exponentially-weighted moving average price of a price feed without any sanity checks. + /// @dev This function returns the same price as `getEmaPrice` in the case where the price is available. + /// However, if the price is not recent this function returns the latest available price. + /// + /// The returned price can be from arbitrarily far in the past; this function makes no guarantees that + /// the returned price is recent or useful for any particular application. + /// + /// Users of this function should check the `publishTime` in the price to ensure that the returned price is + /// sufficiently recent for their application. If you are considering using this function, it may be + /// safer / easier to use either `getEmaPrice` or `getEmaPriceNoOlderThan`. + /// @return prices - please read the documentation of PythStructs.Price to understand how to use this safely. + function getEmaPricesUnsafe( + uint256 subscriptionId, + bytes32[] calldata priceIds + ) external view returns (PythStructs.Price[] memory prices); + + /// @notice Returns the exponentially-weighted moving average price that is no older than `age_seconds` seconds + /// of the current time. + /// @dev This function is a sanity-checked version of `getEmaPricesUnsafe` which is useful in + /// applications that require a sufficiently-recent price. Reverts if the price wasn't updated sufficiently + /// recently. + /// @return prices - please read the documentation of PythStructs.Price to understand how to use this safely. + function getEmaPricesNoOlderThan( + uint256 subscriptionId, + bytes32[] calldata priceIds, + uint256 age_seconds + ) external view returns (PythStructs.Price[] memory prices); + + /// @notice Adds funds to a subscription's balance + /// @param subscriptionId The ID of the subscription + function addFunds(uint256 subscriptionId) external payable; + + /// @notice Withdraws funds from a subscription's balance. + /// @dev A minimum balance must be maintained for active subscriptions. To withdraw past + /// the minimum balance limit, deactivate the subscription first. + /// @param subscriptionId The ID of the subscription + /// @param amount The amount to withdraw + function withdrawFunds(uint256 subscriptionId, uint256 amount) external; + + /// @notice Returns the minimum balance an active subscription of a given size needs to hold. + /// @param numPriceFeeds The number of price feeds in the subscription. + function getMinimumBalance( + uint8 numPriceFeeds + ) external view returns (uint256 minimumBalanceInWei); + + /// @notice Gets all active subscriptions with their parameters, paginated. + /// @dev This function has no access control to allow keepers to discover active subscriptions. + /// @dev Note that the order of subscription IDs returned may not be sequential and can change + /// when subscriptions are deactivated or reactivated. + /// @param startIndex The starting index within the list of active subscriptions (NOT the subscription ID). + /// @param maxResults The maximum number of results to return starting from startIndex. + /// @return subscriptionIds Array of active subscription IDs + /// @return subscriptionParams Array of subscription parameters for each active subscription + /// @return totalCount Total number of active subscriptions + function getActiveSubscriptions( + uint256 startIndex, + uint256 maxResults + ) + external + view + returns ( + uint256[] memory subscriptionIds, + SchedulerStructs.SubscriptionParams[] memory subscriptionParams, + uint256 totalCount + ); +} diff --git a/target_chains/ethereum/pulse_sdk/solidity/README.md b/target_chains/ethereum/pulse_sdk/solidity/README.md new file mode 100644 index 0000000000..cb09e4fca1 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/README.md @@ -0,0 +1,128 @@ +# Pyth Pulse Solidity SDK + +The Pyth Pulse Solidity SDK allows you to interact with the Pyth Pulse protocol, which automatically pushes Pyth price updates to on-chain contracts based on configurable conditions. This SDK provides the interfaces and data structures needed to integrate with the Pulse service. + +## Install + +### Truffle/Hardhat + +If you are using Truffle or Hardhat, simply install the NPM package: + +```bash +npm install @pythnetwork/pulse-sdk-solidity +``` + +### Foundry + +If you are using Foundry, you will need to create an NPM project if you don't already have one. +From the root directory of your project, run: + +```bash +npm init -y +npm install @pythnetwork/pulse-sdk-solidity +``` + +Then add the following line to your `remappings.txt` file: + +```text +@pythnetwork/pulse-sdk-solidity/=node_modules/@pythnetwork/pulse-sdk-solidity +``` + +## Usage + +To use the SDK, you need the address of a Pulse contract on your blockchain. + +```solidity +import "@pythnetwork/pulse-sdk-solidity/IScheduler.sol"; +import "@pythnetwork/pulse-sdk-solidity/SchedulerStructs.sol"; + +IScheduler pulse = IScheduler(
); +``` + +## Key Data Structures + +### SubscriptionParams + +This struct defines the parameters for a Pulse subscription: + +```solidity +struct SubscriptionParams { + bytes32[] priceIds; // Array of Pyth price feed IDs to subscribe to + address[] readerWhitelist; // Optional array of addresses allowed to read prices + bool whitelistEnabled; // Whether to enforce whitelist or allow anyone to read + bool isActive; // Whether the subscription is active + bool isPermanent; // Whether the subscription can be updated + UpdateCriteria updateCriteria; // When to update the price feeds +} +``` + +### SubscriptionStatus + +This struct tracks the current status of a Pulse subscription: + +```solidity +struct SubscriptionStatus { + uint256 priceLastUpdatedAt; // Timestamp of the last update. All feeds in the subscription are updated together. + uint256 balanceInWei; // Balance that will be used to fund the subscription's upkeep. + uint256 totalUpdates; // Tracks update count across all feeds in the subscription (increments by number of feeds per update) + uint256 totalSpent; // Counter of total fees paid for subscription upkeep in wei. +} +``` + +### UpdateCriteria + +This struct defines when price feeds should be updated: + +```solidity +struct UpdateCriteria { + bool updateOnHeartbeat; // Should update based on time elapsed + uint32 heartbeatSeconds; // Time interval for heartbeat updates + bool updateOnDeviation; // Should update on price deviation + uint32 deviationThresholdBps; // Price deviation threshold in basis points +} +``` + +## Creating a Subscription + +```solidity +SchedulerStructs.SubscriptionParams memory params = SchedulerStructs.SubscriptionParams({ + priceIds: new bytes32[](1), + readerWhitelist: new address[](1), + whitelistEnabled: true, + isActive: true, + isPermanent: false, + updateCriteria: SchedulerStructs.UpdateCriteria({ + updateOnHeartbeat: true, + heartbeatSeconds: 60, + updateOnDeviation: true, + deviationThresholdBps: 100 + }) +}); + +params.priceIds[0] = bytes32(...); // Pyth price feed ID +params.readerWhitelist[0] = address(...); // Allowed reader + +uint256 minBalance = pulse.getMinimumBalance(uint8(params.priceIds.length)); +uint256 subscriptionId = pulse.createSubscription{value: minBalance}(params); +``` + +## Updating a Subscription + +You can update an existing subscription's parameters using the `updateSubscription` method. Only the subscription manager (the address that created it) can update a subscription, and permanent subscriptions cannot be updated afterwards. + +## Reading Price Feeds + +```solidity +bytes32[] memory priceIds = new bytes32[](1); +priceIds[0] = bytes32(...); // Pyth price feed ID + +// Specify maximum age in seconds (e.g., 300 seconds = 5 minutes) +uint256 maxAge = 300; +PythStructs.Price[] memory prices = pulse.getPricesNoOlderThan(subscriptionId, priceIds, maxAge); + +// Access price data +int64 price = prices[0].price; +uint64 conf = prices[0].conf; +int32 expo = prices[0].expo; +uint publishTime = prices[0].publishTime; +``` diff --git a/target_chains/ethereum/pulse_sdk/solidity/SchedulerConstants.sol b/target_chains/ethereum/pulse_sdk/solidity/SchedulerConstants.sol new file mode 100644 index 0000000000..16007bd472 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/SchedulerConstants.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +// This contract holds the Scheduler structs +contract SchedulerConstants { + /// Maximum number of price feeds per subscription + uint8 public constant MAX_PRICE_IDS_PER_SUBSCRIPTION = 255; + /// Maximum number of addresses in the reader whitelist + uint8 public constant MAX_READER_WHITELIST_SIZE = 255; + + /// Maximum time in the past (relative to current block timestamp) + /// for which a price update timestamp is considered valid + /// when validating the update conditions. + /// @dev Note: We don't use this when parsing update data from the Pyth contract + /// because don't want to reject update data if it contains a price from a market + /// that closed a few days ago, since it will contain a timestamp from the last + /// trading period. We enforce this value ourselves against the maximum + /// timestamp in the provided update data. + uint64 public constant PAST_TIMESTAMP_MAX_VALIDITY_PERIOD = 1 hours; + + /// Maximum time in the future (relative to current block timestamp) + /// for which a price update timestamp is considered valid + uint64 public constant FUTURE_TIMESTAMP_MAX_VALIDITY_PERIOD = 10 seconds; + /// Fixed gas overhead component used in keeper fee calculation. + /// This is a rough estimate of the tx overhead for a keeper to call updatePriceFeeds. + uint256 public constant GAS_OVERHEAD = 30000; +} diff --git a/target_chains/ethereum/pulse_sdk/solidity/SchedulerErrors.sol b/target_chains/ethereum/pulse_sdk/solidity/SchedulerErrors.sol new file mode 100644 index 0000000000..40477eb3d0 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/SchedulerErrors.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +library SchedulerErrors { + // Authorization errors + + /// 0x82b42900 + error Unauthorized(); + + // Subscription state errors + + /// 0xe7262b66 + error InactiveSubscription(); + /// 0xf4d678b8 + error InsufficientBalance(); + /// 0xf6181305 + error CannotUpdatePermanentSubscription(); + + // Price feed errors + /// 0xae2eaaa9 + error InvalidPriceId(bytes32 providedPriceId, bytes32 expectedPriceId); + /// 0xf14f93d1 + error InvalidPriceIdsLength(uint256 providedLength, uint256 expectedLength); + /// 0x94ec8d9a + error EmptyPriceIds(); + /// 0xb3d1acf6 + error TooManyPriceIds(uint256 provided, uint256 maximum); + /// 0xe3509591 + error DuplicatePriceId(bytes32 priceId); + /// 0xe56ccfaa + error PriceSlotMismatch(); + + // Update criteria errors + /// 0xa7bcd3ae + error InvalidUpdateCriteria(); + /// 0x7e8b0263 + error UpdateConditionsNotMet(); + /// 0x38fdebae + error TimestampTooOld( + uint256 providedUpdateTimestamp, + uint256 currentTimestamp + ); + /// 0x06daa54d + error TimestampOlderThanLastUpdate( + uint256 providedUpdateTimestamp, + uint256 lastUpdatedAt + ); + + // Whitelist errors + /// 0xbe4b60f7 + error TooManyWhitelistedReaders(uint256 provided, uint256 maximum); + /// 0x9941ad5f + error DuplicateWhitelistAddress(address addr); + + // Payment errors + /// 0xec58cd53 + error KeeperPaymentFailed(); +} diff --git a/target_chains/ethereum/contracts/contracts/pulse/SchedulerEvents.sol b/target_chains/ethereum/pulse_sdk/solidity/SchedulerEvents.sol similarity index 93% rename from target_chains/ethereum/contracts/contracts/pulse/SchedulerEvents.sol rename to target_chains/ethereum/pulse_sdk/solidity/SchedulerEvents.sol index 7f0c242032..26bd2fb679 100644 --- a/target_chains/ethereum/contracts/contracts/pulse/SchedulerEvents.sol +++ b/target_chains/ethereum/pulse_sdk/solidity/SchedulerEvents.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.0; -import "./SchedulerState.sol"; +import "./SchedulerStructs.sol"; interface SchedulerEvents { event SubscriptionCreated( diff --git a/target_chains/ethereum/pulse_sdk/solidity/SchedulerStructs.sol b/target_chains/ethereum/pulse_sdk/solidity/SchedulerStructs.sol new file mode 100644 index 0000000000..9cea432ed2 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/SchedulerStructs.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache 2 + +pragma solidity ^0.8.0; + +/// @title SchedulerStructs +/// @notice Contains data structures used by the Pyth Pulse protocol +contract SchedulerStructs { + /// @notice Parameters defining a Pulse subscription + struct SubscriptionParams { + bytes32[] priceIds; // Array of Pyth price feed IDs to subscribe to + address[] readerWhitelist; // Optional array of addresses allowed to read prices + bool whitelistEnabled; // Whether to enforce whitelist or allow anyone to read + bool isActive; // Whether the subscription is active + bool isPermanent; // Whether the subscription can be updated + UpdateCriteria updateCriteria; // When to update the price feeds + } + + /// @notice Status information for a Pulse subscription + struct SubscriptionStatus { + uint256 priceLastUpdatedAt; // Timestamp of the last update. All feeds in the subscription are updated together. + uint256 balanceInWei; // Balance that will be used to fund the subscription's upkeep. + uint256 totalUpdates; // Tracks update count across all feeds in the subscription (increments by number of feeds per update) + uint256 totalSpent; // Counter of total fees paid for subscription upkeep in wei. + } + + /// @notice Criteria for when price feeds should be updated + struct UpdateCriteria { + bool updateOnHeartbeat; // Should update based on time elapsed + uint32 heartbeatSeconds; // Time interval for heartbeat updates + bool updateOnDeviation; // Should update based on price deviation + uint32 deviationThresholdBps; // Price deviation threshold in basis points + } +} diff --git a/target_chains/ethereum/pulse_sdk/solidity/abis/IScheduler.json b/target_chains/ethereum/pulse_sdk/solidity/abis/IScheduler.json new file mode 100644 index 0000000000..45dc0bd324 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/abis/IScheduler.json @@ -0,0 +1,674 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "PricesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "name": "SubscriptionActivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "SubscriptionCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "name": "SubscriptionDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "name": "SubscriptionUpdated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "name": "addFunds", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes32[]", + "name": "priceIds", + "type": "bytes32[]" + }, + { + "internalType": "address[]", + "name": "readerWhitelist", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "whitelistEnabled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPermanent", + "type": "bool" + }, + { + "components": [ + { + "internalType": "bool", + "name": "updateOnHeartbeat", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "heartbeatSeconds", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "updateOnDeviation", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "deviationThresholdBps", + "type": "uint32" + } + ], + "internalType": "struct SchedulerStructs.UpdateCriteria", + "name": "updateCriteria", + "type": "tuple" + } + ], + "internalType": "struct SchedulerStructs.SubscriptionParams", + "name": "subscriptionParams", + "type": "tuple" + } + ], + "name": "createSubscription", + "outputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "startIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxResults", + "type": "uint256" + } + ], + "name": "getActiveSubscriptions", + "outputs": [ + { + "internalType": "uint256[]", + "name": "subscriptionIds", + "type": "uint256[]" + }, + { + "components": [ + { + "internalType": "bytes32[]", + "name": "priceIds", + "type": "bytes32[]" + }, + { + "internalType": "address[]", + "name": "readerWhitelist", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "whitelistEnabled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPermanent", + "type": "bool" + }, + { + "components": [ + { + "internalType": "bool", + "name": "updateOnHeartbeat", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "heartbeatSeconds", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "updateOnDeviation", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "deviationThresholdBps", + "type": "uint32" + } + ], + "internalType": "struct SchedulerStructs.UpdateCriteria", + "name": "updateCriteria", + "type": "tuple" + } + ], + "internalType": "struct SchedulerStructs.SubscriptionParams[]", + "name": "subscriptionParams", + "type": "tuple[]" + }, + { + "internalType": "uint256", + "name": "totalCount", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "priceIds", + "type": "bytes32[]" + }, + { + "internalType": "uint256", + "name": "age_seconds", + "type": "uint256" + } + ], + "name": "getEmaPricesNoOlderThan", + "outputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price[]", + "name": "prices", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "priceIds", + "type": "bytes32[]" + } + ], + "name": "getEmaPricesUnsafe", + "outputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price[]", + "name": "prices", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint8", + "name": "numPriceFeeds", + "type": "uint8" + } + ], + "name": "getMinimumBalance", + "outputs": [ + { + "internalType": "uint256", + "name": "minimumBalanceInWei", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "priceIds", + "type": "bytes32[]" + }, + { + "internalType": "uint256", + "name": "age", + "type": "uint256" + } + ], + "name": "getPricesNoOlderThan", + "outputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price[]", + "name": "prices", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "internalType": "bytes32[]", + "name": "priceIds", + "type": "bytes32[]" + } + ], + "name": "getPricesUnsafe", + "outputs": [ + { + "components": [ + { + "internalType": "int64", + "name": "price", + "type": "int64" + }, + { + "internalType": "uint64", + "name": "conf", + "type": "uint64" + }, + { + "internalType": "int32", + "name": "expo", + "type": "int32" + }, + { + "internalType": "uint256", + "name": "publishTime", + "type": "uint256" + } + ], + "internalType": "struct PythStructs.Price[]", + "name": "prices", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "name": "getSubscription", + "outputs": [ + { + "components": [ + { + "internalType": "bytes32[]", + "name": "priceIds", + "type": "bytes32[]" + }, + { + "internalType": "address[]", + "name": "readerWhitelist", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "whitelistEnabled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPermanent", + "type": "bool" + }, + { + "components": [ + { + "internalType": "bool", + "name": "updateOnHeartbeat", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "heartbeatSeconds", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "updateOnDeviation", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "deviationThresholdBps", + "type": "uint32" + } + ], + "internalType": "struct SchedulerStructs.UpdateCriteria", + "name": "updateCriteria", + "type": "tuple" + } + ], + "internalType": "struct SchedulerStructs.SubscriptionParams", + "name": "params", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "uint256", + "name": "priceLastUpdatedAt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "balanceInWei", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalUpdates", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "totalSpent", + "type": "uint256" + } + ], + "internalType": "struct SchedulerStructs.SubscriptionStatus", + "name": "status", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "internalType": "bytes[]", + "name": "updateData", + "type": "bytes[]" + } + ], + "name": "updatePriceFeeds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "components": [ + { + "internalType": "bytes32[]", + "name": "priceIds", + "type": "bytes32[]" + }, + { + "internalType": "address[]", + "name": "readerWhitelist", + "type": "address[]" + }, + { + "internalType": "bool", + "name": "whitelistEnabled", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + }, + { + "internalType": "bool", + "name": "isPermanent", + "type": "bool" + }, + { + "components": [ + { + "internalType": "bool", + "name": "updateOnHeartbeat", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "heartbeatSeconds", + "type": "uint32" + }, + { + "internalType": "bool", + "name": "updateOnDeviation", + "type": "bool" + }, + { + "internalType": "uint32", + "name": "deviationThresholdBps", + "type": "uint32" + } + ], + "internalType": "struct SchedulerStructs.UpdateCriteria", + "name": "updateCriteria", + "type": "tuple" + } + ], + "internalType": "struct SchedulerStructs.SubscriptionParams", + "name": "newSubscriptionParams", + "type": "tuple" + } + ], + "name": "updateSubscription", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdrawFunds", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerConstants.json b/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerConstants.json new file mode 100644 index 0000000000..1bf2358c19 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerConstants.json @@ -0,0 +1,67 @@ +[ + { + "inputs": [], + "name": "FUTURE_TIMESTAMP_MAX_VALIDITY_PERIOD", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GAS_OVERHEAD", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_PRICE_IDS_PER_SUBSCRIPTION", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "MAX_READER_WHITELIST_SIZE", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PAST_TIMESTAMP_MAX_VALIDITY_PERIOD", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerErrors.json b/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerErrors.json new file mode 100644 index 0000000000..be9a02b889 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerErrors.json @@ -0,0 +1,165 @@ +[ + { + "inputs": [], + "name": "CannotUpdatePermanentSubscription", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "priceId", + "type": "bytes32" + } + ], + "name": "DuplicatePriceId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "DuplicateWhitelistAddress", + "type": "error" + }, + { + "inputs": [], + "name": "EmptyPriceIds", + "type": "error" + }, + { + "inputs": [], + "name": "InactiveSubscription", + "type": "error" + }, + { + "inputs": [], + "name": "InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "providedPriceId", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "expectedPriceId", + "type": "bytes32" + } + ], + "name": "InvalidPriceId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "providedLength", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expectedLength", + "type": "uint256" + } + ], + "name": "InvalidPriceIdsLength", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidUpdateCriteria", + "type": "error" + }, + { + "inputs": [], + "name": "KeeperPaymentFailed", + "type": "error" + }, + { + "inputs": [], + "name": "PriceSlotMismatch", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "providedUpdateTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "lastUpdatedAt", + "type": "uint256" + } + ], + "name": "TimestampOlderThanLastUpdate", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "providedUpdateTimestamp", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "currentTimestamp", + "type": "uint256" + } + ], + "name": "TimestampTooOld", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maximum", + "type": "uint256" + } + ], + "name": "TooManyPriceIds", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maximum", + "type": "uint256" + } + ], + "name": "TooManyWhitelistedReaders", + "type": "error" + }, + { + "inputs": [], + "name": "Unauthorized", + "type": "error" + }, + { + "inputs": [], + "name": "UpdateConditionsNotMet", + "type": "error" + } +] diff --git a/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerEvents.json b/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerEvents.json new file mode 100644 index 0000000000..fda05cfc8e --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerEvents.json @@ -0,0 +1,79 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "timestamp", + "type": "uint256" + } + ], + "name": "PricesUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "name": "SubscriptionActivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "manager", + "type": "address" + } + ], + "name": "SubscriptionCreated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "name": "SubscriptionDeactivated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "subscriptionId", + "type": "uint256" + } + ], + "name": "SubscriptionUpdated", + "type": "event" + } +] diff --git a/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerStructs.json b/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerStructs.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/abis/SchedulerStructs.json @@ -0,0 +1 @@ +[] diff --git a/target_chains/ethereum/pulse_sdk/solidity/package.json b/target_chains/ethereum/pulse_sdk/solidity/package.json new file mode 100644 index 0000000000..d54148e1e7 --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/package.json @@ -0,0 +1,40 @@ +{ + "name": "@pythnetwork/pulse-sdk-solidity", + "version": "1.0.0", + "description": "Automatically update price feeds with Pyth Pulse", + "type": "module", + "repository": { + "type": "git", + "url": "https://github.com/pyth-network/pyth-crosschain", + "directory": "target_chains/ethereum/pulse_sdk/solidity" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "test:format": "prettier --check .", + "fix:format": "prettier --write .", + "build": "generate-abis IScheduler SchedulerConstants SchedulerErrors SchedulerEvents SchedulerStructs", + "test": "git diff --exit-code abis" + }, + "keywords": [ + "pyth", + "solidity", + "price feed", + "pulse" + ], + "author": "Douro Labs", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/pyth-network/pyth-crosschain/issues" + }, + "homepage": "https://github.com/pyth-network/pyth-crosschain/tree/main/target_chains/ethereum/pulse_sdk/solidity", + "devDependencies": { + "abi_generator": "workspace:*", + "prettier": "catalog:", + "prettier-plugin-solidity": "catalog:" + }, + "dependencies": { + "@pythnetwork/pyth-sdk-solidity": "workspace:*" + } +} diff --git a/target_chains/ethereum/pulse_sdk/solidity/prettier.config.js b/target_chains/ethereum/pulse_sdk/solidity/prettier.config.js new file mode 100644 index 0000000000..9ddff614ce --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/prettier.config.js @@ -0,0 +1,5 @@ +import solidity from "prettier-plugin-solidity"; + +export default { + plugins: [solidity], +}; diff --git a/target_chains/ethereum/pulse_sdk/solidity/turbo.json b/target_chains/ethereum/pulse_sdk/solidity/turbo.json new file mode 100644 index 0000000000..9d364662ea --- /dev/null +++ b/target_chains/ethereum/pulse_sdk/solidity/turbo.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://turbo.build/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "outputs": ["abis/**"] + }, + "test": { + "dependsOn": ["build"] + } + } +}