Conversation
passandscore
left a comment
There was a problem hiding this comment.
[INFO] Reputation providers can self-exit without approver consent. unstake() only checks approverLockCount[msg.sender] == 0 — a reputation provider (who isn't an approver themselves) can always call unstake(). I see this is tested (test_WithdrawClearsReputationStatus), so it's intentional. Just confirming: the "lock" is one-directional — it locks the approver from leaving, not the reputation provider.
[INFO] Commitment-time vs settlement-time mismatch. A bidder can submit a bid where slashAmt > 100 * bidAmt. The provider commits to it, but at settlement the slash is silently capped. This benefits the provider (less risk than committed to) but means the bidder's stated slashing terms aren't honored. Consider whether this should be validated at commitment time as well — otherwise a bidder who set a high slashAmt as a credibility signal gets weaker enforcement than they expected.
Missing Test Coverage
- No test for the slash cap in PreconfManager (the 100:1 ratio). Consider adding a test where slashAmt >
100 * bidAmt and verifying the provider is only slashed 100 * bidAmt. - No test for setReputationMinStake access control (onlyOwner revert case).
- No test for what happens when reputationMinStake is changed while providers are active.
- No test for the case where an approver gets slashed below minStake and then tries to approve another
reputation provider (should fail at the providerStakes[msg.sender] >= minStake check).
|
|
||
| abstract contract PreconfManagerStorage { | ||
| /// @dev Maximum ratio of slash amount to bid amount | ||
| uint256 public constant MAX_SLASH_BID_RATIO = 100; |
There was a problem hiding this comment.
[LOW] Hardcoded constant requires upgrade to change. If you ever need to adjust the ratio, it requires a full contract upgrade. Consider making it an owner-configurable state variable with a setter, similar to setMinStake.
| address approver = reputationProviderApprover[provider]; | ||
| require(approver != address(0), ProviderIsNotReputationProvider(provider)); | ||
|
|
||
| require(msg.sender == approver, NotApprover(msg.sender)); |
There was a problem hiding this comment.
[MEDIUM] If a standard provider (the approver) loses their keys or becomes uncooperative, the owner has no ability to remove the reputation provider they vouched for. The reputation provider can self-exit via unstake() → withdraw(), but the owner cannot intervene. Consider adding msg.sender == approver || msg.sender == owner() to the require, or a separate ownerForceRemoveReputationProvider function.
There was a problem hiding this comment.
Can you clarify? In the approveReputationRegistration() function we set reputationProviderApprover[provider] = msg.sender;. This should allow the owner to remove a reputation provider they vouched for here.
There was a problem hiding this comment.
You're right. So, I guess we can ask --> should the owner have an override to remove reputation providers they didn't personally approve? That's a governance design choice, not a bug.
| emit FundsDeposited(provider, msg.value); | ||
|
|
||
| // Auto-convert reputation provider to standard if they reach minStake | ||
| if (reputationProviderApprover[provider] != address(0) && providerStakes[provider] >= minStake) { |
There was a problem hiding this comment.
[LOW] No event on auto-conversion. The auto-conversion logic in _stake() deletes the
reputation status and decrements the approver lock, but emits no event. Off-chain indexers won't know a
provider was converted from reputation to standard. Consider emitting a ReputationProviderConverted(provider, approver) event.
| require(!providerRegistered[msg.sender], ProviderAlreadyRegistered(msg.sender)); | ||
| require(pendingReputationStake[msg.sender] == 0, PendingReputationRequestExists(msg.sender)); | ||
| require(reputationMinStake != 0, InsufficientReputationStake(0, 0)); | ||
| require(msg.value >= reputationMinStake, InsufficientReputationStake(msg.value, reputationMinStake)); |
There was a problem hiding this comment.
[LOW] Reputation provider can request with more than reputationMinStake but less than minStake.requestReputationRegistration accepts any msg.value >= reputationMinStake. If someone sends e.g. 4.99 ETH, they're registered as a reputation provider (with approver lock overhead) instead of just doing registerAndStake. Not a vulnerability, but consider adding a check: require(msg.value < minStake, ...) or auto-routing to standard registration.
Describe your changes
Fix for bid position constraint evaluation, on-chain slash cap, and reputation provider registration system.
-initiateSlash() now caps the effective slash amount to 100x the bid amount before passing to ProviderRegistry.slash().
ProviderRegistry: Added a reputation provider registration path allowing providers to register with a lower configurable minimum stake when approved by the contract owner or an existing standard provider.
-fix edge case in bid options
Unrelated: Added Eureka to the builders map for backrunning.
Issue ticket number and link
Fixes # (issue)
Checklist before requesting a review