Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Latest commit

 

History

History
146 lines (106 loc) · 4.9 KB

012.md

File metadata and controls

146 lines (106 loc) · 4.9 KB

ctf_sec

medium

Minting or burning governance voting token changes voting token supply which affect the ongoing proposal voting.

Summary

Minting or burning governance voting token changes token supply which affect the ongoing proposal voting.

Vulnerability Detail

Either using UXD Council token or using using UXP token, both token can be minted or burned

For UXDCouncilToken

/// @title UXDCouncilToken
/// @notice UXD governance council token
contract UXDCouncilToken is Ownable, ERC20, ERC20Permit, ERC20Votes {

    constructor(address guardian) ERC20("UXD Council Token", "UXDCouncil") ERC20Permit("UXDCouncil") {
        mint(guardian, 1 * 10 ** decimals());
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }

    function burn(uint256 amount) external {
        _burn(msg.sender, amount);
    }

For UXPToken

/// @notice Mint new tokens to an address
/// @dev Can only be called by owner.
/// @param account the address to mint to
/// @param amount the amount to mint
function mint(address account, uint256 amount) external onlyOwner {
	_mint(account, amount);
}

/// @notice Burn tokens from an address 
/// @dev Can only be called by owner. `account` must have approved the caller to spend `amount`.
/// @param account the address to burn from
/// @param amount the amount to burn
function burn(address account, uint256 amount) external onlyOwner {
	if (account != msg.sender) {
		_spendAllowance(account, msg.sender, amount);
	}
	_burn(account, amount);
}

However, the governor contract replies a quorom of the voting power in order to pass the proposal.

contract UXDGovernor is
    ReentrancyGuard,
    Governor,
    GovernorVotes,
    GovernorVotesQuorumFraction,
    GovernorTimelockControl,
    GovernorCountingSimple,
    GovernorSettings
{
    ///         Errors
    error GovERC20ApprovalFailed(address token, address to, uint256 amount);
    error GovERC20TransferFailed(address token, address to, uint256 amount);

    constructor(IVotes _token, TimelockController _timelock, GovernorParams memory _params)
        Governor("UXDGovernor")
        GovernorVotes(_token)
        GovernorSettings(_params.votingDelay, _params.votingPeriod, _params.proposalThreshold)
        GovernorVotesQuorumFraction(_params.quorumFraction)
        GovernorTimelockControl(_timelock)
    {}

If we look into the GovernorVotesQuorumFraction contract

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/4fc19ddb8dd1de3b828c32942896d527cf0e8eda/contracts/governance/extensions/GovernorVotesQuorumFraction.sol#L16

/**
 * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a
 * fraction of the total supply.
 *
 * _Available since v4.3._
 */
abstract contract GovernorVotesQuorumFraction is GovernorVotes {
    using Checkpoints for Checkpoints.History;

    uint256 private _quorumNumerator; // DEPRECATED
    Checkpoints.History private _quorumNumeratorHistory;

    event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator);

    /**
     * @dev Initialize quorum as a fraction of the token's total supply.
     *
     * The fraction is specified as `numerator / denominator`. By default the denominator is 100, so quorum is
     * specified as a percent: a numerator of 10 corresponds to quorum being 10% of total supply. The denominator can be
     * customized by overriding {quorumDenominator}.
     */
    constructor(uint256 quorumNumeratorValue) {
        _updateQuorumNumerator(quorumNumeratorValue);
    }

a quorum is expressed as a fraction of the total supply.

However, with minting voting or burning token, the total supply is constantly changing.

Consider this case:

Initial, the total supply is 10000 UXD council token

Qrum s set to 10% of the total supplym meaning it is required that 1000 UXD counciloted to pass a proposal. A group of user manages to get 990 UXD.

At this point, more council token is minted, the total supply becomes 20000 UXD council tokens, the voting power of the previous group that got 990 UXD is diluted and they have to get 1000 more token they expected.

If the UXD council token is burned and the quorum requirement becomes lower, allowing voting manipulation and the bar to pass a proposal becomes lower if a user already has a lot of voting token.

Impact

Burning or minting of the governance voting token affect ongoing proposal.

Code Snippet

https://github.com/sherlock-audit/2023-01-uxd/blob/main/contracts/governance/UXDGovernor.sol#L32-L53

https://github.com/sherlock-audit/2023-01-uxd/blob/main/contracts/governance/UXDCouncilToken.sol#L8-L24

https://github.com/sherlock-audit/2023-01-uxd/blob/main/contracts/governance/UXPToken.sol#L9-L54

Tool used

Manual Review

Recommendation

We recommend the project fix the total supply of the voting token to not let changing of the total supply affect ongoing proposal.