Manipulation of governance voting result deviating from voted outcome and resulting in a direct change from intended effect of original results
Description
Description
The _balanceOfTokenAt function in the Voting Escrow contract calculates the voting power of tokens without verifying if the locks have expired. This results in expired token locks still contributing to the voting power, which can lead to inaccurate representation of active voter support in governance decisions.
Impact
Including expired locks in the vote weight calculation can distort the actual voting outcomes, enabling outdated stakes to influence current governance decisions. This misalignment can lead to decisions that do not reflect the present intentions of active stakeholders, undermining the protocol's governance integrity and effectiveness.
Incorporating a check at the beginning of the _balanceOfTokenAt function to verify that the token's lock has not expired ensures that the function returns a vote weight of zero for expired tokens. This modification prevents expired locks from affecting vote weight calculations, ensuring that the voting power reflects only the active and legitimate stakes, thereby enhancing the accuracy and fairness of governance processes.
import timeclassTokenLock:def__init__(self,end_time): self.end_time = end_timeclassVotingSystem:def__init__(self): self.locks ={} self.current_time =int(time.time())defadd_token_lock(self,token_id,end_time): self.locks[token_id]=TokenLock(end_time)def_balance_of_token_at_issue(self,token_id): lock = self.locks.get(token_id)ifnot lock:return0# Original code that does not check for expirationreturn100if self.current_time <= lock.end_time else0def_balance_of_token_at_fixed(self,token_id): lock = self.locks.get(token_id)ifnot lock or self.current_time > lock.end_time:return0# Fixed code with expiration checkreturn100defsimulate_voting_power(self): token_id =1 end_time = self.current_time +10# Token expires after 10 seconds self.add_token_lock(token_id, end_time)# Checking before expirationprint("Votes before expiration (Issue):", self._balance_of_token_at_issue(token_id))print("Votes before expiration (Fixed):", self._balance_of_token_at_fixed(token_id))# Simulate time passing beyond token expiration time.sleep(11) self.current_time =int(time.time())# Checking after expirationprint("Votes after expiration (Issue):", self._balance_of_token_at_issue(token_id))print("Votes after expiration (Fixed):", self._balance_of_token_at_fixed(token_id))# Create instance of the voting systemvoting_system =VotingSystem()voting_system.simulate_voting_power()
Expected Output
Before Token Expiration:
With the issue: Votes before expiration (Issue): 100
With the fix: Votes before expiration (Fixed): 100
After Token Expiration:
With the issue: Votes after expiration (Issue): 0 (This output might mistakenly show a value other than zero if not properly handled in the real contract)
With the fix: Votes after expiration (Fixed): 0
This script simulates the problem of token locks influencing voting weights after expiration and the effectiveness of the proposed solution in ensuring only active tokens contribute to voting power.