diff --git a/.github/workflows/publish-core.yml b/.github/workflows/publish-core.yml index 8e485d0c1d..309740c828 100644 --- a/.github/workflows/publish-core.yml +++ b/.github/workflows/publish-core.yml @@ -29,7 +29,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: "11" + version: "11.0.0" - name: Install dependencies run: pnpm install diff --git a/.github/workflows/publish-indexer.yml b/.github/workflows/publish-indexer.yml index cc2f0fcb67..b08d3f4131 100644 --- a/.github/workflows/publish-indexer.yml +++ b/.github/workflows/publish-indexer.yml @@ -94,12 +94,12 @@ jobs: "down": "./scripts/down.sh ./docker/\$ENV" }, "dependencies": { - "dotenv": "^16.4.7", - "handlebars": "^4.7.8", - "rpc-websocket-client": "^1.1.4", - "tsx": "^4.19.4", - "viem": "^2.23.5", - "zod": "^3.25.32" + "dotenv": "16.6.1", + "handlebars": "4.7.9", + "rpc-websocket-client": "1.1.4", + "tsx": "4.21.0", + "viem": "2.47.6", + "zod": "3.25.76" } } PKGJSON diff --git a/.github/workflows/publish-sdk.yml b/.github/workflows/publish-sdk.yml index 988c857b82..921dc3bcf4 100644 --- a/.github/workflows/publish-sdk.yml +++ b/.github/workflows/publish-sdk.yml @@ -33,7 +33,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: "11" + version: "11.0.0" - name: Install dependencies run: pnpm install diff --git a/.github/workflows/publish-simplex.yml b/.github/workflows/publish-simplex.yml index bdc733571d..5078dae987 100644 --- a/.github/workflows/publish-simplex.yml +++ b/.github/workflows/publish-simplex.yml @@ -206,7 +206,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: "11" + version: "11.0.0" # Straight from GitHub releases, not apt: the runners' default apt # mirror (azure.archive.ubuntu.com) has repeatedly hung apt-get diff --git a/.github/workflows/test-core.yml b/.github/workflows/test-core.yml index c159e4fb20..6ab97da4bf 100644 --- a/.github/workflows/test-core.yml +++ b/.github/workflows/test-core.yml @@ -49,7 +49,7 @@ jobs: - uses: pnpm/action-setup@v4 with: - version: 11 + version: 11.0.0 run_install: false - name: Get pnpm store directory diff --git a/.github/workflows/test-lz-endpoint.yml b/.github/workflows/test-lz-endpoint.yml index 5bd4c4efac..c718114758 100644 --- a/.github/workflows/test-lz-endpoint.yml +++ b/.github/workflows/test-lz-endpoint.yml @@ -48,7 +48,7 @@ jobs: - uses: pnpm/action-setup@v4 with: - version: 11 + version: 11.0.0 run_install: false - name: Get pnpm store directory diff --git a/.github/workflows/test-sdk.yml b/.github/workflows/test-sdk.yml index c4b5121819..cbfd794a63 100644 --- a/.github/workflows/test-sdk.yml +++ b/.github/workflows/test-sdk.yml @@ -42,7 +42,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 11 + version: 11.0.0 - name: Install dependencies run: pnpm install @@ -147,7 +147,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 11 + version: 11.0.0 - name: Install dependencies run: pnpm install diff --git a/.github/workflows/test-simplex-e2e.yml b/.github/workflows/test-simplex-e2e.yml index c9e0a5ccb4..4ba3cb9a15 100644 --- a/.github/workflows/test-simplex-e2e.yml +++ b/.github/workflows/test-simplex-e2e.yml @@ -58,7 +58,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 11 + version: 11.0.0 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/test-simplex-orderbook.yml b/.github/workflows/test-simplex-orderbook.yml index b81e46c2b9..d23caafb24 100644 --- a/.github/workflows/test-simplex-orderbook.yml +++ b/.github/workflows/test-simplex-orderbook.yml @@ -51,7 +51,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 11 + version: 11.0.0 - name: Install dependencies working-directory: sdk diff --git a/.github/workflows/test-solver-inventory.yml b/.github/workflows/test-solver-inventory.yml index fe6e02f71c..6c8d8bef4a 100644 --- a/.github/workflows/test-solver-inventory.yml +++ b/.github/workflows/test-solver-inventory.yml @@ -45,7 +45,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 with: - version: 11 + version: 11.0.0 - name: Install Foundry (anvil) uses: foundry-rs/foundry-toolchain@v1 diff --git a/docs/ai/changelog/2026-10-22-ci-pnpm-matches-packagemanager.md b/docs/ai/changelog/2026-10-22-ci-pnpm-matches-packagemanager.md new file mode 100644 index 0000000000..53af8b99ea --- /dev/null +++ b/docs/ai/changelog/2026-10-22-ci-pnpm-matches-packagemanager.md @@ -0,0 +1,14 @@ +# 2026-10-22 — CI installs the pnpm version the workspace names + +Every workflow that sets up pnpm 11 now asks `pnpm/action-setup` for `11.0.0`, the version in +`sdk/package.json`'s `packageManager` field. Before this, the workflows asked for `11`, which +means the newest 11.x release. + +When the running pnpm differs from `packageManager`, pnpm downloads `@pnpm/exe` at the named +version and switches to it. Since pnpm 11.28.7 (2026-10-21), that download goes through the +workspace's `trustPolicy: no-downgrade`. `@pnpm/exe@11.0.0` has a provenance attestation where +the releases before it had a trusted publisher, so the check refuses it and `pnpm install` fails +before resolving anything. + +Running the exact version means pnpm never switches. Change the workflows and `packageManager` +together when upgrading pnpm. diff --git a/sdk/packages/indexer/docs/ai/changelog/2026-10-22-indexer-dependencies-are-pinned.md b/sdk/packages/indexer/docs/ai/changelog/2026-10-22-indexer-dependencies-are-pinned.md new file mode 100644 index 0000000000..2d0b299c76 --- /dev/null +++ b/sdk/packages/indexer/docs/ai/changelog/2026-10-22-indexer-dependencies-are-pinned.md @@ -0,0 +1,17 @@ +# 2026-10-22 — Indexer dependencies are pinned to exact versions + +Every dependency in the indexer's `package.json` names an exact version, except the +`workspace:*` link to `@hyperbridge/sdk`. None of them use `latest` or a range any more. + +The pins are the versions `sdk/pnpm-lock.yaml` already resolved, so installs and the release build +are unchanged. `viem` is pinned to 2.47.6, the version the workspace override in +`pnpm-workspace.yaml` already forces. + +The release tarball has its own `package.json`, written by `.github/workflows/publish-indexer.yml`. +Its six dependencies are pinned to the same versions. A deployment installs them with `npm install` +and no lockfile, so a range there would resolve fresh on every deploy. + +A `latest` specifier takes whatever npm tags as latest on the day the lockfile is refreshed. +`@subql/common@5.8.3`, published on 2026-10-05, carried a credential-stealing payload and was briefly +tagged `latest`. Upgrade a dependency by changing its version here, deliberately. When the change +touches one of the release package's six dependencies, change it in the workflow too. diff --git a/sdk/packages/indexer/package.json b/sdk/packages/indexer/package.json index 30465a7c24..55bc889238 100644 --- a/sdk/packages/indexer/package.json +++ b/sdk/packages/indexer/package.json @@ -50,52 +50,52 @@ }, "dependencies": { "@hyperbridge/sdk": "workspace:*", - "@ethersproject/abi": "^5.7.0", - "@ethersproject/providers": "^5.7.2", - "@ethersproject/shims": "^5.7.0", - "@open-web3/orml-type-definitions": "^2.0.1", - "@polkadot/api": "latest", - "@polkadot/types": "latest", - "@polkadot/util": "latest", - "@polkadot/util-crypto": "latest", - "@subql/common": "latest", + "@ethersproject/abi": "5.8.0", + "@ethersproject/providers": "5.8.0", + "@ethersproject/shims": "5.8.0", + "@open-web3/orml-type-definitions": "2.0.1", + "@polkadot/api": "16.5.6", + "@polkadot/types": "16.5.6", + "@polkadot/util": "14.0.3", + "@polkadot/util-crypto": "14.0.3", + "@subql/common": "5.8.2", "@subql/common-ethereum": "4.7.0", - "@subql/types-core": "latest", - "@subql/types-ethereum": "latest", - "@subql/validator": "latest", - "@types/node-fetch": "^2.6.13", - "assert": "^2.0.0", - "decimal.js": "^10.5.0", - "dotenv": "^16.4.7", - "fast-text-encoding": "^1.0.6", - "handlebars": "^4.7.8", + "@subql/types-core": "2.2.0", + "@subql/types-ethereum": "4.2.3", + "@subql/validator": "2.2.0", + "@types/node-fetch": "2.6.13", + "assert": "2.1.0", + "decimal.js": "10.6.0", + "dotenv": "16.6.1", + "fast-text-encoding": "1.0.6", + "handlebars": "4.7.9", "node-fetch": "2.7.0", - "pg": "^8.20.0", - "safe-stable-stringify": "^2.5.0", - "scale-ts": "^1.6.1", - "viem": "^2.23.5", - "zod": "^3.25.32" + "pg": "8.20.0", + "safe-stable-stringify": "2.5.0", + "scale-ts": "1.6.1", + "viem": "2.47.6", + "zod": "3.25.76" }, "devDependencies": { "@subql/cli": "5.7.1-0", - "@subql/node": "latest", - "@subql/node-core": "latest", - "@subql/node-ethereum": "latest", - "@subql/testing": "latest", - "@subql/types": "latest", - "@types/handlebars": "^4.1.0", - "@types/jest": "^29.5.14", - "@types/node": "^22.13.5", - "@types/pino": "^7.0.4", - "ethers": "^5.7.2", - "fs-extra": "^11.3.0", - "prettier": "^3.5.2", - "rpc-websocket-client": "^1.1.4", - "ts-jest": "^29.2.6", - "ts-node": "^10.9.2", - "tslib": "^2.8.1", - "tsx": "^4.19.4", - "typescript": "latest" + "@subql/node": "6.4.6", + "@subql/node-core": "19.3.1", + "@subql/node-ethereum": "6.5.0", + "@subql/testing": "2.3.1", + "@subql/types": "3.15.0", + "@types/handlebars": "4.1.0", + "@types/jest": "29.5.14", + "@types/node": "22.19.17", + "@types/pino": "7.0.5", + "ethers": "5.8.0", + "fs-extra": "11.3.4", + "prettier": "3.5.2", + "rpc-websocket-client": "1.1.4", + "ts-jest": "29.4.9", + "ts-node": "10.9.2", + "tslib": "2.8.1", + "tsx": "4.21.0", + "typescript": "6.0.3" }, "exports": { "./substrate-chaintypes/hyperbridge": "./src/substrate-chaintypes/hyperbridge.ts" diff --git a/sdk/packages/lz-endpoint/README.md b/sdk/packages/lz-endpoint/README.md index c9d33cbee1..61632c0b29 100644 --- a/sdk/packages/lz-endpoint/README.md +++ b/sdk/packages/lz-endpoint/README.md @@ -55,6 +55,8 @@ Fees can be paid in two ways: The `quote()` function returns the appropriate fee based on the `payInLzToken` flag. +LayerZero requires `quote()` to be `view`, so it prices a native fee by reading the host's fee oracle in a static call. Some hosts' oracles price by simulating a swap, which a static call cannot do. That's the Uniswap V3 wrapper on Ethereum and Polygon, and the V4 wrapper on Arbitrum and Base. On those chains a native-fee `quote()` reverts, so OApps there should pay in the fee token. BSC's oracle is PancakeSwap's V2 router, which quotes natively. + ### Relayer fees A per-destination relayer fee incentivizes Hyperbridge relayers to deliver messages. Defaults to $0.30 (computed from the fee token's decimals). The adapter owner can customize fees: diff --git a/sdk/packages/lz-endpoint/contracts/HyperbridgeLzEndpoint.sol b/sdk/packages/lz-endpoint/contracts/HyperbridgeLzEndpoint.sol index 568feae3da..15c69fd7d3 100644 --- a/sdk/packages/lz-endpoint/contracts/HyperbridgeLzEndpoint.sol +++ b/sdk/packages/lz-endpoint/contracts/HyperbridgeLzEndpoint.sol @@ -36,6 +36,16 @@ import {ILayerZeroReceiver} from "@layerzerolabs/lz-evm-protocol-v2/contracts/in import {ILayerZeroComposer} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/ILayerZeroComposer.sol"; import {SetConfigParam} from "@layerzerolabs/lz-evm-protocol-v2/contracts/interfaces/IMessageLibManager.sol"; +/** + * @dev The host's fee oracle, read in a static context. `HyperApp.quote` calls it with a + * state-changing `CALL`, which a `view` function cannot make. + */ +interface IUniswapV2RouterView { + function WETH() external view returns (address); + + function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory); +} + /** * @title HyperbridgeLzEndpoint * @author Polytope Labs (hello@polytope.technology) @@ -341,10 +351,23 @@ contract HyperbridgeLzEndpoint is HyperApp, Ownable, Pausable, ILayerZeroEndpoin if (_params.payInLzToken) { return MessagingFee({nativeFee: 0, lzTokenFee: request.fee * 2}); } else { - return MessagingFee({nativeFee: quote(request) * 2, lzTokenFee: 0}); + return MessagingFee({nativeFee: _nativeFee(request.fee) * 2, lzTokenFee: 0}); } } + /** + * @dev The native amount the host's fee oracle wants for `feeTokenAmount`. LayerZero + * requires `quote` to be `view`, so this reverts on a host whose oracle prices by + * simulating a swap, such as a Uniswap V3 or V4 wrapper. + */ + function _nativeFee(uint256 feeTokenAmount) private view returns (uint256) { + address router = IDispatcher(_host).uniswapV2Router(); + address[] memory path = new address[](2); + path[0] = IUniswapV2RouterView(router).WETH(); + path[1] = IDispatcher(_host).feeToken(); + return IUniswapV2RouterView(router).getAmountsIn(feeTokenAmount, path)[0]; + } + // ==================== ISMP Callbacks ==================== /** diff --git a/sdk/pnpm-lock.yaml b/sdk/pnpm-lock.yaml index e3199e38df..1bd82ceb84 100644 --- a/sdk/pnpm-lock.yaml +++ b/sdk/pnpm-lock.yaml @@ -73,140 +73,140 @@ importers: packages/indexer: dependencies: '@ethersproject/abi': - specifier: ^5.7.0 + specifier: 5.8.0 version: 5.8.0 '@ethersproject/providers': - specifier: ^5.7.2 + specifier: 5.8.0 version: 5.8.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) '@ethersproject/shims': - specifier: ^5.7.0 + specifier: 5.8.0 version: 5.8.0 '@hyperbridge/sdk': specifier: workspace:* version: link:../sdk '@open-web3/orml-type-definitions': - specifier: ^2.0.1 + specifier: 2.0.1 version: 2.0.1 '@polkadot/api': - specifier: latest + specifier: 16.5.6 version: 16.5.6(bufferutil@4.1.0)(utf-8-validate@5.0.10) '@polkadot/types': - specifier: latest + specifier: 16.5.6 version: 16.5.6 '@polkadot/util': - specifier: latest + specifier: 14.0.3 version: 14.0.3 '@polkadot/util-crypto': - specifier: latest + specifier: 14.0.3 version: 14.0.3(@polkadot/util@14.0.3) '@subql/common': - specifier: latest + specifier: 5.8.2 version: 5.8.2 '@subql/common-ethereum': specifier: 4.7.0 version: 4.7.0(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.8.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(bufferutil@4.1.0)(class-transformer@0.5.1)(class-validator@0.14.1)(ethers@5.8.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(typescript@6.0.3)(utf-8-validate@5.0.10) '@subql/types-core': - specifier: latest + specifier: 2.2.0 version: 2.2.0 '@subql/types-ethereum': - specifier: latest + specifier: 4.2.3 version: 4.2.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) '@subql/validator': - specifier: latest + specifier: 2.2.0 version: 2.2.0(@chain-registry/v2-types@0.53.146)(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.8.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(@near-js/crypto@2.5.1(@near-js/types@2.5.1)(@near-js/utils@2.5.1(@near-js/types@2.5.1)))(@near-js/transactions@2.5.1(@near-js/crypto@2.5.1(@near-js/types@2.5.1)(@near-js/utils@2.5.1(@near-js/types@2.5.1)))(@near-js/types@2.5.1)(@near-js/utils@2.5.1(@near-js/types@2.5.1)))(@near-js/types@2.5.1)(@near-js/utils@2.5.1(@near-js/types@2.5.1))(@polkadot/api@16.5.6(bufferutil@4.1.0)(utf-8-validate@5.0.10))(algosdk@2.11.0)(bufferutil@4.1.0)(class-transformer@0.5.1)(class-validator@0.14.1)(ejs@3.1.10)(encoding@0.1.13)(ethers@5.8.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(node-fetch@2.7.0(encoding@0.1.13))(typescript@6.0.3)(utf-8-validate@5.0.10) '@types/node-fetch': - specifier: ^2.6.13 + specifier: 2.6.13 version: 2.6.13 assert: - specifier: ^2.0.0 + specifier: 2.1.0 version: 2.1.0 decimal.js: - specifier: ^10.5.0 + specifier: 10.6.0 version: 10.6.0 dotenv: - specifier: ^16.4.7 + specifier: 16.6.1 version: 16.6.1 fast-text-encoding: - specifier: ^1.0.6 + specifier: 1.0.6 version: 1.0.6 handlebars: - specifier: ^4.7.8 + specifier: 4.7.9 version: 4.7.9 node-fetch: specifier: 2.7.0 version: 2.7.0(encoding@0.1.13) pg: - specifier: ^8.20.0 + specifier: 8.20.0 version: 8.20.0 safe-stable-stringify: - specifier: ^2.5.0 + specifier: 2.5.0 version: 2.5.0 scale-ts: - specifier: ^1.6.1 + specifier: 1.6.1 version: 1.6.1 viem: specifier: 2.47.6 version: 2.47.6(bufferutil@4.1.0)(typescript@6.0.3)(utf-8-validate@5.0.10)(zod@3.25.76) zod: - specifier: ^3.25.32 + specifier: 3.25.76 version: 3.25.76 devDependencies: '@subql/cli': specifier: 5.7.1-0 version: 5.7.1-0(@types/node@22.19.17)(encoding@0.1.13)(pg@8.20.0) '@subql/node': - specifier: latest + specifier: 6.4.6 version: 6.4.6(@types/react@19.2.17)(bufferutil@4.1.0)(class-transformer@0.5.1)(class-validator@0.14.1)(graphql@16.13.2)(pg@8.20.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rxjs@7.8.2)(utf-8-validate@5.0.10) '@subql/node-core': - specifier: latest + specifier: 19.3.1 version: 19.3.1(@nestjs/core@11.1.18)(@polkadot/api@16.5.6(bufferutil@4.1.0)(utf-8-validate@5.0.10))(@types/react@19.2.17)(class-transformer@0.5.1)(class-validator@0.14.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@subql/node-ethereum': - specifier: latest + specifier: 6.5.0 version: 6.5.0(@ethersproject/abi@5.8.0)(@ethersproject/providers@5.8.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(@polkadot/api@16.5.6(bufferutil@4.1.0)(utf-8-validate@5.0.10))(@subql/utils@2.22.1(pg@8.20.0))(@types/react@19.2.17)(bufferutil@4.1.0)(class-transformer@0.5.1)(class-validator@0.14.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(rxjs@7.8.2)(typescript@6.0.3)(utf-8-validate@5.0.10) '@subql/testing': - specifier: latest + specifier: 2.3.1 version: 2.3.1 '@subql/types': - specifier: latest + specifier: 3.15.0 version: 3.15.0(@polkadot/api@16.5.6(bufferutil@4.1.0)(utf-8-validate@5.0.10)) '@types/handlebars': - specifier: ^4.1.0 + specifier: 4.1.0 version: 4.1.0 '@types/jest': - specifier: ^29.5.14 + specifier: 29.5.14 version: 29.5.14 '@types/node': - specifier: ^22.13.5 + specifier: 22.19.17 version: 22.19.17 '@types/pino': - specifier: ^7.0.4 + specifier: 7.0.5 version: 7.0.5 ethers: - specifier: ^5.7.2 + specifier: 5.8.0 version: 5.8.0(bufferutil@4.1.0)(utf-8-validate@5.0.10) fs-extra: - specifier: ^11.3.0 + specifier: 11.3.4 version: 11.3.4 prettier: - specifier: ^3.5.2 + specifier: 3.5.2 version: 3.5.2 rpc-websocket-client: - specifier: ^1.1.4 + specifier: 1.1.4 version: 1.1.4(bufferutil@4.1.0)(utf-8-validate@5.0.10) ts-jest: - specifier: ^29.2.6 + specifier: 29.4.9 version: 29.4.9(@babel/core@7.18.10)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.18.10))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.17)(ts-node@10.9.2(@types/node@22.19.17)(typescript@6.0.3)))(typescript@6.0.3) ts-node: - specifier: ^10.9.2 + specifier: 10.9.2 version: 10.9.2(@types/node@22.19.17)(typescript@6.0.3) tslib: - specifier: ^2.8.1 + specifier: 2.8.1 version: 2.8.1 tsx: - specifier: ^4.19.4 + specifier: 4.21.0 version: 4.21.0 typescript: - specifier: latest + specifier: 6.0.3 version: 6.0.3 packages/lz-endpoint: