This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Cross-VM bridge enabling Flow EVM users to access Flow YieldVaults' Cadence-based yield farming protocol. EVM users submit requests through a Solidity contract, which are processed by a Cadence worker that manages YieldVault positions.
cd solidity && forge build # Build contracts
cd solidity && forge test # Run all tests
cd solidity && forge test -vvv # Verbose test output
cd solidity && forge test --match-test testFunctionName # Run single test
cd solidity && forge fmt # Format code./local/run_cadence_tests.sh # Run all Cadence tests (cleans db, installs deps)
flow test cadence/tests/<file>.cdc # Run single test file
flow deps install --skip-alias --skip-deployments # Install dependencies./local/setup_and_run_emulator.sh # Start emulator
./local/deploy_full_stack.sh # Deploy all contracts
./local/run_solidity_tests.sh # Run Solidity tests on emulator./scripts/export-artifacts.sh # Export ABIs only
./scripts/export-artifacts.sh --network testnet --evm-address 0x... # Export and update addresses- EVM User calls
FlowYieldVaultsRequests.sol(creates request, escrows funds) - FlowYieldVaultsEVMWorkerOps.cdc SchedulerHandler schedules WorkerHandlers to process requests
- FlowYieldVaultsEVM.cdc Worker fetches pending requests via
getPendingRequestsUnpacked() - Two-phase commit:
startProcessingBatch()marks PROCESSING and deducts balance,completeProcessing()marks COMPLETED/FAILED and credits any EVM-side refund due toclaimableRefunds(failed CREATE/DEPOSIT or successful CREATE/DEPOSIT precision residuals)
| Contract | Location | Purpose |
|---|---|---|
FlowYieldVaultsRequests.sol |
solidity/src/ |
EVM request queue + fund escrow |
FlowYieldVaultsEVM.cdc |
cadence/contracts/ |
Cadence worker processing requests |
FlowYieldVaultsEVMWorkerOps.cdc |
cadence/contracts/ |
SchedulerHandler + WorkerHandler orchestration |
- COA Bridge: Cadence Owned Account bridges funds between EVM and Cadence via FlowEVMBridge
- Sentinel Values:
NATIVE_FLOW = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF,NO_YIELDVAULT_ID = type(uint64).max - Ownership Tracking: Parallel mappings on both EVM (
userOwnsYieldVault) and Cadence (yieldVaultOwnershipLookup) for O(1) lookups - Scheduler/Worker Split: SchedulerHandler runs at fixed interval, schedules WorkerHandlers for individual requests
- Batch Preprocessing: SchedulerHandler validates requests before scheduling workers; invalid requests fail early
- Crash Recovery: SchedulerHandler monitors WorkerHandler transactions and marks panicked requests as FAILED
0: CREATE_YIELDVAULT (requires deposit)
1: DEPOSIT_TO_YIELDVAULT (requires deposit)
2: WITHDRAW_FROM_YIELDVAULT
3: CLOSE_YIELDVAULT
cadence/tests/evm_bridge_lifecycle_test.cdc- Full request lifecyclecadence/tests/access_control_test.cdc- Security boundariescadence/tests/error_handling_test.cdc- Edge casescadence/tests/test_helpers.cdc- Shared test utilities
solidity/test/FlowYieldVaultsRequests.t.sol- Request creation, COA operations, pagination
- Contracts defined in
contractssection with aliases per network (emulator, testing, testnet) - Dependencies imported from Flow mainnet (FlowEVMBridge, FlowToken, FlowTransactionScheduler, etc.)
- Accounts:
emulator-account,emulator-flow-yield-vaults,testnet-account
- Solidity 0.8.20, optimizer enabled (200 runs), via_ir enabled
- OpenZeppelin contracts via remapping
@openzeppelin/contracts/
NATIVE_FLOW:0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF(native $FLOW token marker)NO_YIELDVAULT_ID:type(uint64).max/UInt64.max(no yieldvault sentinel)
| Contract | Address |
|---|---|
| FlowYieldVaultsRequests (EVM) | 0xF633C9dBf1a3964a895fCC4CA4404B6f8BA8141d |
| FlowYieldVaultsEVM (Cadence) | df111ffc5064198a |
| FlowYieldVaultsEVMWorkerOps | df111ffc5064198a |
The current worker code expects the 5-argument completeProcessing(uint256,bool,uint64,string,uint256) ABI. Keep Cadence and EVM deployments in sync when reviewing or updating testnet addresses.
When reviewing this codebase, keep these fundamental blockchain properties in mind:
All blockchain transactions are atomic. If any operation within a transaction panics/reverts, ALL state changes made during that transaction are rolled back completely. There is no "partial completion" scenario.
- In Cadence:
panic()reverts all state changes in the transaction - In Solidity:
revert()or failedrequire()reverts all state changes - This is by design and is the correct way to ensure data consistency
Therefore, patterns like:
// This is SAFE - if processRequest panics, the remove never happened
scheduledRequests.remove(key: requestId)
processResult = worker.processRequest(request) // if this panics, the line above reverts tooBlockchain transactions execute one at a time in a deterministic order. There is no parallel execution within the same blockchain execution environment.
- Transactions are ordered within blocks and executed sequentially
- Two transactions cannot "race" against each other simultaneously
- What might look like a "race condition" is actually just transaction ordering, which is well-defined behavior
This means scenarios like "Transaction A completes but Transaction B sees stale state" are impossible within the same execution context. By the time Transaction B executes, Transaction A has either fully committed or fully reverted.
- WorkerHandler/SchedulerHandler coordination is safe because they run in separate transactions that execute sequentially
- Panic-based error handling in
processRequest()is the correct pattern - it ensures atomicity across Cadence and EVM state - State removal before vs after processing doesn't create race conditions - if processing fails, the entire transaction (including removal) reverts
- Amount units: EVM uses wei (10^18), Cadence uses UFix64. Conversion required at the bridge boundary.
- Type identifiers: Vault/strategy identifiers are Cadence type strings like
A.xxx.FlowToken.Vault - Request IDs start at 1, not 0 (Solidity
nextRequestIdinitialized to 1) - Pending requests array: Pagination via
getPendingRequestsUnpacked(offset, limit) - Cadence test cleanup: Always clean
./imports/and./db/directories before running Cadence tests (handled byrun_cadence_tests.sh) - Test accounts: Tests use mock EVM addresses like
0x0000...0011and well-known private keys (0x2-0x6) - never use on mainnet
This project depends on lib/FlowYieldVaults (git submodule) which contains the core YieldVaults Cadence protocol including FlowYieldVaults.cdc and FlowYieldVaultsClosedBeta.cdc.