Skip to content

👽️ server: resolve panda controller dynamically - #1355

Merged
cruzdanilo merged 1 commit into
mainfrom
panda-controller
Sep 30, 2026
Merged

cruzdanilo merged 1 commit into
mainfrom
panda-controller

Conversation

@nfmelendez

@nfmelendez nfmelendez commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • Bug Fixes
    • Refunds now use the controller configured for the active network instead of a fixed address, improving compatibility across supported networks.
    • When no matching controller is available, refund processing stops with a clear error rather than retrying or attempting to send the refund.

@changeset-bot

changeset-bot Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b1e424f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@exactly/server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: fb7380b8-459f-43f5-96d0-06a961167567

📥 Commits

Reviewing files that changed from the base of the PR and between 2e9393a and b1e424f.

📒 Files selected for processing (6)
  • .changeset/brave-otters-resolve.md
  • server/test/mocks/panda.ts
  • server/test/utils/panda.test.ts
  • server/test/workers/refund.test.ts
  • server/utils/panda.ts
  • server/workers/refund/worker.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: ada14f75-5e59-47ad-9703-d195f8ac9fb8

📥 Commits

Reviewing files that changed from the base of the PR and between a52f261 and 2e9393a.

📒 Files selected for processing (6)
  • .changeset/brave-otters-resolve.md
  • server/test/mocks/panda.ts
  • server/test/utils/panda.test.ts
  • server/test/workers/refund.test.ts
  • server/utils/panda.ts
  • server/workers/refund/worker.ts

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

Refund processing now retrieves Panda tenant contract metadata and selects the version 1 controller for the configured chain. If no matching controller exists, processing fails with an unrecoverable error.

Changes

Refund Controller Resolution

Layer / File(s) Summary
Retrieve Panda contract metadata
server/utils/panda.ts, server/test/mocks/panda.ts, server/test/utils/panda.test.ts
The Panda client exposes getContracts(), which requests and validates tenant contract records. Tests check the endpoint and normalized contract fields.
Select controller for refund
server/workers/refund/worker.ts, server/test/workers/refund.test.ts, .changeset/brave-otters-resolve.md
The refund worker retrieves contract metadata alongside withdrawal parameters, selects the configured chain’s version 1 controller, and uses its address for the withdrawal. Tests cover the controller lookup and missing-controller failure. A changeset declares a patch release for @exactly/server.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~15 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant RefundWorker
  participant PandaClient
  participant PandaAPI
  participant Controller
  RefundWorker->>PandaClient: Request tenant contracts
  PandaClient->>PandaAPI: GET /issuing/tenants/contracts
  PandaAPI-->>PandaClient: Return contract records
  PandaClient-->>RefundWorker: Return validated contract records
  RefundWorker->>Controller: Send withdrawal call to selected controller
Loading

Merge Risk: ⚪ Minimal · up to 2e939

Refund processing now looks up the controller from Panda contract metadata instead of a hard-coded address map, and fails safely when no controller matches. No merge-blocking risk was identified.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 2e939

Dynamic controller discovery gives Panda’s tenant metadata authority over a privileged refund call destination. Chain and version checks reject missing matches, but do not establish that a returned address is an approved controller. Existing authentication, amount checks, and transaction ordering limit exposure; upstream metadata policy and deployed contract protections remain unverified.

Retained concerns

  • Medium · security · inferred: The PR delegates refund controller identity to external metadata without a demonstrated semantic authorization boundary. A matching record with a syntactically valid but incorrect or malicious address becomes a call target of the keeper-enabled refunder account. Missing-match rejection does not reject such a record, and proxyAddress is not cross-checked against withdrawal parameters. This introduces target-redirection exposure if the metadata authority is compromised or misconfigured; exploitability and asset impact depend on unverified upstream policy and deployed contract controls.
Security review details

Security Blast Radius

  • inferred — Target-authority exposure is bounded to refunds processed with the affected Panda credentials and configured chain. A shared metadata record can affect multiple refund jobs using that configuration. The executing refunder account is checked for KEEPER_ROLE during readiness; broader tenant, environment, balance, allowance, or downstream privilege exposure was not established.

Security Findings and Attack Paths

  • inferred — The newly enabled conditional path is control of a matching metadata record, followed by selection of its address and execution of withdrawal calldata against it through the privileged refunder account. This requires influence over the metadata authority or its response, not merely ordinary webhook fields. No verified theft, privilege escalation, or deployed-control bypass is established; the previous static mapping did not delegate target identity this way.

Trust Boundaries and Controls

  • observed — Existing controls include webhook signature validation, API-key-bearing Panda requests, locally issuer-signed refund jobs, worker amount checks, and simulation before signing. Both batch calls carry zero native value, and missing controller metadata prevents submission. These controls do not themselves authenticate the selected address as an approved deployed controller. Panda already supplied withdrawal parameters before this PR.

Resilience and Maintainability Implications

  • inferred — Within one wallet attempt, retransmission uses the same serialized transaction. Across queue retries or interruption before submission, the worker refetches metadata and may choose a different controller if the registry changes; no controller snapshot links those attempts. Hash persistence, receipt-triggered hook enqueue, and Replay error handling remain present. Concurrent metadata and withdrawal requests also lack a demonstrated shared snapshot or authorization cleanup contract, so no orphaned reservation is asserted.

Hardening Proposals

  • proposed — Define and verify an authoritative controller approval contract for chain, version, and proxy identity. Possible controls include an approved registry, rejection of duplicate matches, and binding withdrawal parameters to the selected record. Establish metadata stability across retries and document recovery for missing-controller failures, including cleanup only if withdrawal authorization has durable side effects.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: resolving the Panda controller dynamically in the server refund flow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
✨ Simplify code
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.05%. Comparing base (e885fce) to head (b1e424f).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1355      +/-   ##
==========================================
+ Coverage   71.29%   72.05%   +0.76%     
==========================================
  Files         303      304       +1     
  Lines       12858    12904      +46     
  Branches     4761     4788      +27     
==========================================
+ Hits         9167     9298     +131     
+ Misses       3450     3365      -85     
  Partials      241      241              
Flag Coverage Δ
e2e 71.74% <50.00%> (+0.64%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@nfmelendez

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: b1e424f9db

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@cruzdanilo
cruzdanilo merged commit b1e424f into main Sep 30, 2026
13 of 14 checks passed
@cruzdanilo
cruzdanilo deleted the panda-controller branch September 30, 2026 17:59

This branch had an error being deployed

1 failed and 1 active deployments
test — b1e424f9 Deployed Sep 30, 2026 by cruzdanilo via test #14454
version — b1e424f9 Deployed Sep 30, 2026 by cruzdanilo via version #1024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants