Conversation
Code Review - PR #43: Guard Against Local Registry CorruptionI've reviewed this PR addressing issue #24. Overall, the changes properly implement the recommended defenses against registry corruption. Here's my detailed feedback: ✅ Strengths
🐛 Critical Bug FoundLocation: if (request.requestType == RequestType.CREATE_YIELDVAULT) {
request.yieldVaultId = yieldVaultId;
} else if (request.yieldVaultId != yieldVaultId) {
revert YieldVaultIdMismatch(request.yieldVaultId, yieldVaultId);
}
request.yieldVaultId = yieldVaultId; // ⚠️ LINE 1128 - REDUNDANT AND PROBLEMATICIssue: Line 1128 unconditionally assigns
Impact: The validation at line 1124-1125 becomes pointless since line 1128 overwrites Recommendation: Remove line 1128 entirely. The assignment at line 1123 is sufficient for CREATE operations, and for other operations,
|
Pull Request Review: Guard Against Local Registry YieldVault IDs CorruptionSummaryThis PR addresses issue #24 by adding defensive checks to prevent COA operational mistakes from corrupting the EVM-side registry. The changes implement three key safeguards in the ✅ Positive Aspects1. Security Improvements - Strong
2. Code Quality
3. Targeted Fix
🔍 Issues & ConcernsCritical: Missing Test CoverageThe new error cases are not covered by tests. I found no tests for:
Recommendation: Add tests covering: function test_CompleteProcessing_RevertYieldVaultIdMismatch() public
function test_RegisterYieldVault_RevertAlreadyRegistered() public
function test_UnregisterYieldVault_RevertInvalidOwnership() publicThese should verify the revert occurs and that contract state remains consistent after the revert. Medium: Potential Edge Case with
|
Code Review SummaryThis PR effectively addresses FLOW-9 by adding defensive checks to prevent YieldVault ID registry corruption. The changes are well-targeted and directly resolve the security concerns outlined in the issue. ✅ Strengths1. Strong ID Binding (lines 1120-1126)The new logic enforces that for DEPOSIT/WITHDRAW/CLOSE operations, the if (request.requestType == RequestType.CREATE_YIELDVAULT) {
request.yieldVaultId = yieldVaultId;
} else if (request.yieldVaultId != yieldVaultId) {
revert YieldVaultIdMismatch(request.yieldVaultId, yieldVaultId);
}Impact: Prevents COA mistakes from targeting the wrong vault (e.g., closing Alice's vault when processing Bob's request). 2. Duplicate Registration Guard (lines 1561-1564)Prevents registering an already-valid YieldVault ID: if (validYieldVaultIds[yieldVaultId]) {
revert YieldVaultIdAlreadyRegistered(yieldVaultId);
}Impact: Blocks duplicate registrations that could corrupt ownership mappings. 3. Owner Validation on Unregister (lines 1591-1594)Validates ownership before unregistering: if (yieldVaultOwners[yieldVaultId] != user) {
revert InvalidYieldVaultId(yieldVaultId, user);
}Impact: Ensures only the rightful owner's vault can be unregistered, fixing the scenario described in issue #24 where Bob's vault could be incorrectly removed. 4. Comprehensive Test CoverageBoth new tests properly validate the error conditions:
🔍 AnalysisSecurity Impact: Medium-HighThese checks prevent several attack vectors:
Code Quality: Excellent
Potential Edge Cases Covered:
💡 Minor Observations1. Event Emission ConsistencyThe 2. Gas Optimization (Optional)Line 1562: The check reads from storage (
3. Test Enhancement Suggestion (Optional)Consider adding a test for the WITHDRAW case to complement the DEPOSIT test: function test_CompleteProcessing_RevertWithdrawIdMismatch() public {
// Similar to deposit test but for withdraw operation
}This would complete the test coverage for all non-CREATE operations. 4. CLOSE_YIELDVAULT Edge CaseThe fix handles CLOSE correctly through the ID mismatch check. However, the unregister validation at line 1592 adds a second layer of defense. This defense-in-depth approach is good, though it means:
🎯 RecommendationsReady to Merge ✅The changes are production-ready with the following minor suggestions:
No Blocking Issues
📋 Checklist
Excellent work on this security enhancement! The PR directly addresses the identified vulnerability with minimal code changes and maximum defensive benefit. |
PR Review: Add checks to guard against local registry YieldVault IDs corruptionSummaryThis PR addresses issue #24 by adding three defensive checks to prevent YieldVault ID corruption in the EVM-side registry. The changes are well-targeted and directly address the security concerns outlined in the issue. Code Quality & Best Practices ✅Strengths:
Security Analysis ✅The three guards work together to prevent the corruption scenarios described in issue #24: 1. ID Mismatch Protection (lines 1120-1126)Purpose: Prevents COA from accidentally completing a DEPOSIT/WITHDRAW/CLOSE request with a different YieldVault ID than originally specified. Security impact:
2. Duplicate Registration Protection (lines 1562-1564)Purpose: Prevents re-registering an already-valid YieldVault ID. Security impact:
3. Ownership Validation on Unregister (lines 1592-1594)Purpose: Ensures the vault being unregistered actually belongs to the specified user. Security impact:
Overall security assessment: These checks effectively address the corruption vectors identified in issue #24. The defense-in-depth approach is appropriate for a cross-VM bridge where operational mistakes could have significant impact. Test Coverage ✅The PR adds three comprehensive test cases that cover the main scenarios. Minor suggestions for additional coverage:
Performance Considerations ✅All three checks are extremely efficient:
Total overhead: <5000 gas in worst case, negligible compared to typical request processing costs. Minor Suggestions
ConclusionRecommendation: APPROVE ✅ This is a well-crafted security fix that directly addresses the identified vulnerability. The implementation is clean, efficient, and follows best practices. The changes are minimal and focused, reducing risk of introducing new bugs. The PR successfully closes issue #24 and strengthens the integrity of the EVM-side YieldVault registry against operational mistakes from the Cadence worker. |
Pull Request Review: FLOW-9 - Guard Against Local Registry CorruptionSummaryThis PR addresses a critical security issue where COA operational mistakes could corrupt the EVM-side registry by adding three defensive checks to prevent YieldVault ID misbinding. The implementation directly addresses all three recommendations from issue #24. ✅ Strengths
🔍 Observations & Suggestions1. Test Coverage Gap - WITHDRAW Request TypeThe PR tests DEPOSIT ID mismatch but not WITHDRAW. Consider adding a test for WITHDRAW operations: function test_CompleteProcessing_RevertWithdrawIdMismatch() public {
// Setup: create vault with ID 100
vm.prank(user);
uint256 createReq = c.createYieldVault{value: 1 ether}(NATIVE_FLOW, 1 ether, VAULT_ID, STRATEGY_ID);
vm.startPrank(coa);
c.startProcessing(createReq);
c.completeProcessing(createReq, true, 100, "Created");
vm.stopPrank();
// Deposit to build up balance
vm.prank(user);
uint256 depositReq = c.depositToYieldVault{value: 1 ether}(100, NATIVE_FLOW, 1 ether);
vm.startPrank(coa);
c.startProcessing(depositReq);
c.completeProcessing(depositReq, true, 100, "Deposited");
vm.stopPrank();
// Try to withdraw but COA provides wrong ID
vm.prank(user);
uint256 withdrawReq = c.withdrawFromYieldVault(100, 0.5 ether);
vm.startPrank(coa);
c.startProcessing(withdrawReq);
vm.expectRevert(abi.encodeWithSelector(
FlowYieldVaultsRequests.YieldVaultIdMismatch.selector,
100, // expected
101 // provided (wrong)
));
c.completeProcessing(withdrawReq, true, 101, "Wrong ID");
vm.stopPrank();
}2. Potential Edge Case - CLOSE with Wrong UserThe test Consider adding: function test_CompleteProcessing_RevertCloseWithWrongUserVault() public {
// User1 creates vault 100
vm.prank(user);
uint256 req1 = c.createYieldVault{value: 1 ether}(NATIVE_FLOW, 1 ether, VAULT_ID, STRATEGY_ID);
vm.startPrank(coa);
c.startProcessing(req1);
c.completeProcessing(req1, true, 100, "Created");
vm.stopPrank();
// User2 creates vault 101
vm.prank(user2);
uint256 req2 = c.createYieldVault{value: 1 ether}(NATIVE_FLOW, 1 ether, VAULT_ID, STRATEGY_ID);
vm.startPrank(coa);
c.startProcessing(req2);
c.completeProcessing(req2, true, 101, "Created");
vm.stopPrank();
// User1 closes their vault but COA mistakenly tries to close user2's vault
vm.prank(user);
uint256 closeReq = c.closeYieldVault(100);
vm.startPrank(coa);
c.startProcessing(closeReq);
vm.expectRevert(abi.encodeWithSelector(
FlowYieldVaultsRequests.InvalidYieldVaultId.selector,
101, // yieldVaultId provided
user // request.user (who doesn't own 101)
));
c.completeProcessing(closeReq, true, 101, "Wrong vault");
vm.stopPrank();
}This would catch the exact scenario described in the issue where Alice's CLOSE request could accidentally unregister Bob's vault. 3. Documentation EnhancementConsider adding inline comments explaining the two-path logic in // Enforce strong ID binding for DEPOSIT/WITHDRAW/CLOSE by requiring the
// supplied yieldVaultId matches the request's stored yieldVaultId
if (request.requestType == RequestType.CREATE_YIELDVAULT) {
// CREATE: assign the Cadence-generated ID (first time we learn it)
request.yieldVaultId = yieldVaultId;
} else if (request.yieldVaultId != yieldVaultId) {
// DEPOSIT/WITHDRAW/CLOSE: enforce ID must match what user specified
revert YieldVaultIdMismatch(request.yieldVaultId, yieldVaultId);
}🛡️ Security AnalysisAttack Vector Prevention ✅Vector 1: Duplicate Registration
Vector 2: ID Misbinding on DEPOSIT/WITHDRAW/CLOSE
Vector 3: Cross-User Unregistration
Gas Considerations
Reentrancy
📋 Code QualityBest Practices ✅
Potential Improvements
/// @notice Thrown when attempting to register a YieldVault ID that already exists
/// @param yieldVaultId The duplicate YieldVault ID
error YieldVaultIdAlreadyRegistered(uint64 yieldVaultId);
/// @notice Thrown when COA provides mismatched YieldVault ID during request completion
/// @param expectedId The YieldVault ID stored in the request
/// @param providedId The YieldVault ID provided by COA
error YieldVaultIdMismatch(uint64 expectedId, uint64 providedId);✅ ConclusionThis PR successfully addresses a critical security vulnerability with minimal code changes and excellent test coverage. The implementation is sound, follows Solidity best practices, and maintains backward compatibility. Recommendation: APPROVE with minor suggestions The suggested additional tests would strengthen coverage but are not blockers for merging, as the core vulnerability is properly fixed. The current implementation correctly prevents all three attack vectors identified in issue #24. Risk Assessment: Low - Changes are defensive (add validation only), well-tested, and don't modify core business logic. Great work @m-Peter! 🎉 |
|
Forgot to Approve but LGTM ! Approved here... |
Closes: #24