Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
bdba9b1
fix: make graph construction and SPFA relaxation deterministic
tvinagre Apr 27, 2026
d001d5b
chore: add .worktrees/ to gitignore for worktree isolation
tvinagre Mar 18, 2026
1beda3d
feat: add RecordedUpdate and MarketRecording serialization types
tvinagre Mar 18, 2026
c176b02
feat: implement recording I/O with serde_json + zstd
tvinagre Mar 18, 2026
6869368
fix: add doc comments and workspace-manage tempfile dev-dependency
tvinagre Mar 18, 2026
3ab44ad
feat: add integration test harness with Update message replay
tvinagre Mar 19, 2026
9c7a35b
fix: address code quality review findings in test harness
tvinagre Mar 19, 2026
b7dbeb2
feat: add record-market tool skeleton
tvinagre Mar 19, 2026
acdac2d
test: add solution availability and quality integration tests
tvinagre Mar 19, 2026
1dc992f
test: add solve time integration tests (criterion 2)
tvinagre Mar 19, 2026
ecd1de9
test: add derived data integration tests (criterion 3)
tvinagre Mar 19, 2026
4175f45
feat: add BLESS_GOLDEN workflow for golden output regeneration
tvinagre Mar 19, 2026
5913cbd
chore: set up Git LFS for integration test fixture files
tvinagre Mar 19, 2026
d643ebf
ci: add integration tests to CI and nightly Tycho canary
tvinagre Mar 19, 2026
4e1784b
feat: implement record-market tool and load_test_scenarios
tvinagre Mar 19, 2026
10059a7
fix: recorder improvements from live Tycho testing
tvinagre Mar 19, 2026
897d168
fix: resolve worker readiness race and serialization in replay pipeline
tvinagre Mar 19, 2026
1381959
refactor: address review feedback on recording tool and integration t…
tvinagre Mar 20, 2026
e06e8b8
refactor: address second round of review feedback
tvinagre Mar 23, 2026
490d7e0
refactor: replace derived data threshold tests with exact golden asse…
tvinagre Mar 23, 2026
9c8b711
style: apply nightly fmt formatting
tvinagre Mar 23, 2026
8c6dd60
fix: resolve rebase conflicts with main
tvinagre Mar 23, 2026
362b4d1
fix: resolve rebase conflicts with origin/main
tvinagre Apr 2, 2026
945d622
refactor: restructure integration test infrastructure per PR review
tvinagre Apr 6, 2026
5b2b531
test: regenerate fixtures with 60s recording
tvinagre Apr 6, 2026
3590c1c
fix: address PR review — top-level imports, warn on fallbacks, fix re…
tvinagre Apr 8, 2026
d0367e7
refactor: feature-gate from_recording, fix canary, improve test preci…
tvinagre Apr 8, 2026
68fbdb6
fix: address review findings — remove duplicates, harden CI and test …
tvinagre Apr 9, 2026
db00f2a
revert: restore fixtures/integration/ pending decision on removal
tvinagre Apr 9, 2026
0dc02a1
refactor: move MarketEvent import to feature-gated top-level
tvinagre Apr 9, 2026
5c23d27
fix: remove stale fixtures/integration/ and rename golden to expected
tvinagre Apr 9, 2026
ccd2c40
fix: add test-fixtures and record-market stubs to Dockerfile
tvinagre Apr 9, 2026
31a1be5
fix: handle EIP1559 gas price in recorder
tvinagre Apr 9, 2026
bbfe41c
fix: regenerate fixtures from live Tycho, widen quality threshold
tvinagre Apr 9, 2026
d7f02d5
fix: restore 1% quality threshold and add expected output regeneration
tvinagre Apr 27, 2026
46c0019
fix: require tycho-simulation >=0.275.0 for Update serde support
tvinagre Jun 9, 2026
c9ce8de
Merge remote-tracking branch 'origin/main' into tl/ENG-5578-integrati…
tvinagre Jun 9, 2026
8bcbbd4
test: regenerate expected outputs after merging main
tvinagre Jun 9, 2026
1f15706
docs: document record-market, test fixtures, and integration tests
tvinagre Jun 9, 2026
831b5e2
style: apply rustfmt and remove duplicate cfg attribute
tvinagre Jun 9, 2026
295e866
fix: unify expected-output block number, clarify canary purpose
tvinagre Jun 10, 2026
ed9823b
Merge remote-tracking branch 'origin/main' into tl/ENG-5578-integrati…
tvinagre Jun 10, 2026
78761e0
feat: make record-market and replay pipeline chain-agnostic
tvinagre Jun 12, 2026
6550e8d
Merge remote-tracking branch 'origin/main' into tl/ENG-5578-integrati…
tvinagre Jun 13, 2026
0920c90
fix: sync Cargo.lock with 0.78.1 workspace version bump
tvinagre Jun 13, 2026
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
3 changes: 3 additions & 0 deletions .claude/CODEBASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Key properties:
| [`fynd-core`](../fynd-core/CLAUDE.md) | `fynd-core/` | Pure solving logic: algorithms, worker pools, graph, feed, derived data, encoding. No HTTP deps |
| [`fynd-rpc`](../fynd-rpc/CLAUDE.md) | `fynd-rpc/` | HTTP RPC server builder (Actix Web): API handlers, middleware, `FyndRPCBuilder` |
| [`fynd-rpc-types`](../fynd-rpc-types/CLAUDE.md) | `fynd-rpc-types/` | Shared DTO types for the RPC API (request/response wire format) |
| `fynd-test-fixtures` | `test-fixtures/` | Shared types for recorded-market test fixtures: `MarketRecording`, expected outputs, test scenarios. Not published |

### [Clients](../clients/CLAUDE.md)

Expand All @@ -44,6 +45,7 @@ Both clients wrap the same OpenAPI spec (`clients/openapi.json`, generated via `
|---|---|---|
| `fynd-benchmark` | `tools/benchmark/` | Load testing, solver comparison, trade dataset download |
| `fynd-swap-cli` | `tools/fynd-swap-cli/` | Quote and execute token swaps (ERC-20 or Permit2) |
| `record-market` | `tools/record-market/` | Record live Tycho market state and generate expected outputs for the integration tests |

## Architecture Overview

Expand Down Expand Up @@ -118,6 +120,7 @@ See `docs/ARCHITECTURE.md` for the full architecture diagram and detailed compon
## Testing

- `cargo nextest run --workspace --all-targets --all-features` — full test suite
- `cargo nextest run -p fynd-core --features test-utils --test integration` — replayed-market integration tests against recorded fixtures (`fynd-core/tests/fixtures/`, Git LFS). See `fynd-core/tests/integration/README.md`; regenerate baselines with the ignored `regenerate_expected_outputs` test, record fresh markets with `tools/record-market`
- `cargo +nightly clippy --workspace --all-targets --all-features` — lint
- `cargo +nightly fmt --all --check` — format check
- `RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --locked --package fynd-core --package fynd-rpc-types --package fynd-rpc --package fynd-client` — doc build (broken links, missing docs)
Expand Down
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Track compressed market recordings with Git LFS to keep the repo lightweight.
# These fixtures are multi-MB zstd-compressed JSON files used by integration tests.
fynd-core/tests/fixtures/*.json.zst filter=lfs diff=lfs merge=lfs -text
26 changes: 26 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,32 @@ jobs:
- run: pnpm --dir clients/typescript --filter @kayibal/fynd-client run lint
- run: pnpm --dir clients/typescript --filter @kayibal/fynd-client run test

integration_tests:
name: Integration Tests
runs-on: ubuntu-latest
timeout-minutes: 15
needs: [compile_and_test]
env:
RUSTFLAGS: "-D warnings"
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
lfs: true
- name: Setup toolchain
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: stable
- name: Setup Rust Cache
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
cache-on-failure: true
- name: Install latest nextest release
uses: taiki-e/install-action@2b15ad09ca0f06a76791407e35ab20f0b712d615 # nextest
- name: Run integration tests
run: cargo nextest run -p fynd-core --features test-utils --test integration

security_audit:
name: Security Audit
runs-on: ubuntu-latest
Expand Down
70 changes: 70 additions & 0 deletions .github/workflows/nightly-canary.yaml
Comment thread
tvinagre marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Nightly Canary

# Records fresh live Tycho data and regenerates expected outputs from that same
# recording before running the integration tests. The baselines are therefore
# self-referential: this canary detects Tycho data-format changes, decode
# failures, and replay-pipeline crashes — NOT solver quality regressions.
# Quality is guarded by the committed baseline in the PR-triggered
# integration_tests job in ci.yaml.

on:
schedule:
- cron: '0 6 * * *' # Daily at 06:00 UTC
workflow_dispatch: # Allow manual trigger

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"

jobs:
live-canary:
name: Live Tycho Canary
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Setup toolchain
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: stable
- name: Setup Rust Cache
uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
cache-on-failure: true
- name: Install latest nextest release
uses: taiki-e/install-action@2b15ad09ca0f06a76791407e35ab20f0b712d615 # nextest

- name: Record fresh market state
run: |
cargo run -p record-market -- \
--tycho-url "$TYCHO_URL" \
--rpc-url "$RPC_URL" \
--tycho-api-key "$TYCHO_API_KEY" \
--duration-secs 120 \
--output-dir fynd-core/tests/fixtures
env:
TYCHO_URL: ${{ secrets.TYCHO_URL }}
RPC_URL: ${{ secrets.RPC_URL }}
TYCHO_API_KEY: ${{ secrets.TYCHO_API_KEY }}

- name: Run solver against live market
run: |
cargo nextest run -p fynd-core --features test-utils --test integration

- name: Notify on failure
if: failure()
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
echo "::error::Nightly canary failed — Tycho data format may have changed or the replay pipeline crashed"
if [ -z "$SLACK_WEBHOOK_URL" ]; then
echo "::warning::SLACK_WEBHOOK_URL secret not set; skipping Slack notification"
exit 0
fi
curl -sf -X POST -H 'Content-type: application/json' \
--data "{\"text\":\":red_circle: Nightly canary failed — Tycho data format may have changed or the replay pipeline crashed. <${RUN_URL}|View run>\"}" \
"$SLACK_WEBHOOK_URL"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ scale_results*.json
.env
.claude/worktrees/
.claude/plans/
.worktrees/

# fynd-gas-audit output artifacts
tools/fynd-gas-audit/out/
41 changes: 41 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ members = [
"tools/erc20-overrides",
"tools/fynd-swap-cli",
"tools/fynd-gas-audit",
"tools/record-market",
"test-fixtures",
]
resolver = "2"

Expand Down Expand Up @@ -139,6 +141,9 @@ tycho-execution = ">=0.304"
tycho-simulation = ">=0.304"
typetag = "0.2"

# Compression
zstd = "0.13"

# Graph algorithms
petgraph = "0.6"

Expand All @@ -156,13 +161,16 @@ async-trait = "0.1"
chrono = "0.4"
itertools = "0.14.0"
hex = "0.4"
sha2 = "0.10"

# Internal crates
fynd-core = { path = "fynd-core", version = "0.78.1" }
fynd-rpc = { path = "fynd-rpc", version = "0.78.1" }
fynd-rpc-types = { path = "fynd-rpc-types", version = "0.78.1" }
fynd-client = { path = "clients/rust", version = "0.78.1" }
erc20-overrides = { path = "tools/erc20-overrides", version = "0.78.1" }
fynd-test-fixtures = { path = "test-fixtures" }

# Dev dependencies
rstest = "0.18"
tempfile = "3"
15 changes: 12 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ COPY tools/benchmark/Cargo.toml tools/benchmark/
COPY tools/fynd-swap-cli/Cargo.toml tools/fynd-swap-cli/
COPY tools/erc20-overrides/Cargo.toml tools/erc20-overrides/
COPY tools/fynd-gas-audit/Cargo.toml tools/fynd-gas-audit/
COPY tools/record-market/Cargo.toml tools/record-market/
COPY test-fixtures/Cargo.toml test-fixtures/
RUN mkdir -p src fynd-core/src fynd-rpc/src fynd-rpc-types/src \
clients/rust/src tools/benchmark/src tools/fynd-swap-cli/src \
tools/erc20-overrides/src tools/fynd-gas-audit/src && \
tools/erc20-overrides/src tools/fynd-gas-audit/src \
tools/record-market/src test-fixtures/src && \
echo "fn main() {}" > src/main.rs && \
echo "" > src/lib.rs && \
echo "" > fynd-core/src/lib.rs && \
Expand All @@ -35,10 +38,13 @@ RUN mkdir -p src fynd-core/src fynd-rpc/src fynd-rpc-types/src \
echo "fn main() {}" > tools/fynd-swap-cli/src/main.rs && \
echo "" > tools/erc20-overrides/src/lib.rs && \
echo "fn main() {}" > tools/fynd-gas-audit/src/main.rs && \
echo "fn main() {}" > tools/record-market/src/main.rs && \
echo "" > test-fixtures/src/lib.rs && \
cargo build --release --package fynd --package fynd-swap-cli && \
rm -rf src fynd-core/src fynd-rpc/src fynd-rpc-types/src \
clients/rust/src tools/benchmark/src tools/fynd-swap-cli/src \
tools/erc20-overrides/src tools/fynd-gas-audit/src
tools/erc20-overrides/src tools/fynd-gas-audit/src \
tools/record-market/src test-fixtures/src

# Copy real source and rebuild
COPY src/ src/
Expand All @@ -48,9 +54,12 @@ COPY fynd-rpc-types/src/ fynd-rpc-types/src/
COPY clients/rust/src/ clients/rust/src/
COPY tools/fynd-swap-cli/src/ tools/fynd-swap-cli/src/
COPY tools/erc20-overrides/src/ tools/erc20-overrides/src/
RUN mkdir -p tools/benchmark/src tools/fynd-gas-audit/src && \
RUN mkdir -p tools/benchmark/src tools/fynd-gas-audit/src \
tools/record-market/src test-fixtures/src && \
echo "fn main() {}" > tools/benchmark/src/main.rs && \
echo "fn main() {}" > tools/fynd-gas-audit/src/main.rs && \
echo "fn main() {}" > tools/record-market/src/main.rs && \
echo "" > test-fixtures/src/lib.rs && \
touch src/main.rs src/lib.rs fynd-core/src/lib.rs fynd-rpc/src/lib.rs \
fynd-rpc-types/src/lib.rs clients/rust/src/lib.rs \
tools/fynd-swap-cli/src/main.rs tools/erc20-overrides/src/lib.rs && \
Expand Down
8 changes: 8 additions & 0 deletions fynd-core/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ Price guard methods: `price_guard_enabled(bool)`, `register_price_provider(Box<d

See `fynd-core/examples/custom_algorithm.rs` for a walkthrough.

## Integration Tests

`tests/integration/` replays a recorded market (`tests/fixtures/`, Git LFS) through the full
pipeline and asserts solution availability, quality vs baseline, derived-data metrics, and timing.
Run with `cargo nextest run -p fynd-core --features test-utils --test integration`. The
`test-utils` feature gates `Solver::from_recording` and the recording helpers; fixtures are
recorded with `tools/record-market`. See `tests/integration/README.md`.

## Data Flow

**Market updates** (every block):
Expand Down
6 changes: 6 additions & 0 deletions fynd-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ reqwest.workspace = true
tokio-tungstenite.workspace = true
alloy = { workspace = true, features = ["sol-types"] }

[features]
test-utils = []

[dev-dependencies]
rstest.workspace = true
tempfile.workspace = true
toml.workspace = true
fynd-test-fixtures.workspace = true
tracing-subscriber.workspace = true
14 changes: 14 additions & 0 deletions fynd-core/src/feed/protocol_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ use tycho_simulation::{

use super::DataFeedError;

/// Register DEX protocol decoders for test tooling (record-market).
///
/// Wrapper over [`register_exchanges`] so the recorder builds the same protocol stream as
/// production without exposing the crate-private `DataFeedError`.
#[cfg(feature = "test-utils")]
pub fn register_exchanges_for_recording(
builder: ProtocolStreamBuilder,
tvl_filter: ComponentFilter,
protocols: &[String],
) -> Result<ProtocolStreamBuilder, String> {
register_exchanges(builder, tvl_filter, protocols).map_err(|e| e.to_string())
}

/// Register DEX protocol decoders on a [`ProtocolStreamBuilder`].
pub(crate) fn register_exchanges(
mut builder: ProtocolStreamBuilder,
tvl_filter: ComponentFilter,
Expand Down
2 changes: 1 addition & 1 deletion fynd-core/src/feed/tycho_feed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ impl TychoFeed {

/// Handles a message from Tycho stream.
#[instrument(skip(self, msg))]
async fn handle_tycho_message(&self, msg: Update) -> Result<(), DataFeedError> {
pub(crate) async fn handle_tycho_message(&self, msg: Update) -> Result<(), DataFeedError> {
// Collect variables for market shared data update
let Update {
new_pairs: added_components,
Expand Down
Loading
Loading