Skip to content

Feat/validate referral token account#48

Open
codewithgun wants to merge 6 commits intorelease_0.2.2from
feat/validate-referral-token-account
Open

Feat/validate referral token account#48
codewithgun wants to merge 6 commits intorelease_0.2.2from
feat/validate-referral-token-account

Conversation

@codewithgun
Copy link
Contributor

@codewithgun codewithgun commented Mar 2, 2026

Context

Referral fee blocking on protocol fee zap to avoid operator steal fee.

Other changes

  • Typo fix (cosmetic) ProtozolZapError → ProtocolZapError — renamed across all files
  • Moved validation of whitelisted swap steps into validate_route_plan because validation of referral fee require the traversal of swap steps. Thus, reduced duplicated checking.

Pending todo

  • Update DLMM, DAMM v1, v2, and DBC protocol zap dependency version.

@codewithgun
Copy link
Contributor Author

/bot review

@metoeraag-bot
Copy link

metoeraag-bot bot commented Mar 2, 2026

Bot Agent progress: /bot review

Progress:

  • Repo checks (5 ok, 0 failed)
  • Context build
  • Codex review (1 pass + first look)
  • Buddy review (agreed after 2/10)
  • Post review

Copy link

@metoeraag-bot metoeraag-bot bot left a comment

Choose a reason for hiding this comment

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

Summary

Retain all five findings: (1) confirmed unused Pubkey import warning in damm_v2_zap.rs; (2) referral account index constants are brittle against upstream instruction-layout drift and merit regression tests; (3) DAMM V2 no-referral sentinel check currently assumes program ID and should be verified/documented against authoritative source/IDL; (4) same sentinel-verification/documentation need for DLMM; and (5) moving Jupiter platform_fee_bps enforcement out of public validate_payload creates a potential call-order bypass unless the invariant is enforced there too or call order is guaranteed/documented.

Inline comments

See inline comments on the diff.

Potential concerns (lower confidence)
  • protocol-zap/src/processors/dlmm_zap.rs:42 Same sentinel concern as DAMM V2: this check compares the referral account key to the DLMM program ID. Please confirm from DLMM source/IDL that this is the actual no-referral sentinel value and document it inline; otherwise adjust the comparison to the correct convention.
Claude (API) review

Rounds: 2 (min=1, max=10).
First look: Codex + Claude (API).
Agreement: yes (no new findings/questions).

Debate transcript

First look comparison

Codex (first look):

Summary:
Referral-fee validation integration looks mostly consistent across processors (trait changes, constructor parsing for Jupiter, and centralized validation call path in extract_amm_accounts_and_info). I only found one concrete cleanup item and one robustness risk tied to hardcoded AMM account indices.

Inline comment highlights:

  • protocol-zap/src/processors/damm_v2_zap.rs:1: Pubkey is imported but not used in this file (also visible in cargo check warnings). Please remove the unused import so warnings stay clean and future warnings remain noticeable.
  • protocol-zap/src/constants.rs:15: The new referral account index constants are tightly coupled to DLMM/DAMM instruction account ordering. With dependency version updates already noted as pending, these can drift and make ensure_no_referral_fee validate the wrong account (

Claude (API) (first look):

Summary:
PR adds referral fee validation to prevent operators from stealing protocol fees via AMM referral accounts during zap-out. Also renames ProtozolZapErrorProtocolZapError. The DLMM and DAMM v2 referral checks compare the referral token account key against the program ID, which seems like an incorrect sentinel value — needs verification.

Inline comment highlights:

  • protocol-zap/src/processors/damm_v2_zap.rs:42: The referral token account key is compared against zap_sdk::constants::DAMM_V2.to_bytes() (the DAMM V2 program ID). This means the check passes only if the referral account slot contains the program's own address. Is this actually the s
  • protocol-zap/src/processors/dlmm_zap.rs:42: Same concern as DAMM v2: the referral token account key is compared against zap_sdk::constants::DLMM.to_bytes() (the DLMM program ID). Is the DLMM program ID genuinely the sentinel value passed in the referral account slot when no refer
  • protocol-zap/src/processors/jup_v6_zap.rs:93: The platform_fee_bps != 0 check was previously in validate_payload and has been moved to ensure_no_referral_fee. However, validate_payload is called separately from ensure_no_referral_fee. If a caller invokes only `validate_payloa
  • protocol-zap/src/processors/damm_v2_zap.rs:1: There's a cargo warning about an unused import pubkey::Pubkey in this file (visible in the cargo check output). The Pubkey import on line 1 is used on line 42 implicitly via the .to_bytes() comparison, but the compiler disagrees — p
  • protocol-zap/src/lib.rs:2: The cargo check output shows warning: unused import: pubkey::Pubkey in protocol-zap/src/processors/damm_v2_zap.rs:1. Meanwhile in lib.rs, IntrospectedInstruction is imported but only used in the trait definition. This is fine, but
  • protocol-zap/src/utils/mod.rs:212: The get_account_index_in_instruction helper hardcodes ZAP_OUT_ACCOUNTS_LEN = 2 as a local constant inside the function. If ZapOutCtx ever gains or loses an account, this will silently break referral index lookups and other account ref

Comparison notes:

Synthesis of Reviews

  • No major direct disagreement, but different severity framing:

    • Review A: mostly consistent integration, minor cleanup + robustness caution.
    • Review B: potential correctness/security bug (referral account compared to AMM program ID sentinel).
  • Index fragility scope differs:

    • Review A focuses on referral index constants in constants.rs drifting with upstream account ordering.
    • Review B adds a second fragility point: local hardcoded ZAP_OUT_ACCOUNTS_LEN = 2 in get_account_index_in_instruction.
  • Validation-path confidence differs:

    • Review A praises centralized ensure_no_referral_fee flow.
    • Review B warns moving platform_fee_bps != 0 from validate_payload may leave gaps if callers invoke only validate_payload.

Most important follow-up action:
Verify and fix the DLMM/DAMM “no referral” sentinel logic (program ID vs intended sentinel), then add regression tests covering referral checks and call-path invariants.

Round 1

Codex (primary):

Summary:
Referral-fee validation integration looks mostly consistent across processors (trait changes, constructor parsing for Jupiter, and centralized validation call path in extract_amm_accounts_and_info). I only found one concrete cleanup item and one robustness risk tied to hardcoded AMM account indices.

Inline comment highlights:

  • protocol-zap/src/processors/damm_v2_zap.rs:1: Pubkey is imported but not used in this file (also visible in cargo check warnings). Please remove the unused import so warnings stay clean and future warnings remain noticeable.
  • protocol-zap/src/constants.rs:15: The new referral account index constants are tightly coupled to DLMM/DAMM instruction account ordering. With dependency version updates already noted as pending, these can drift and make ensure_no_referral_fee validate the wrong account (

Claude (API):

Critique of Primary Review

The primary review correctly identified the unused Pubkey import and the fragility of hardcoded account index constants. Both are valid findings.

However, the primary review missed the most important issue in this PR: the sentinel value used in the DLMM and DAMM V2 referral fee checks. Lines 42 in both damm_v2_zap.rs and dlmm_zap.rs compare the referral token account key against the respective AMM program ID. This is the security-critical logic that the entire PR exists to add, and it needs explicit verification that the AMM programs actually use their own program ID as a placeholder when no referral is provided. If this assumption is wrong, the referral fee blocking either doesn't work (false negatives allowing theft) or rejects all valid transactions (false positives breaking functionality).

The primary review also missed the subtle API contract change where platform_fee_bps validation was moved out of validate_payload into ensure_no_referral_fee for Jupiter processors, potentially leaving a gap if validate_payload is called in isolation.

The unused import finding and index constant fragility comments are both valid and worth keeping.

Codex (response):

  • New findings applied: 3/3
  • Open questions kept for author: 2/2

Round 2

Codex (primary):

Summary:
Kept the two original findings (unused import cleanup and account-index drift risk) and added three critic-identified issues: both DAMM V2 and DLMM referral checks assume the AMM program ID is the no-referral sentinel and need authoritative verification/documentation, and Jupiter’s platform_fee_bps guard was moved out of validate_payload, which can be bypassed if that public method is called in isolation.

Inline comment highlights:

  • protocol-zap/src/processors/damm_v2_zap.rs:1: Pubkey is imported but not used in this file (also visible in cargo check warnings). Please remove the unused import so warnings stay clean and future warnings remain noticeable.
  • protocol-zap/src/constants.rs:15: The new referral account index constants are tightly coupled to DLMM/DAMM instruction account ordering. With dependency version updates already noted as pending, these can drift and make ensure_no_referral_fee validate the wrong account (
  • protocol-zap/src/processors/damm_v2_zap.rs:42: Potential correctness/security issue: this compares the referral token account key to DAMM_V2.to_bytes() (the DAMM V2 program ID), which assumes DAMM V2 uses its own program ID as the sentinel when no referral is set. Please verify this a
  • protocol-zap/src/processors/dlmm_zap.rs:42: Same sentinel concern as DAMM V2: this check compares the referral account key to the DLMM program ID. Please confirm from DLMM source/IDL that this is the actual no-referral sentinel value and document it inline; otherwise adjust the compa
  • protocol-zap/src/processors/jup_v6_zap.rs:93: platform_fee_bps != 0 was moved from validate_payload to ensure_no_referral_fee. Since validate_payload is a public trait method, callers invoking it alone would no longer enforce this invariant. Consider keeping the check in `valid

Claude (API):

The primary review now covers all significant issues identified across both prior critique rounds and the independent first-look review:

  1. Sentinel value verification (DAMM V2 line 42, DLMM line 42) — correctly flagged and awaiting author confirmation.
  2. platform_fee_bps guard moved out of validate_payload (Jupiter line 93) — correctly flagged as defense-in-depth concern.
  3. Unused Pubkey import — minor cleanup, correctly flagged.
  4. Account index constant drift risk — correctly flagged in constants.rs.

The ZAP_OUT_ACCOUNTS_LEN = 2 hardcoded constant fragility (from utils/mod.rs:212) was raised as a question in the prior critique and is implicitly covered by the broader index-drift concern in constants.rs. No additional high-signal findings remain that the primary review hasn't already addressed or that are pending author response.

All three prior critic findings were applied and both open questions were kept. No false positives to retract. The review is comprehensive for this PR's scope.

Codex (response):

Agreement reached. No further changes.

Synthesis

Synthesis of Reviews

  • No major direct disagreement, but different severity framing:

    • Review A: mostly consistent integration, minor cleanup + robustness caution.
    • Review B: potential correctness/security bug (referral account compared to AMM program ID sentinel).
  • Index fragility scope differs:

    • Review A focuses on referral index constants in constants.rs drifting with upstream account ordering.
    • Review B adds a second fragility point: local hardcoded ZAP_OUT_ACCOUNTS_LEN = 2 in get_account_index_in_instruction.
  • Validation-path confidence differs:

    • Review A praises centralized ensure_no_referral_fee flow.
    • Review B warns moving platform_fee_bps != 0 from validate_payload may leave gaps if callers invoke only validate_payload.

Most important follow-up action:
Verify and fix the DLMM/DAMM “no referral” sentinel logic (program ID vs intended sentinel), then add regression tests covering referral checks and call-path invariants.

Repo checks

Repo Checks

  • LLM checks planner: added package install step before running JS commands.

  • rustup component add --toolchain 1.85.0-x86_64-unknown-linux-gnu rustfmt: ok

info: downloading component 'rustfmt'
info: installing component 'rustfmt'
  • cargo fetch --locked: ok
Updating git repository `https://github.com/MeteoraAg/damm-v2`
From https://github.com/MeteoraAg/damm-v2
 * [new ref]         d9cef5aaec9cfa1a6d3b0b28d213c87c285127de -> refs/commit/d9cef5aaec9cfa1a6d3b0b28d213c87c285127de
 Downloading crates ...
  Downloaded anyhow v1.0.98
  Downloaded solana-curve25519 v2.3.5
  Downloaded solana-sysvar v2.2.2
  Downloaded bytemuck_derive v1.10.0
  Downloaded winnow v0.7.12
  Downloaded indexmap v2.10.0
  Downloaded cc v1.2.30
  Downloaded pest v2.8.3
  Downloaded ruint v1.16.0
  Downloaded redox_syscall v0.5.14
  Downloaded serde_json v1.0.141
  Downloaded solana-zk-sdk v2.3.5
  • pnpm install --frozen-lockfile: ok
Lockfile is up to date, resolution step is skipped
Progress: resolved 1, reused 0, downloaded 0, added 0
Packages: +199
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 199, reused 195, downloaded 4, added 199, done

dependencies:
+ @coral-xyz/anchor 0.31.1
+ @solana/spl-token 0.4.13
+ @solana/web3.js 1.98.2
+ babar 0.2.3
+ borsh 2.0.0
+ litesvm 0.1.0

devDependencies:
+ @meteora-ag/cp-amm-sdk 1.2.3
+ @types/bn.js 5.2.0
+ @types/chai 4.3.20
+ @types/mocha 9.1.1
+ chai 4.5.0
+ mocha 9.2.2
+ prettier 2.8.8
+ ts-mocha 10.1.0
+ typescript 5.8.3

╭ Warning ─────────────────────────────────────────────────────────────────────╮
│                                                                              │
│   Ignored build scripts: bigint-buffer@1.1.5, bufferutil@4.0.9,              │
│   utf-8-validate@5.0.10.                                                     │
│   Run "pnpm approve-builds" to pick which dependencies should be allowed     │
│   to run scripts.                                                            │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
Done in 1.2s using pnpm v10.28.2

! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-10.28.2.tgz
  • cargo check --workspace: ok
1
    Checking spl-pod v0.5.1
    Checking spl-token-confidential-transfer-ciphertext-arithmetic v0.2.1
    Checking spl-token-confidential-transfer-proof-generation v0.2.0
    Checking spl-token v7.0.0
    Checking spl-type-length-value v0.7.0
    Checking spl-token-confidential-transfer-proof-extraction v0.2.1
    Checking spl-token-group-interface v0.5.0
    Checking spl-tlv-account-resolution v0.9.0
    Checking spl-elgamal-registry v0.1.1
    Checking spl-token-metadata-interface v0.6.0
    Checking spl-transfer-hook-interface v0.9.0
    Checking spl-token-2022 v6.0.0
    Checking anchor-lang v0.31.1
    Checking jupiter v0.1.0 (/data/workdir/MeteoraAg/zap-program/libs/jupiter)
    Checking dlmm v0.10.1 (/data/workdir/MeteoraAg/zap-program/libs/dlmm)
    Checking spl-associated-token-account v6.0.0
    Checking protocol-zap v0.1.0 (/data/workdir/MeteoraAg/zap-program/protocol-zap)
warning: unused import: `pubkey::Pubkey`
 --> protocol-zap/src/processors/damm_v2_zap.rs:1:17
  |
1 | use pinocchio::{pubkey::Pubkey, sysvars::instructions::IntrospectedInstruction};
  |                 ^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

    Checking anchor-spl v0.31.1
warning: `protocol-zap` (lib) generated 1 warning (run `cargo fix --lib -p protocol-zap` to apply 1 suggestion)
    Checking cp-amm v0.1.6 (https://github.com/MeteoraAg/damm-v2?rev=d9cef5aaec9cfa1a6d3b0b28d213c87c285127de#d9cef5aa)
    Checking zap v0.2.2 (/data/workdir/MeteoraAg/zap-program/programs/zap)
warning: use of deprecated method `anchor_lang::prelude::AccountInfo::<'a>::realloc`: Use AccountInfo::resize() instead
  --> programs/zap/src/lib.rs:21:1
   |
21 | #[program]
   | ^^^^^^^^^^
   |
   = note: `#[warn(deprecated)]` on by default
   = note: this warning originates in the attribute macro `program` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: `zap` (lib) generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 26.19s
  • cargo fmt --check: ok

@codewithgun
Copy link
Contributor Author

/bot review

@metoeraag-bot
Copy link

metoeraag-bot bot commented Mar 8, 2026

Bot Agent progress: /bot review

Progress:

  • Repo checks (3 ok, 1 failed)
  • Context build
  • Codex review (1 pass + first look)
  • Buddy review (agreed after 4/10)
  • Post review

Copy link

@metoeraag-bot metoeraag-bot bot left a comment

Choose a reason for hiding this comment

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

Summary

⚠️ Limited-confidence review: check failed: pnpm run lint.

Referral-fee validation/refactoring looks directionally good overall, but two high-confidence issues still need fixes before landing: Whirlpool V2 sums remaining-account lengths into a u8 and can wrap, and the refactor moves whitelist/platform-fee/referral validation out of validate_payload() into validate_route_plan(), creating an implicit requirement that callers invoke both in the right order. Please either document or enforce that contract so those checks cannot be skipped.

Inline comments

See inline comments on the diff.

Claude (API) review

Rounds: 4 (min=1, max=10).
First look: Codex + Claude (Claude first-look failed; fell back to Codex).
Agreement: yes (no new findings/questions).

Debate transcript

First look comparison

Codex (first look):

Summary:
Referral-fee validation/refactoring looks directionally good, but there are two correctness concerns worth fixing before landing: one overflow in the Whirlpool V2 account-length parser, and one rollout blocker from making the new AMM referral-account layout mandatory before the corresponding version bump is included.

Inline comment highlights:

  • protocol-zap/src/processors/jup_swap_step_referral_fee_parser/whirlpool.rs:55: slice.length is being accumulated into a u8 here. If the total exceeds 255, this will panic in debug builds and wrap in release builds, which means get_end_account_index() can undercount the Whirlpool V2 tail and mis-parse the rest of
  • protocol-zap/src/utils/mod.rs:182: This call makes the new referral-account layout checks mandatory for every zap-out. The PR description still calls out the DLMM/DAMM version bump as pending, so during that mixed-version window older instructions that don't carry the new re

Codex (first look fallback):

Summary:
Referral-fee validation is headed in the right direction, but I found one concrete step-boundary bug in the new Mercurial parser and one public-API behavior regression around validate_payload() no longer enforcing checks it previously covered.

Inline comment highlights:

  • protocol-zap/src/processors/jup_swap_step_referral_fee_parser/mercurial.rs:51: find_next_swap_step_program_account_index is being called with processed_index, which means the search starts at processed_index + 1 — i.e. the current Mercurial step's program account. If the next hop is also Mercurial, this immedi
  • protocol-zap/src/processors/jup_v6_zap.rs:130: validate_payload() used to reject non-whitelisted swap steps and non-zero platform_fee_bps, but after this change it only checks convergence. extract_amm_accounts_and_info() now calls validate_route_plan(), so the repo-internal path

Comparison notes:

Review synthesis

  • No direct disagreement: both reviewers think the refactor is directionally good, but not merge-ready due to correctness/regression risks.
  • Different parser focus: Codex flags a Whirlpool V2 u8 overflow that can mis-parse trailing accounts; Buddy flags a Mercurial step-boundary bug when consecutive hops use the same parser path.
  • Different risk emphasis: Codex is most concerned about mixed-version rollout compatibility (new referral layout becoming mandatory too early), while Buddy is most concerned about a public API regression (validate_payload() no longer enforcing previous checks).

Most important follow-up action:
Block merge and do a targeted regression-fix pass with tests covering the two parser bugs, mixed-version referral-layout compatibility, and restoration of validate_payload()’s prior enforcement behavior.

Round 1

Codex (primary):

Summary:
Referral-fee validation/refactoring looks directionally good, but there are two correctness concerns worth fixing before landing: one overflow in the Whirlpool V2 account-length parser, and one rollout blocker from making the new AMM referral-account layout mandatory before the corresponding version bump is included.

Inline comment highlights:

  • protocol-zap/src/processors/jup_swap_step_referral_fee_parser/whirlpool.rs:55: slice.length is being accumulated into a u8 here. If the total exceeds 255, this will panic in debug builds and wrap in release builds, which means get_end_account_index() can undercount the Whirlpool V2 tail and mis-parse the rest of
  • protocol-zap/src/utils/mod.rs:182: This call makes the new referral-account layout checks mandatory for every zap-out. The PR description still calls out the DLMM/DAMM version bump as pending, so during that mixed-version window older instructions that don't carry the new re

Claude (API):

(no additional notes)

Codex (response):

  • Open questions kept for author: 1/1

Round 2

Codex (primary):

Summary:
Referral-fee validation/refactoring looks directionally good, but there are two correctness concerns worth fixing before landing: one overflow in the Whirlpool V2 account-length parser, and one rollout blocker from making the new AMM referral-account layout mandatory before the corresponding version bump is included.

Inline comment highlights:

  • protocol-zap/src/processors/jup_swap_step_referral_fee_parser/whirlpool.rs:55: slice.length is being accumulated into a u8 here. If the total exceeds 255, this will panic in debug builds and wrap in release builds, which means get_end_account_index() can undercount the Whirlpool V2 tail and mis-parse the rest of
  • protocol-zap/src/utils/mod.rs:182: This call makes the new referral-account layout checks mandatory for every zap-out. The PR description still calls out the DLMM/DAMM version bump as pending, so during that mixed-version window older instructions that don't carry the new re

Claude (API):

Critique of the primary review

The primary review correctly identifies two real issues:

  1. Whirlpool V2 u8 overflow (whirlpool.rs:55) — Agreed. The u8 accumulation is a real bug in validation code that must not silently wrap.

  2. Mixed-version rollout risk (utils/mod.rs:182) — Agreed this is an important sequencing concern, though it's more of a deployment/release question than a code bug. Kept as a question.

Issues the primary review missed

  • Mercurial step-boundary bug (mercurial.rs:51): The first-look review identified that find_next_swap_step_program_account_index is called with processed_index, meaning the search starts from processed_index + 1 which is the current Mercurial step's own program account. When the next step shares the same program address (or more generally, since the search starts too early), it can match the wrong account. This is a correctness issue that can cause the validation to misparse multi-hop routes involving Mercurial. The primary review did not flag this.

Overall assessment

Both the Whirlpool overflow and the Mercurial boundary bug are merge-blocking issues that need fixes and targeted tests before landing.

Codex (response):

  • New findings applied: 2/3
  • Open questions kept for author: 1/1

Round 3

Codex (primary):

Summary:
Referral-fee validation/refactoring looks directionally good overall, but two merge-blocking correctness issues need fixes before landing: the Whirlpool V2 remaining-account length is summed into a u8 and can wrap, and Mercurial can search for the next step boundary starting at its own program account and undercount the current step. Separately, please confirm rollout sequencing for the new zap-out referral-account layout checks so older DLMM/DAMM instructions do not fail during a mixed-version deployment.

Inline comment highlights:

  • protocol-zap/src/processors/jup_swap_step_referral_fee_parser/whirlpool.rs:55: slice.length is currently being summed into a u8 here because of type inference from the iterator item. If the total remaining accounts exceeds 255, this will panic in debug builds and silently wrap in release builds, which makes `get_e
  • protocol-zap/src/processors/jup_swap_step_referral_fee_parser/mercurial.rs:51: processed_index is the end of the previous step, so calling find_next_swap_step_program_account_index(..., processed_index, ...) starts the search from processed_index + 1, which is this Mercurial step's own program-account slot. That
  • protocol-zap/src/utils/mod.rs:182: The PR description still mentions the DLMM/DAMM version bump as pending. Since this path now makes the new referral-account layout validation unconditional for zap-out routes, can you confirm this won't be merged/deployed before the bumped

Claude (API):

Assessment of the primary review

The primary review correctly identified the two highest-priority issues:

  1. Whirlpool V2 u8 overflow (whirlpool.rs:55) — Correct and merge-blocking.
  2. Mercurial step-boundary bug (mercurial.rs:51) — Correct concern, though the exact failure conditions deserve author clarification (see questions).
  3. Deployment sequencing (utils/mod.rs:182) — Valid operational concern kept as author question.

What the primary review missed

  • API contract regression: The split of validation across validate_payload() and validate_route_plan() creates an implicit ordering dependency that isn't documented or enforced. The first-look review flagged this; the primary review did not. This is a maintainability/security concern — a future caller could skip validate_route_plan() and bypass all referral-fee and whitelist checks.

Items I'm not escalating

  • The unbounded linear scan in placeholder/program-account search functions is low-severity given the Solana instruction account limit (~256). Noted for awareness but dropped.
  • The program-ID-as-placeholder pattern (DAMM V2/DLMM) is consistent with Jupiter conventions and already documented in the parser files.

Codex (response):

  • New findings applied: 1/2
  • Open questions kept for author: 1/1

Round 4

Codex (primary):

Summary:
Referral-fee validation/refactoring looks directionally good overall, but two correctness issues still need fixes before landing: Whirlpool V2 sums remaining-account lengths into a u8 and can wrap, and Mercurial's next-step search may start at its own program-account slot and undercount the current step. Separately, please confirm rollout sequencing for the new zap-out referral-account layout checks, and document or enforce the new requirement that callers run validate_route_plan() in addition to validate_payload() so whitelist/platform-fee/referral validation cannot be skipped.

Inline comment highlights:

  • protocol-zap/src/processors/jup_swap_step_referral_fee_parser/whirlpool.rs:55: slice.length is currently being summed into a u8 here because of type inference from the iterator item. If the total remaining accounts exceeds 255, this will panic in debug builds and silently wrap in release builds, which makes `get_e
  • protocol-zap/src/processors/jup_swap_step_referral_fee_parser/mercurial.rs:51: processed_index is the previous step's inclusive end, so calling find_next_swap_step_program_account_index(..., processed_index, ...) starts scanning at processed_index + 1, which is this Mercurial step's own program-account slot. If
  • protocol-zap/src/processors/jup_v6_zap.rs:130: validate_payload() used to be the single validation entry point for convergence plus whitelist/platform_fee_bps checks. After this refactor, whitelist/platform-fee/referral validation lives in validate_route_plan() instead. That creat
  • protocol-zap/src/utils/mod.rs:182: The PR description still mentions the DLMM/DAMM version bump as pending. Since this path now makes the new referral-account layout validation unconditional for zap-out routes, can you confirm this won't be merged/deployed before the bumped

Claude (API):

Assessment

The primary review now covers the four key issues identified across all review rounds:

  1. Whirlpool V2 u8 overflow (whirlpool.rs:55) — Correctly flagged, merge-blocking.
  2. Mercurial step-boundary bug (mercurial.rs:51) — Correctly flagged with author question kept open.
  3. API contract regression (jup_v6_zap.rs:130) — Applied from prior critique; the validate_payload() / validate_route_plan() split ordering dependency is now documented.
  4. Deployment sequencing (utils/mod.rs:182) — Kept as author question.

I have no additional findings to add and no false positives to retract. The primary review is comprehensive and correctly prioritized.

Codex (response):

Agreement reached. No further changes.

Synthesis

Review synthesis

  • No direct disagreement: both reviewers think the refactor is directionally good, but not merge-ready due to correctness/regression risks.
  • Different parser focus: Codex flags a Whirlpool V2 u8 overflow that can mis-parse trailing accounts; Buddy flags a Mercurial step-boundary bug when consecutive hops use the same parser path.
  • Different risk emphasis: Codex is most concerned about mixed-version rollout compatibility (new referral layout becoming mandatory too early), while Buddy is most concerned about a public API regression (validate_payload() no longer enforcing previous checks).

Most important follow-up action:
Block merge and do a targeted regression-fix pass with tests covering the two parser bugs, mixed-version referral-layout compatibility, and restoration of validate_payload()’s prior enforcement behavior.

Repo checks

Repo Checks

  • cargo fetch --locked: ok
info: syncing channel updates for '1.85.0-x86_64-unknown-linux-gnu'
info: latest update on 2025-02-20, rust version 1.85.0 (4d91de4e4 2025-02-17)
info: downloading component 'cargo'
info: downloading component 'rust-std'
info: downloading component 'rustc'
info: installing component 'cargo'
info: installing component 'rust-std'
info: installing component 'rustc'
    Updating git repository `https://github.com/MeteoraAg/damm-v2`
From https://github.com/MeteoraAg/damm-v2
 * [new ref]         d9cef5aaec9cfa1a6d3b0b28d213c87c285127de -> refs/commit/d9cef5aaec9cfa1a6d3b0b28d213c87c285127de
 Downloading crates ...
  Downloaded anyhow v1.0.98
  Downloaded solana-curve25519 v2.3.5
  Downloaded pest v2.8.3
  Downloaded ruint v1.16.0
  Downloaded redox_syscall v0.5.14
  Downloaded solana-sysvar v2.2.2
  Downloaded serde_json v1.0.141
  Downloaded bytemuck_derive v1.10.0
  Downloaded solana-zk-sdk v2.3.5
  • pnpm install --frozen-lockfile: ok
Lockfile is up to date, resolution step is skipped
Progress: resolved 1, reused 0, downloaded 0, added 0
Packages: +199
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 199, reused 118, downloaded 0, added 0
Progress: resolved 199, reused 194, downloaded 4, added 198
Progress: resolved 199, reused 194, downloaded 5, added 199, done

dependencies:
+ @coral-xyz/anchor 0.31.1
+ @solana/spl-token 0.4.13
+ @solana/web3.js 1.98.2
+ babar 0.2.3
+ borsh 2.0.0
+ litesvm 0.1.0

devDependencies:
+ @meteora-ag/cp-amm-sdk 1.2.3
+ @types/bn.js 5.2.0
+ @types/chai 4.3.20
+ @types/mocha 9.1.1
+ chai 4.5.0
+ mocha 9.2.2
+ prettier 2.8.8
+ ts-mocha 10.1.0
+ typescript 5.8.3

╭ Warning ─────────────────────────────────────────────────────────────────────╮
│                                                                              │
│   Ignored build scripts: bigint-buffer@1.1.5, bufferutil@4.0.9,              │
│   utf-8-validate@5.0.10.                                                     │
│   Run "pnpm approve-builds" to pick which dependencies should be allowed     │
│   to run scripts.                                                            │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
Done in 3.1s using pnpm v10.28.2

! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-10.28.2.tgz
  • pnpm run lint: failed
> @ lint /data/workdir/MeteoraAg/zap-program
> prettier */*.js "*/**/*{.js,.ts}" --check

Checking formatting...
 ELIFECYCLE  Command failed with exit code 2.

[error] No files matching the pattern were found: "*/*.js".
[warn] tests/test_zapin/zapin_dlmm_initialize_position.test.ts
[warn] Code style issues found in the above file. Forgot to run Prettier?
  • cargo check --workspace: ok
ompiling anchor-attribute-access-control v0.31.1
   Compiling anchor-attribute-account v0.31.1
   Compiling anchor-attribute-event v0.31.1
   Compiling anchor-attribute-program v0.31.1
   Compiling anchor-attribute-error v0.31.1
    Checking solana-program v2.3.0
   Compiling anchor-derive-serde v0.31.1
    Checking spl-program-error v0.6.0
   Compiling anchor-derive-accounts v0.31.1
    Checking spl-token v7.0.0
    Checking spl-pod v0.5.1
    Checking spl-token-confidential-transfer-proof-generation v0.2.0
    Checking spl-token-confidential-transfer-ciphertext-arithmetic v0.2.1
    Checking spl-type-length-value v0.7.0
    Checking spl-token-confidential-transfer-proof-extraction v0.2.1
    Checking spl-token-group-interface v0.5.0
    Checking spl-elgamal-registry v0.1.1
    Checking spl-tlv-account-resolution v0.9.0
    Checking spl-token-metadata-interface v0.6.0
    Checking spl-transfer-hook-interface v0.9.0
    Checking spl-token-2022 v6.0.0
    Checking anchor-lang v0.31.1
    Checking jupiter v0.1.0 (/data/workdir/MeteoraAg/zap-program/libs/jupiter)
    Checking dlmm v0.10.1 (/data/workdir/MeteoraAg/zap-program/libs/dlmm)
    Checking protocol-zap v0.1.0 (/data/workdir/MeteoraAg/zap-program/protocol-zap)
    Checking spl-associated-token-account v6.0.0
    Checking anchor-spl v0.31.1
    Checking cp-amm v0.1.6 (https://github.com/MeteoraAg/damm-v2?rev=d9cef5aaec9cfa1a6d3b0b28d213c87c285127de#d9cef5aa)
    Checking zap v0.2.2 (/data/workdir/MeteoraAg/zap-program/programs/zap)
warning: use of deprecated method `anchor_lang::prelude::AccountInfo::<'a>::realloc`: Use AccountInfo::resize() instead
  --> programs/zap/src/lib.rs:21:1
   |
21 | #[program]
   | ^^^^^^^^^^
   |
   = note: `#[warn(deprecated)]` on by default
   = note: this warning originates in the attribute macro `program` (in Nightly builds, run with -Z macro-backtrace for more info)

warning: `zap` (lib) generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 29.30s

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.

1 participant