Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat--tests #5

Merged
merged 8 commits into from
Nov 20, 2023
Merged
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
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ jobs:
out
key: "build-${{ github.sha }}"

- name: Setup repo
uses: ./.github/actions/setup-repo
with:
registry-token: ${{ secrets.GH_REGISTRY_ACCESS_TOKEN }}

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
Expand Down
235 changes: 79 additions & 156 deletions contracts/AngleGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ pragma solidity ^0.8.20;

import { IVotes } from "oz/governance/utils/IVotes.sol";

import { Governor, SafeCast } from "oz/governance/Governor.sol";
import { Governor } from "oz/governance/Governor.sol";
import { GovernorPreventLateQuorum } from "oz/governance/extensions/GovernorPreventLateQuorum.sol";
import { GovernorVotesQuorumFraction, GovernorVotes } from "oz/governance/extensions/GovernorVotesQuorumFraction.sol";
import { GovernorSettings } from "oz/governance/extensions/GovernorSettings.sol";
import { TimelockController } from "oz/governance/TimelockController.sol";
import { IERC5805 } from "oz/interfaces/IERC5805.sol";

import { GovernorProposals } from "./external/GovernorProposals.sol";
import { GovernorPreventLateQuorum } from "./external/GovernorPreventLateQuorum.sol";
import { GovernorToken } from "./external/GovernorToken.sol";
import { GovernorCountingFractional } from "./external/GovernorCountingFractional.sol";
import { GovernorShortCircuit } from "./external/GovernorShortCircuit.sol";
Expand All @@ -30,7 +29,6 @@ import "./utils/Errors.sol";
contract AngleGovernor is
GovernorSettings,
GovernorToken,
GovernorProposals,
GovernorPreventLateQuorum,
GovernorCountingFractional,
GovernorVotesQuorumFraction,
Expand All @@ -46,7 +44,8 @@ contract AngleGovernor is
VARIABLES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

TimelockController private _timelock;
/// @notice Timelock address that owns this contract and can change the system's parameters
TimelockController public timelock;

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
MODIFIER
Expand Down Expand Up @@ -88,13 +87,8 @@ contract AngleGovernor is
VIEW FUNCTIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

/// @notice Timelock address that owns this contract and can change the system's parameters
function timelock() public view returns (address) {
return address(_timelock);
}

function _executor() internal view override(Governor) returns (address) {
return address(_timelock);
return address(timelock);
}

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Expand All @@ -108,16 +102,48 @@ contract AngleGovernor is
_updateTimelock(newTimelock);
}

/// @inheritdoc GovernorSettings
function setVotingDelay(uint48 newVotingDelay) public override onlyExecutor {
_setVotingDelay(newVotingDelay);
}

/// @inheritdoc GovernorSettings
function setVotingPeriod(uint32 newVotingPeriod) public override onlyExecutor {
_setVotingPeriod(newVotingPeriod);
}

/// @inheritdoc GovernorSettings
function setProposalThreshold(uint256 newProposalThreshold) public override onlyExecutor {
_setProposalThreshold(newProposalThreshold);
}

/// @param veANGLEVotingDelegation New IERC5805 veANGLEVotingDelegation contract address
function setVeANGLEVotingDelegation(address veANGLEVotingDelegation) external onlyExecutor {
_setVeANGLEVotingDelegation(veANGLEVotingDelegation);
}

/// @inheritdoc GovernorVotesQuorumFraction
function updateQuorumNumerator(uint256 newQuorumNumerator) external override onlyExecutor {
_updateQuorumNumerator(newQuorumNumerator);
}

/// @param newShortCircuitNumerator Number expressed as x/100 (percentage)
function updateShortCircuitNumerator(uint256 newShortCircuitNumerator) external onlyExecutor {
_updateShortCircuitNumerator(newShortCircuitNumerator);
}

/// @notice Changes the amount of blocks before the voting snapshot
function setVotingDelayBlocks(uint256 newVotingDelayBlocks) external onlyExecutor {
_setVotingDelayBlocks(newVotingDelayBlocks);
}

/// @inheritdoc GovernorPreventLateQuorum
function setLateQuorumVoteExtension(
uint48 newVoteExtension
) public override(GovernorPreventLateQuorum) onlyExecutor {
_setLateQuorumVoteExtension(newVoteExtension);
}

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OVERRIDES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/
Expand All @@ -126,99 +152,21 @@ contract AngleGovernor is
// solhint-disable-next-line
/// @notice Fork from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/FraxGovernorAlpha.sol
function state(uint256 proposalId) public view override returns (ProposalState) {
// We read the struct fields into the stack at once so Solidity emits a single SLOAD
ProposalCore storage proposal = _proposals[proposalId];
bool proposalExecuted = proposal.executed;
bool proposalCanceled = proposal.canceled;

if (proposalExecuted) {
return ProposalState.Executed;
}

if (proposalCanceled) {
return ProposalState.Canceled;
}

uint256 snapshot = proposalSnapshot(proposalId);

if (snapshot == 0) {
revert GovernorNonexistentProposal(proposalId);
}

uint256 currentTimepoint = clock();
ProposalState classicProposalState = Governor.state(proposalId);

if (snapshot >= currentTimepoint || $snapshotTimestampToSnapshotBlockNumber[snapshot] >= block.number) {
return ProposalState.Pending;
}
if (
classicProposalState == ProposalState.Executed ||
classicProposalState == ProposalState.Canceled ||
classicProposalState == ProposalState.Pending
) return classicProposalState;

// Allow early execution when overwhelming majority
(bool isShortCircuitFor, bool isShortCircuitAgainst) = _shortCircuit(proposalId);
if (isShortCircuitFor) {
return ProposalState.Succeeded;
} else if (isShortCircuitAgainst) {
return ProposalState.Defeated;
}

uint256 deadline = proposalDeadline(proposalId);

if (deadline >= currentTimepoint) {
return ProposalState.Active;
} else if (!_quorumReached(proposalId) || !_voteSucceeded(proposalId)) {
return ProposalState.Defeated;
} else if (proposalEta(proposalId) == 0) {
return ProposalState.Succeeded;
} else {
return ProposalState.Queued;
}
}

/// @inheritdoc Governor
// solhint-disable-next-line
/// @notice Fork from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/FraxGovernorAlpha.sol
function _propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description,
address proposer
) internal override returns (uint256 proposalId) {
proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description)));

if (targets.length != values.length || targets.length != calldatas.length || targets.length == 0) {
revert GovernorInvalidProposalLength(targets.length, calldatas.length, values.length);
}
if (_proposals[proposalId].voteStart != 0) {
revert GovernorUnexpectedProposalState(proposalId, state(proposalId), bytes32(0));
}

uint256 snapshot = clock() + votingDelay();
uint256 duration = votingPeriod();

ProposalCore storage proposal = _proposals[proposalId];
proposal.proposer = proposer;
proposal.voteStart = SafeCast.toUint48(snapshot);
proposal.voteDuration = SafeCast.toUint32(duration);

// cf Frax Finance contracts
// Save the block number of the snapshot, so it can be later used to fetch the total outstanding supply
// of veANGLE. We did this so we can still support quorum(timestamp), without breaking the OZ standard.
// The underlying issue is that VE_ANGLE.totalSupply(timestamp) doesn't work for historical values, so we must
// use VE_ANGLE.totalSupply(), or VE_ANGLE.totalSupplyAt(blockNumber).
$snapshotTimestampToSnapshotBlockNumber[snapshot] = block.number + $votingDelayBlocks;

emit ProposalCreated(
proposalId,
proposer,
targets,
values,
new string[](targets.length),
calldatas,
snapshot,
snapshot + duration,
description
);

// Using a named return variable to avoid stack too deep errors
} else return classicProposalState;
}

/// @inheritdoc GovernorVotesQuorumFraction
Expand All @@ -233,49 +181,13 @@ contract AngleGovernor is
quorumDenominator();
}

/// @inheritdoc GovernorPreventLateQuorum
function _castVote(
uint256 proposalId,
address account,
uint8 support,
string memory reason,
bytes memory params
) internal override(Governor, GovernorPreventLateQuorum) returns (uint256) {
return GovernorPreventLateQuorum._castVote(proposalId, account, support, reason, params);
}

/// @inheritdoc GovernorPreventLateQuorum
function proposalDeadline(
uint256 proposalId
) public view override(Governor, GovernorProposals, GovernorPreventLateQuorum) returns (uint256) {
) public view override(Governor, GovernorPreventLateQuorum) returns (uint256) {
return GovernorPreventLateQuorum.proposalDeadline(proposalId);
}

/// @inheritdoc GovernorVotesQuorumFraction
function updateQuorumNumerator(uint256 newQuorumNumerator) external override onlyExecutor {
_updateQuorumNumerator(newQuorumNumerator);
}

/// @inheritdoc GovernorPreventLateQuorum
function setLateQuorumVoteExtension(uint48 newVoteExtension) public override onlyExecutor {
_setLateQuorumVoteExtension(newVoteExtension);
}

/// @inheritdoc GovernorSettings
function setVotingDelay(uint48 newVotingDelay) public override onlyExecutor {
_setVotingDelay(newVotingDelay);
}

/// @inheritdoc GovernorSettings
function setVotingPeriod(uint32 newVotingPeriod) public override onlyExecutor {
_setVotingPeriod(newVotingPeriod);
}

/// @inheritdoc GovernorSettings
function setProposalThreshold(uint256 newProposalThreshold) public override onlyExecutor {
_setProposalThreshold(newProposalThreshold);
}

/// @inheritdoc GovernorSettings
function votingDelay() public view override(Governor, GovernorSettings) returns (uint256) {
return GovernorSettings.votingDelay();
Expand All @@ -291,27 +203,6 @@ contract AngleGovernor is
return GovernorSettings.proposalThreshold();
}

/// @inheritdoc Governor
function proposalSnapshot(
uint256 proposalId
) public view virtual override(Governor, GovernorProposals) returns (uint256) {
return GovernorProposals.proposalSnapshot(proposalId);
}

/// @inheritdoc Governor
function proposalProposer(
uint256 proposalId
) public view virtual override(Governor, GovernorProposals) returns (address) {
return GovernorProposals.proposalProposer(proposalId);
}

/// @inheritdoc Governor
function proposalEta(
uint256 proposalId
) public view virtual override(Governor, GovernorProposals) returns (uint256) {
return GovernorProposals.proposalEta(proposalId);
}

/// @inheritdoc GovernorVotes
function token() public view override(GovernorToken, GovernorVotes) returns (IERC5805) {
return GovernorToken.token();
Expand All @@ -321,8 +212,40 @@ contract AngleGovernor is
INTERNALS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

/// @inheritdoc Governor
// solhint-disable-next-line
/// @notice Fork from Frax Finance: https://github.com/FraxFinance/frax-governance/blob/e465513ac282aa7bfd6744b3136354fae51fed3c/src/FraxGovernorAlpha.sol
function _propose(
address[] memory targets,
uint256[] memory values,
bytes[] memory calldatas,
string memory description,
address proposer
) internal override returns (uint256 proposalId) {
proposalId = super._propose(targets, values, calldatas, description, proposer);

// cf Frax Finance contracts
// Save the block number of the snapshot, so it can be later used to fetch the total outstanding supply
// of veANGLE. We did this so we can still support quorum(timestamp), without breaking the OZ standard.
// The underlying issue is that VE_ANGLE.totalSupply(timestamp) doesn't work for historical values, so we must
// use VE_ANGLE.totalSupply(), or VE_ANGLE.totalSupplyAt(blockNumber).
uint256 snapshot = proposalSnapshot(proposalId);
$snapshotTimestampToSnapshotBlockNumber[snapshot] = block.number + $votingDelayBlocks;
}

/// @inheritdoc GovernorPreventLateQuorum
function _castVote(
uint256 proposalId,
address account,
uint8 support,
string memory reason,
bytes memory params
) internal override(Governor, GovernorPreventLateQuorum) returns (uint256) {
return GovernorPreventLateQuorum._castVote(proposalId, account, support, reason, params);
}

function _updateTimelock(TimelockController newTimelock) private {
emit TimelockChange(address(_timelock), address(newTimelock));
_timelock = newTimelock;
emit TimelockChange(address(timelock), address(newTimelock));
timelock = newTimelock;
}
}
9 changes: 5 additions & 4 deletions contracts/VeANGLEVotingDelegation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract VeANGLEVotingDelegation is EIP712, IERC5805 {

/// @notice vote weight multiplier taken from veANGLE
/// TODO: update to our case
uint256 public constant VOTE_WEIGHT_MULTIPLIER = 3;
uint256 public constant VOTE_WEIGHT_MULTIPLIER = 1;

/// @notice Typehash needed for delegations by signature
/// @dev keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)")
Expand Down Expand Up @@ -89,7 +89,7 @@ contract VeANGLEVotingDelegation is EIP712, IERC5805 {

// It's possible that some delegated veANGLE has expired.
// Add up all expirations during this time period, week by week.
(uint256 totalExpiredBias, uint256 totalExpiredSlope, uint256 totalExpiredAngle) = _calculateExpirations({
(uint256 totalExpiredBias, uint256 totalExpiredSlope, ) = _calculateExpirations({
account: voter,
start: checkpoint.timestamp,
end: timestamp,
Expand All @@ -98,14 +98,15 @@ contract VeANGLEVotingDelegation is EIP712, IERC5805 {

uint256 expirationAdjustedBias = checkpoint.normalizedBias - totalExpiredBias;
uint256 expirationAdjustedSlope = checkpoint.normalizedSlope - totalExpiredSlope;
uint256 expirationAdjustedAngle = checkpoint.totalAngle - totalExpiredAngle;
// uint256 expirationAdjustedAngle = checkpoint.totalAngle - totalExpiredAngle;

uint256 voteDecay = expirationAdjustedSlope * timestamp;
uint256 biasAtTimestamp = (expirationAdjustedBias > voteDecay) ? expirationAdjustedBias - voteDecay : 0;

// If all delegations are expired they have no voting weight.
// This differs from veANGLE, which returns the locked ANGLE amount if it has not yet been withdrawn.
delegatedWeight = expirationAdjustedAngle + (VOTE_WEIGHT_MULTIPLIER * biasAtTimestamp);
delegatedWeight = VOTE_WEIGHT_MULTIPLIER * biasAtTimestamp;
// delegatedWeight = expirationAdjustedAngle + (VOTE_WEIGHT_MULTIPLIER * biasAtTimestamp);
}

/// @notice Calculates ```account```'s voting weight.
Expand Down
Loading
Loading