Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .github/workflows/rainix-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Docker image CI

on:
push:
workflow_dispatch:
inputs:
tag:
description: 'Tag to give the build. Try to make it unique.'
required: true

env:
CHANNEL: ${{ inputs.tag || github.head_ref || github.ref_name }}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Potential tag collision risk with dynamic CHANNEL naming.

The CHANNEL environment variable derives from inputs.tag, github.head_ref, or github.ref_name. For concurrent pushes to different branches, this could lead to race conditions or unintended tag overwrites.

Consider adding a unique suffix or using a more structured tagging strategy:

 env:
-  CHANNEL: ${{ inputs.tag || github.head_ref || github.ref_name }}
+  CHANNEL: ${{ inputs.tag || format('{0}-{1}', github.head_ref || github.ref_name, github.run_number) }}
   DOCKER_BUILDKIT: 1

Or use commit SHA for uniqueness:

env:
  CHANNEL: ${{ inputs.tag || format('{0}-{1}', github.head_ref || github.ref_name, github.sha) }}
🤖 Prompt for AI Agents
.github/workflows/rainix-docker.yml around line 12: the CHANNEL value is derived
from inputs.tag or branch name which can collide across concurrent runs; change
the assignment to append a unique identifier (e.g., short commit SHA or
timestamp) or use a structured format combining branch/tag with github.sha to
guarantee uniqueness and avoid tag overwrites; update the env variable
construction accordingly and ensure downstream steps use the new CHANNEL value
consistently.

DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
TAG_BASE: rainprotocol/pyth-crosschain

jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0

- name: Install Nix 1/2
uses: DeterminateSystems/nix-installer-action@main
with:
determinate: true
- name: Install Nix 2/2
uses: DeterminateSystems/flakehub-cache-action@main

- name: Install deps
run: nix develop -c pnpm install --frozen-lockfile

- name: Build Price Pusher
run: nix develop -c pnpm turbo build --filter @pythnetwork/price-pusher
Comment on lines +36 to +40
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Build step alignment with Dockerfile concerns.

The workflow builds the price-pusher package using pnpm turbo build, but the Dockerfile (as currently written) doesn't install dependencies or run build steps. This creates a mismatch where the workflow builds locally, but the Docker image may not have these artifacts available at runtime.

Ensure the Dockerfile includes the necessary build steps (as flagged in the Dockerfile review), or structure the workflow to produce build artifacts that are then copied into a minimal runtime image using a multi-stage build pattern.

🤖 Prompt for AI Agents
.github/workflows/rainix-docker.yml lines 36-40: the CI runs `pnpm turbo build`
for @pythnetwork/price-pusher but the Dockerfile does not install deps or copy
build outputs, causing runtime images to miss artifacts; either update the
Dockerfile to perform dependency install and the package build (add a build
stage that runs pnpm install/build and copies the dist into the final image) or
change the workflow to output the built artifacts (e.g., tar/zip or push to
registry) and use a multi-stage Dockerfile that copies those artifacts into a
minimal runtime image; ensure the chosen approach installs dependencies with
frozen lockfile, produces the same build artifacts as the workflow, and that the
final image contains the built files and any runtime-only deps.


- uses: docker/setup-buildx-action@v2
- uses: docker/login-action@v2
Comment on lines +42 to +43
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Update Docker actions to latest versions.

The workflow uses docker/setup-buildx-action@v2 and docker/login-action@v2, which are outdated and may not run on current GitHub Actions runners.

Apply this diff to update to v3:

-      - uses: docker/setup-buildx-action@v2
-      - uses: docker/login-action@v2
+      - uses: docker/setup-buildx-action@v3
+      - uses: docker/login-action@v3
🧰 Tools
🪛 actionlint (1.7.7)

42-42: the runner of "docker/setup-buildx-action@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)


43-43: the runner of "docker/login-action@v2" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In .github/workflows/rainix-docker.yml around lines 42 to 43, the workflow pins
docker/setup-buildx-action@v2 and docker/login-action@v2 which are outdated;
update those action versions to @v3 by replacing the two usages with
docker/setup-buildx-action@v3 and docker/login-action@v3 (and run a quick
workflow dispatch to verify no new required inputs changed).

with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- run: |
rm .dockerignore
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify that removing .dockerignore is intentional.

The workflow explicitly removes the .dockerignore file before building. This could lead to unnecessarily large Docker images if build artifacts, node_modules, or other ignored files are included.

Verify whether removing .dockerignore is required:

If the removal is necessary, document why in a comment:

       - run: |
+          # Remove .dockerignore to include build artifacts in the image
           rm .dockerignore
           docker build -t "$TAG_BASE:$CHANNEL" --build-arg GIT_SHA=${{ github.sha }} --build-arg DOCKER_CHANNEL=$CHANNEL .

🏁 Script executed:

#!/bin/bash
# Check if .dockerignore exists and what it contains
if [ -f .dockerignore ]; then
  echo "=== Contents of .dockerignore ==="
  cat .dockerignore
  echo ""
  echo "=== Checking for large directories that might be ignored ==="
  fd -t d 'node_modules|dist|build|.git' --max-depth 3 -x du -sh
else
  echo ".dockerignore does not exist in the repository"
fi

Length of output: 448


Document rationale for removing .dockerignore
Add a comment above rm .dockerignore to explain that .dockerignore ignores the lib directory and other build outputs, so it must be removed to include necessary artifacts in the Docker build context:

       - run: |
+        # Remove .dockerignore so compiled artifacts (lib, build outputs, node_modules, etc.) are included in Docker context
         rm .dockerignore
         docker build -t "$TAG_BASE:$CHANNEL" --build-arg GIT_SHA=${{ github.sha }} --build-arg DOCKER_CHANNEL=$CHANNEL .

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
.github/workflows/rainix-docker.yml around line 48: add a brief comment above
the rm .dockerignore step explaining that the repository's .dockerignore
excludes the lib directory and other build outputs needed in the image, so we
remove .dockerignore to ensure those artifacts are included in the Docker build
context; keep the comment concise and factual.

docker build -t "$TAG_BASE:$CHANNEL" --build-arg GIT_SHA=${{ github.sha }} --build-arg DOCKER_CHANNEL=$CHANNEL .
- run: |
docker push "$TAG_BASE:$CHANNEL"
Comment on lines +47 to +51
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider using docker/build-push-action for better caching and features.

The workflow manually runs docker build and docker push commands. The docker/build-push-action provides better layer caching, multi-platform support, and BuildKit features.

Replace the manual docker commands:

-      - run: |
-          rm .dockerignore
-          docker build -t "$TAG_BASE:$CHANNEL" --build-arg GIT_SHA=${{ github.sha }} --build-arg DOCKER_CHANNEL=$CHANNEL .
-      - run: |
-          docker push "$TAG_BASE:$CHANNEL"
+      - uses: docker/build-push-action@v5
+        with:
+          context: .
+          push: true
+          tags: ${{ env.TAG_BASE }}:${{ env.CHANNEL }}
+          build-args: |
+            GIT_SHA=${{ github.sha }}
+            DOCKER_CHANNEL=${{ env.CHANNEL }}
+          cache-from: type=gha
+          cache-to: type=gha,mode=max
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- run: |
rm .dockerignore
docker build -t "$TAG_BASE:$CHANNEL" --build-arg GIT_SHA=${{ github.sha }} --build-arg DOCKER_CHANNEL=$CHANNEL .
- run: |
docker push "$TAG_BASE:$CHANNEL"
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ env.TAG_BASE }}:${{ env.CHANNEL }}
build-args: |
GIT_SHA=${{ github.sha }}
DOCKER_CHANNEL=${{ env.CHANNEL }}
cache-from: type=gha
cache-to: type=gha,mode=max
🤖 Prompt for AI Agents
.github/workflows/rainix-docker.yml around lines 47 to 51: replace the manual
docker build and docker push steps with docker/build-push-action to get
BuildKit, caching and multi-platform support; update the job to use - uses:
docker/build-push-action@v4 - with context: ., push: true, tags:
"$TAG_BASE:$CHANNEL", build-args: GIT_SHA=${{ github.sha }},
DOCKER_CHANNEL=$CHANNEL and configure cache-from/cache-to (e.g., type=registry)
as appropriate; ensure any removal of .dockerignore is handled before the action
or omitted if unnecessary and keep environment variables/permissions for pushing
(e.g., set up docker login or use GITHUB_TOKEN/registry credentials) so the
action can authenticate and push.

21 changes: 21 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM node:22.14
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify that the Node.js base image version is current and secure.

The Dockerfile uses node:22.14 as the base image. Ensure this version is up-to-date and free from known vulnerabilities.


🌐 Web query:

What is the latest LTS version of Node.js?

💡 Result:

The current LTS major is Node.js v22 ("Jod"); the latest release in that line is v22.20.0 (released Sep 24, 2025). [1][2]

Sources:
[1] Node.js v22.20.0 release notes (Sep 24, 2025).
[2] Node.js Releases listing showing v22 as Active LTS.


Update Node.js base image to v22.20.0
Replace FROM node:22.14 with FROM node:22.20.0 (latest Active LTS as of Sep 24, 2025) to include the most recent security patches.

🧰 Tools
🪛 Checkov (3.2.334)

[low] 1-21: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-21: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🤖 Prompt for AI Agents
In Dockerfile around lines 1 to 1, the base image is pinned to node:22.14;
update it to the current Active LTS by replacing that line with FROM
node:22.20.0 so the build uses Node.js v22.20.0 with latest security patches;
ensure no other Dockerfile references or CI cache expectations require the older
tag and rebuild any dependent images.


# set git sha and docker tag form build time arg to run time env in container
ARG GIT_SHA
ARG DOCKER_CHANNEL
ENV GIT_COMMIT=$GIT_SHA
ENV DOCKER_TAG=$DOCKER_CHANNEL

WORKDIR /price-pusher
ADD . .
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use COPY instead of ADD for regular files.

Docker best practices recommend using COPY instead of ADD for copying files and directories, as ADD has additional features (like extracting tar files) that can lead to unexpected behavior.

Apply this diff:

-ADD . .
+COPY . .
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ADD . .
COPY . .
🧰 Tools
🪛 Checkov (3.2.334)

[low] 10-10: Ensure that COPY is used instead of ADD in Dockerfiles

(CKV_DOCKER_4)

🪛 Hadolint (2.14.0)

[error] 10-10: Use COPY instead of ADD for files and folders

(DL3020)

🤖 Prompt for AI Agents
In Dockerfile around line 10, the Dockerfile uses ADD . . which is discouraged
for regular file copying; replace the ADD command with COPY . . to follow best
practices (use COPY for simple file/directory copies and reserve ADD only when
you need its extra features like remote URLs or automatic tar extraction).


WORKDIR apps/price_pusher
Comment on lines +9 to +12
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Missing dependency installation and build steps.

The Dockerfile copies all files and switches to the apps/price_pusher directory, but there's no npm install or build step. Without installing dependencies, the npm run start command will fail at runtime.

Add dependency installation and build steps after copying files:

 WORKDIR /price-pusher
 COPY . .
+RUN npm install --frozen-lockfile
+RUN npm run build

 WORKDIR apps/price_pusher

Alternatively, if using a monorepo tool like turbo (as indicated in the workflow), adjust accordingly:

 WORKDIR /price-pusher
 COPY . .
+RUN npm install -g pnpm
+RUN pnpm install --frozen-lockfile
+RUN pnpm turbo build --filter @pythnetwork/price-pusher

 WORKDIR apps/price_pusher
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
WORKDIR /price-pusher
ADD . .
WORKDIR apps/price_pusher
WORKDIR /price-pusher
COPY . .
RUN npm install --frozen-lockfile
RUN npm run build
WORKDIR apps/price_pusher
Suggested change
WORKDIR /price-pusher
ADD . .
WORKDIR apps/price_pusher
WORKDIR /price-pusher
COPY . .
RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile
RUN pnpm turbo build --filter @pythnetwork/price-pusher
WORKDIR apps/price_pusher
🧰 Tools
🪛 Checkov (3.2.334)

[low] 10-10: Ensure that COPY is used instead of ADD in Dockerfiles

(CKV_DOCKER_4)


[low] 12-12: Ensure that WORKDIR values are absolute paths

(CKV_DOCKER_10)

🪛 Hadolint (2.14.0)

[error] 10-10: Use COPY instead of ADD for files and folders

(DL3020)


[error] 12-12: Use absolute WORKDIR

(DL3000)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use absolute WORKDIR path.

The second WORKDIR uses a relative path. Docker best practices recommend using absolute paths for clarity and to avoid ambiguity.

Apply this diff:

-WORKDIR apps/price_pusher
+WORKDIR /price-pusher/apps/price_pusher
🧰 Tools
🪛 Checkov (3.2.334)

[low] 12-12: Ensure that WORKDIR values are absolute paths

(CKV_DOCKER_10)

🪛 Hadolint (2.14.0)

[error] 12-12: Use absolute WORKDIR

(DL3000)

🤖 Prompt for AI Agents
In Dockerfile at line 12, the WORKDIR is set to a relative path
("apps/price_pusher"); change it to an absolute path (for example
"/apps/price_pusher" or the repository canonical app root such as
"/usr/src/app/apps/price_pusher") so the Docker image uses an unambiguous
working directory; update the WORKDIR line to the chosen absolute path.

CMD ["bash", "-c", "npm run start evm -- \
--price-config-file ./price-config.stable.sample.yaml \
--endpoint \"${ENDPOINT}\" \
--pyth-contract-address \"${PYTH_CONTRACT_ADDRESS}\" \
--price-service-endpoint \"${PRICE_SERVICE_ENDPOINT}\" \
--mnemonic-file <(echo \"${MNEMONIC}\") \
--pushing-frequency \"${PUSHING_FREQUENCY:-300}\" \
--polling-frequency \"${POLLING_FREQUENCY:-5}\" \
--override-gas-price-multiplier \"${GAS_PRICE_MULTIPLIER:-1.1}\""]
Comment on lines +1 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Add HEALTHCHECK instruction for container monitoring.

A HEALTHCHECK instruction allows Docker and orchestration platforms to monitor the health of the running container and restart it if necessary.

Consider adding a health check appropriate for your application:

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node healthcheck.js || exit 1

Alternatively, if the price pusher exposes an HTTP endpoint, use a curl-based health check:

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:PORT/health || exit 1
🧰 Tools
🪛 Checkov (3.2.334)

[low] 10-10: Ensure that COPY is used instead of ADD in Dockerfiles

(CKV_DOCKER_4)


[low] 12-12: Ensure that WORKDIR values are absolute paths

(CKV_DOCKER_10)


[low] 1-21: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-21: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)

[error] 10-10: Use COPY instead of ADD for files and folders

(DL3020)


[error] 12-12: Use absolute WORKDIR

(DL3000)

🤖 Prompt for AI Agents
Dockerfile lines 1-21: add a HEALTHCHECK instruction near the end of the
Dockerfile so container orchestrators can detect and restart unhealthy
containers; implement either a lightweight node-based check (add a small
healthcheck.js to the app and ensure it’s copied into the image, then add a
HEALTHCHECK that runs node healthcheck.js with sensible
--interval/--timeout/--start-period/--retries) or an HTTP check (ensure the
service listens on a known PORT and add a HEALTHCHECK that curls the local
/health endpoint with the same timing options); place the HEALTHCHECK after
CMD/ENTRYPOINT or at the end of the file and document the required health
endpoint/script and port in the repo README.

⚠️ Potential issue | 🟠 Major

Security: Add a non-root USER directive.

The container runs as root by default, which poses a security risk. Create and switch to a non-privileged user before running the application.

Add a non-root user:

 WORKDIR /price-pusher
 COPY . .
+RUN groupadd -r appuser && useradd -r -g appuser appuser
+RUN chown -R appuser:appuser /price-pusher

+USER appuser
 WORKDIR /price-pusher/apps/price_pusher

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Checkov (3.2.334)

[low] 10-10: Ensure that COPY is used instead of ADD in Dockerfiles

(CKV_DOCKER_4)


[low] 12-12: Ensure that WORKDIR values are absolute paths

(CKV_DOCKER_10)


[low] 1-21: Ensure that HEALTHCHECK instructions have been added to container images

(CKV_DOCKER_2)


[low] 1-21: Ensure that a user for the container has been created

(CKV_DOCKER_3)

🪛 Hadolint (2.14.0)

[error] 10-10: Use COPY instead of ADD for files and folders

(DL3020)


[error] 12-12: Use absolute WORKDIR

(DL3000)

🤖 Prompt for AI Agents
In Dockerfile around lines 1 to 21, the image runs as root by default; create a
non-privileged user, set its home/workdir ownership and switch to it before CMD
to reduce attack surface. Add steps to: create a user and group (non-root), set
appropriate ownership (chown) of /price-pusher and apps/price_pusher so the new
user can read/write, set HOME and USER to that non-root account, and switch to
that USER before the CMD; ensure any files or ports the process needs are
accessible by that user and avoid running privileged setup commands after
switching.

243 changes: 224 additions & 19 deletions apps/price_pusher/price-config.stable.sample.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,224 @@
- alias: BTC/USD
id: e62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43
time_difference: 60
price_deviation: 0.5
confidence_ratio: 100
- alias: BNB/USD
id: 2f95862b045670cd22bee3114c39763a4a08beeb663b145d283c31d7d1101c4f
time_difference: 60
price_deviation: 1
confidence_ratio: 100
early_update:
time_difference: 30
price_deviation: 0.5
confidence_ratio: 10
- alias: PYTH/USD
id: 0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff
time_difference: 60
price_deviation: 0.5
confidence_ratio: 100
- alias: GOOG/USD
id: e65ff435be42630439c96396653a342829e877e2aafaeaf1a10d0ee5fd2cf3f2
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Incorrect comment persists despite prior fix claim.

The comment "0.05% deviation" appears on all price_deviation: 0.05 lines throughout the file, but a value of 0.05 represents 5%, not 0.05%. Past review comments indicate this was addressed in commit c345fbf, yet the incorrect comments remain in the current code. This mismatch will confuse operators tuning thresholds and risks misconfiguration.

Apply this diff to fix all occurrences:

-  price_deviation: 0.05   # 0.05% deviation trips a push
+  price_deviation: 0.05   # 5% deviation trips a push

Repeat for all 26 entries in the file.

Also applies to: 12-12, 20-20, 28-28, 36-36, 44-44, 52-52, 60-60, 68-68, 76-76, 84-84, 92-92, 100-100, 108-108, 116-116, 124-124, 132-132, 140-140, 148-148, 156-156, 164-164, 172-172, 180-180, 188-188, 196-196, 204-204

🤖 Prompt for AI Agents
In apps/price_pusher/price-config.stable.sample.yaml around lines
4,12,20,28,36,44,52,60,68,76,84,92,100,108,116,124,132,140,148,156,164,172,180,188,196,204,
the inline comment for price_deviation: 0.05 incorrectly reads "0.05% deviation"
even though the value 0.05 represents 5% (0.05 == 5%), so update each comment to
read "5% deviation" (or "0.05 = 5% deviation") to accurately reflect the numeric
meaning and avoid operator confusion; make this change for all 26 occurrences
listed.

confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: AMZN/USD
id: b5d0e0fa58a1f8b81498ae670ce93c872d14434b72c364885d4fa1b257cbb07a
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: AMZN/USD.PRE
id: 82c59e36a8e0247e15283748d6cd51f5fa1019d73fbf3ab6d927e17d9e357a7f
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: AMZN/USD.POST
id: 62731dfcc8b8542e52753f208248c3e73fab2ec15422d6f65c2decda71ccea0d
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: AAPL/USD
id: 49f6b65cb1de6b10eaf75e7c03ca029c306d0357e91b5311b175084a5ad55688
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: MSFT/USD
id: d0ca23c1cc005e004ccf1db5bf76aeb6a49218f43dac3d4b275e92de12ded4d1
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: TSLA/USD
id: 16dad506d7db8da01c87581c87ca897a012a153557d4d578c3b9c9e1bc0632f1
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: TSLA/USD.PRE
id: 42676a595d0099c381687124805c8bb22c75424dffcaa55e3dc6549854ebe20a
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: TSLA/USD.POST
id: 2a797e196973b72447e0ab8e841d9f5706c37dc581fe66a0bd21bcd256cdb9b9
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: NVDA/USD
id: b1073854ed24cbc755dc527418f52b7d271f6cc967bbf8d8129112b18860a593
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: NVDA/USD.PRE
id: 61c4ca5b9731a79e285a01e24432d57d89f0ecdd4cd7828196ca8992d5eafef6
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: NVDA/USD.POST
id: 25719379353a508b1531945f3c466759d6efd866f52fbaeb3631decb70ba381f
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: META/USD
id: 78a3e3b8e676a8f73c439f5d749737034b139bbbe899ba5775216fba596607fe
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: GME/USD
id: 6f9cd89ef1b7fd39f667101a91ad578b6c6ace4579d5f7f285a4b06aa4504be6
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: MSTR/USD
id: e1e80251e5f5184f2195008382538e847fafc36f751896889dd3d1b1f6111f09
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: MSTR/USD.PRE
id: 1a11eb21c271f3127e4c9ec8a0e9b1042dc088ccba7a94a1a7d1aa37599a00f6
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: MSTR/USD.POST
id: d8b856d7e17c467877d2d947f27b832db0d65b362ddb6f728797d46b0a8b54c0
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: BRKB/USD
id: e21c688b7fc65b4606a50f3635f466f6986db129bf16979875d160f9c508e8c7
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: SPLG/USD
id: 4dfbf28d72ab41a878afcd4c6d5e9593dca7cf65a0da739cbad9b7414004f82d
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: IAU/USD
id: f703fbded84f7da4bd9ff4661b5d1ffefa8a9c90b7fa12f247edc8251efac914
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: COIN/USD
id: fee33f2a978bf32dd6b662b65ba8083c6773b494f8401194ec1870c640860245
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: COIN/USD.PRE
id: 8bdee6bc9dc5a61b971e31dcfae96fc0c7eae37b2604aa6002ad22980bd3517c
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: COIN/USD.POST
id: 5c3bd92f2eed33779040caea9f82fac705f5121d26251f8f5e17ec35b9559cd4
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: SIVR/USD
id: 0a5ee42b0f7287a777926d08bc185a6a60f42f40a9b63d78d85d4a03ee2e3737
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: CRCL/USD
id: 92b8527aabe59ea2b12230f7b532769b133ffb118dfbd48ff676f14b273f1365
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: CRCL/USD.PRE
id: b6ce1644a22bb348f89a81696141c1caaca5e7ea83de289a44fba1a9897ca2d6
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: CRCL/USD.POST
id: 9bdba52fbb3d588d573928b1e781c6441e446a83c011fed92d8362c5b309ce02
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
- alias: PPLT/USD
id: 782410278b6c8aa2d437812281526012808404aa14c243f73fb9939eeb88d430
time_difference: 300 # pushes if on-chain is >5min behind
price_deviation: 0.05 # 0.05% deviation trips a push
confidence_ratio: 200 # effectively ignore this trigger
early_update:
time_difference: 150
price_deviation: 0.03
10 changes: 10 additions & 0 deletions apps/price_pusher/src/evm/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,16 @@ export default {
logger.child({ module: "PythPriceListener" }),
);

// Start the price listener and wait for first update
await pythListener.start();
const receivedUpdate = await pythListener.waitForFirstPriceUpdate(15000);

if (receivedUpdate) {
console.log('Price update received!');
} else {
console.log('Timeout waiting for price update');
}

Comment on lines +153 to +162
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use structured logging and decide behavior on timeout.

Replace console.log with the existing pino logger for consistency, and make the timeout case explicit (warn or exit) to avoid silent degraded startup.

-    if (receivedUpdate) {
-      console.log('Price update received!');
-    } else {
-      console.log('Timeout waiting for price update');
-    }
+    if (receivedUpdate) {
+      logger.info('First Pyth price update received.');
+    } else {
+      logger.warn('Timeout waiting for first Pyth price update after 15s; continuing startup.');
+      // Optionally: return process.exit(1) if startup must fail without data
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Start the price listener and wait for first update
await pythListener.start();
const receivedUpdate = await pythListener.waitForFirstPriceUpdate(15000);
if (receivedUpdate) {
console.log('Price update received!');
} else {
console.log('Timeout waiting for price update');
}
// Start the price listener and wait for first update
await pythListener.start();
const receivedUpdate = await pythListener.waitForFirstPriceUpdate(15000);
if (receivedUpdate) {
logger.info('First Pyth price update received.');
} else {
logger.warn('Timeout waiting for first Pyth price update after 15s; continuing startup.');
// Optionally: return process.exit(1) if startup must fail without data
}
🤖 Prompt for AI Agents
In apps/price_pusher/src/evm/command.ts around lines 153 to 162, replace the
console.log calls with the module's pino logger instance (use the existing
logger variable) and make the timeout explicit: log a success with logger.info
when an update is received, and when waitForFirstPriceUpdate times out log
logger.warn (or logger.error if you prefer failing fast) with context, then
decide behavior—either throw an error or call process.exit(1) to fail startup
instead of silently continuing; update the code accordingly so logging is
consistent and the timeout path is explicit and handled.

const client = await createClient(endpoint, mnemonic);
const pythContract = createPythContract(client, pythContractAddress);

Expand Down
15 changes: 10 additions & 5 deletions apps/price_pusher/src/evm/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ export class EvmPricePusher implements IPricePusher {
await (this.customGasStation?.getCustomGasPrice() ??
this.client.getGasPrice()),
);

this.logger.debug(`Initial gas price: ${gasPrice} gwei`);

Comment on lines +196 to 198
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Gas price unit mismatch in logs.

getGasPrice returns wei; logs label it as gwei. Either log in wei or convert for readability.

-    this.logger.debug(`Initial gas price: ${gasPrice} gwei`);
+    const gasPriceGwei = gasPrice / 1e9;
+    this.logger.debug(`Initial gas price: ${gasPriceGwei} gwei (${gasPrice} wei)`);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/price_pusher/src/evm/evm.ts around lines 196-198, the logged "Initial
gas price" is labeled as gwei but getGasPrice returns wei; change the log to
either convert the wei value to gwei before logging (e.g., using BigNumber
division by 1e9 or ethers.utils.formatUnits(gasPrice, "gwei")) or update the
label to "wei" if you want to log the raw value, ensuring correct units are
displayed.

// Try to re-use the same nonce and increase the gas if the last tx is not landed yet.
if (this.pusherAddress === undefined) {
Expand Down Expand Up @@ -227,7 +229,7 @@ export class EvmPricePusher implements IPricePusher {

const txNonce = lastExecutedNonce + 1;

this.logger.debug(`Using gas price: ${gasPrice} and nonce: ${txNonce}`);
this.logger.debug(`Final gas price: ${gasPrice} gwei, nonce: ${txNonce}, update fee: ${updateFee} wei`);

const pubTimesToPushParam = pubTimesToPush.map((pubTime) =>
BigInt(pubTime),
Expand All @@ -242,17 +244,20 @@ export class EvmPricePusher implements IPricePusher {
};

try {
const gasLimitToUse = this.gasLimit !== undefined
? BigInt(Math.ceil(this.gasLimit))
: BigInt(1000000); // Default gas limit of 1M gas units

this.logger.debug(`Using gas limit: ${gasLimitToUse}, gas price: ${gasPrice}, update fee: ${updateFee}`);

Comment on lines +247 to +252
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid forcing gas in simulation; apply gas limit on submission.

Providing a fixed gas in simulate can cause false reverts if it’s too low/high. Let simulate estimate gas; set the cap when sending.

-      const gasLimitToUse = this.gasLimit !== undefined
-        ? BigInt(Math.ceil(this.gasLimit))
-        : BigInt(1000000); // Default gas limit of 1M gas units
-      
-      this.logger.debug(`Using gas limit: ${gasLimitToUse}, gas price: ${gasPrice}, update fee: ${updateFee}`);
+      const gasLimitToUse = this.gasLimit !== undefined
+        ? BigInt(Math.ceil(this.gasLimit))
+        : undefined; // Let simulate/chain estimate if not provided
+      
+      this.logger.debug(
+        `Using gas limit: ${gasLimitToUse ?? 'estimate'}, gas price: ${gasPrice}, update fee: ${updateFee}`
+      );

And below:

-          {
-            value: updateFee,
-            gasPrice: BigInt(Math.ceil(gasPrice)),
-            nonce: txNonce,
-            gas: gasLimitToUse,
-          },
+          {
+            value: updateFee,
+            gasPrice: BigInt(Math.ceil(gasPrice)),
+            nonce: txNonce,
+          },
         );
 
-      this.logger.debug({ request }, "Simulated request successfully");
-
-      const hash = await this.client.writeContract(request);
+      const requestWithGas =
+        gasLimitToUse !== undefined ? { ...request, gas: gasLimitToUse } : request;
+      this.logger.debug({ request: requestWithGas }, "Simulated request successfully");
+
+      const hash = await this.client.writeContract(requestWithGas);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const gasLimitToUse = this.gasLimit !== undefined
? BigInt(Math.ceil(this.gasLimit))
: BigInt(1000000); // Default gas limit of 1M gas units
this.logger.debug(`Using gas limit: ${gasLimitToUse}, gas price: ${gasPrice}, update fee: ${updateFee}`);
// let the chain estimate gas when no explicit limit is set
const gasLimitToUse = this.gasLimit !== undefined
? BigInt(Math.ceil(this.gasLimit))
: undefined; // Let simulate/chain estimate if not provided
this.logger.debug(
`Using gas limit: ${gasLimitToUse ?? 'estimate'}, gas price: ${gasPrice}, update fee: ${updateFee}`
);
// … earlier: await this.client.simulateContract(request,
// {
// value: updateFee,
// gasPrice: BigInt(Math.ceil(gasPrice)),
// nonce: txNonce,
{
value: updateFee,
gasPrice: BigInt(Math.ceil(gasPrice)),
nonce: txNonce,
},
);
// apply the cap only on the actual write
const requestWithGas =
gasLimitToUse !== undefined ? { ...request, gas: gasLimitToUse } : request;
this.logger.debug({ request: requestWithGas }, "Simulated request successfully");
const hash = await this.client.writeContract(requestWithGas);
// …
🤖 Prompt for AI Agents
In apps/price_pusher/src/evm/evm.ts around lines 247-252 the code forces a gas
value into the simulation step which can cause false reverts; change the flow so
simulation uses the provider's gas estimation (do not set gas/gasLimit for
simulate), and only apply the computed gasLimitToUse as a cap when constructing
the actual transaction for submission (e.g., pass gasLimitToUse into the
send/submit call or tx overrides). Keep the gasLimit calculation
(BigInt(Math.ceil(...) or default) and the debug log, but remove passing that
value into the simulation API and ensure it is used solely as the override on
the final send.

const { request } =
await this.pythContract.simulate.updatePriceFeedsIfNecessary(
[priceFeedUpdateDataWith0x, priceIdsWith0x, pubTimesToPushParam],
{
value: updateFee,
gasPrice: BigInt(Math.ceil(gasPrice)),
nonce: txNonce,
gas:
this.gasLimit !== undefined
? BigInt(Math.ceil(this.gasLimit))
: undefined,
gas: gasLimitToUse,
},
);

Expand Down
Loading
Loading