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
2 changes: 2 additions & 0 deletions PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ source of truth로 사용한다.
- multi-venue 아키텍처와 책임 문서 작성
- Corner Store용 Uniswap v3 최소 배포 profile 분리와 테스트
- ExecutionRouter/VenueRegistry/VenueSelector와 AMM reference adapter skeleton
- router now rejects requests whose `context.venueType` mismatches the registered
`VenueConfig.venueType` (closes the PR-12 review medium finding)

## Blocked

Expand Down
8 changes: 7 additions & 1 deletion src/execution/ExecutionRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {Events} from "../libraries/Events.sol";
/// @title ExecutionRouter
/// @notice Single entry point for trade execution. Orchestrates the gate sequence
/// (deadline -> nonce -> compliance -> amount bound -> venue suspension -> venue policy
/// binding -> adapter dispatch -> post-trade commit) and delegates the actual swap to
/// binding -> venue type binding -> adapter dispatch -> post-trade commit) and delegates the actual swap to
/// the venue's registered adapter. Non-custodial: the router never holds tokens.
contract ExecutionRouter is IExecutionRouter, Governed, ReentrancyGuard {
IComplianceEngine public immutable engine;
Expand Down Expand Up @@ -84,6 +84,12 @@ contract ExecutionRouter is IExecutionRouter, Governed, ReentrancyGuard {
VenueConfig memory cfg = venueReg.venueOf(req.context.venue);
if (!cfg.active || cfg.adapter == address(0)) revert Errors.AdapterNotRegistered();

// 7a. bind the caller-supplied venue type to the registry's stored config.
// Step 6 validated req.context.venueType against the decision's type mask;
// without this check a caller could misreport venueType and route a venue
// of a disallowed type through an allowed-type bit.
if (cfg.venueType != req.context.venueType) revert Errors.VenueTypeMismatch();

// 8. dispatch to adapter (performs the swap; non-custodial)
ExecutionResult memory r = IExecutionAdapter(cfg.adapter).execute(req, d);

Expand Down
1 change: 1 addition & 0 deletions src/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ library Errors {
error PolicyNotActive(); // UNKNOWN/SUSPENDED
error ComplianceRejected(bytes32 reasonCode);
error VenueNotAllowed();
error VenueTypeMismatch();
error VenueSuspended();
error AdapterNotRegistered();
error DeadlineExpired();
Expand Down
12 changes: 12 additions & 0 deletions test/unit/execution/Router.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,18 @@ contract RouterTest is Test {
router.execute(_defaultReq());
}

function test_execute_revertsWhenVenueTypeMismatchesRegistry() public {
// registry has VENUE registered as VenueType.AMM (see setUp)
ExecutionRequest memory req = _defaultReq();
req.context.venueType = VenueType.RFQ;
// let step-6 selector pass by allowing RFQ in the decision's type mask
engine.setDecision(_decision(true, 1 << uint256(VenueType.RFQ), bytes32(0), type(uint256).max, REASON_OK));

vm.prank(BUYER);
vm.expectRevert(Errors.VenueTypeMismatch.selector);
router.execute(req);
}

function test_revert_adapterNotRegistered_unknownVenue() public {
ExecutionRequest memory req = _defaultReq();
req.context.venue = address(0xABCD); // not registered, but allowedVenuesHash==0 passes selector
Expand Down
Loading