Skip to content

Commit

Permalink
85% tc
Browse files Browse the repository at this point in the history
  • Loading branch information
jordaniza committed Sep 8, 2024
1 parent bbeb31a commit fd6d1a8
Show file tree
Hide file tree
Showing 9 changed files with 219 additions and 124 deletions.
60 changes: 21 additions & 39 deletions src/escrow/increasing/VotingEscrowIncreasing.sol
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ contract VotingEscrow is
_disableInitializers();
}

// todo add the initializer inheritance chain
function initialize(
address _token,
address _dao,
Expand All @@ -133,10 +132,6 @@ contract VotingEscrow is
// allow sending tokens to this contract
whitelisted[address(this)] = true;
emit WhitelistSet(address(this), true);

// rm the zero id
// emit Transfer(address(0), address(this), tokenId);
// emit Transfer(address(this), address(0), tokenId);
}

/*//////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -196,7 +191,7 @@ contract VotingEscrow is
}

/*///////////////////////////////////////////////////////////////
Getters: Voting Power
Getters: Voting
//////////////////////////////////////////////////////////////*/

/// @return The voting power of the NFT at the current block
Expand Down Expand Up @@ -240,6 +235,11 @@ contract VotingEscrow is
}
}

/// @notice Checks if the NFT is currently voting. We require the user to reset their votes if so.
function isVoting(uint256 _tokenId) public view returns (bool) {
return ISimpleGaugeVoter(voter).isVoting(_tokenId);
}

/*//////////////////////////////////////////////////////////////
ERC721 LOGIC
//////////////////////////////////////////////////////////////*/
Expand Down Expand Up @@ -350,12 +350,18 @@ contract VotingEscrow is
Exit and Withdraw Logic
//////////////////////////////////////////////////////////////*/

/// @notice Resets the votes and begins the withdrawal process for a given tokenId
/// @dev Convenience function, the user must have authorized this contract to act on their behalf.
function resetVotesAndBeginWithdrawal(uint256 _tokenId) external whenNotPaused {
ISimpleGaugeVoter(voter).reset(_tokenId);
beginWithdrawal(_tokenId);
}

/// @notice Enters a tokenId into the withdrawal queue by transferring to this contract and creating a ticket.
/// @param _tokenId The tokenId to begin withdrawal for. Will be transferred to this contract before burning.
/// @dev The user must not have active votes in the voter contract.
function beginWithdrawal(uint256 _tokenId) external nonReentrant whenNotPaused {
function beginWithdrawal(uint256 _tokenId) public nonReentrant whenNotPaused {
// can't exit if you have votes pending
// TODO: UX we could simplify by attempting to withdraw
if (isVoting(_tokenId)) revert CannotExit();
address owner = _ownerOf(_tokenId);
// todo: should we call queue first or second
Expand All @@ -375,14 +381,12 @@ contract VotingEscrow is
uint256 value = oldLocked.amount;

// Burn the NFT
_burn(_tokenId); // todo: at the moment this doesn't like that the contract owns the token
// TODO double check ownership here to make sure only correct burner
_burn(_tokenId);
_locked[_tokenId] = LockedBalance(0, 0);
uint256 supplyBefore = totalLocked;
totalLocked = supplyBefore - value;

// oldLocked can have either expired <= timestamp or zero end
// oldLocked has only 0 end
// Both can have >= 0 amount
// TODO: we need to reset the locked balance here, not have it lingering
_checkpoint(_tokenId, oldLocked, LockedBalance(0, 0));

Expand All @@ -391,45 +395,23 @@ contract VotingEscrow is
emit Withdraw(sender, _tokenId, value, block.timestamp, totalLocked);
}

/*//////////////////////////////////////////////////////////////
Voting Logic
//////////////////////////////////////////////////////////////*/

function isVoting(uint256 _tokenId) public view returns (bool) {
return ISimpleGaugeVoter(voter).isVoting(_tokenId);
}

/*///////////////////////////////////////////////////////////////
IVotes Ideas
IVotes-ish
//////////////////////////////////////////////////////////////*/

// TODO - let's check delegation in depth to see if this iface makes sense
// TODO - review if it makes sense to do this
// we need to be careful, as totalSupply in this contract
// refers to the total number of NFTs minted, not the total voting power
// so we don't want to mislead callers by exposing a similar function

function getVotes(uint256 _tokenId) external view returns (uint256) {
return votingPowerAt(_tokenId, block.timestamp);
}

function getVotes(address _account, uint256 _tokenId) external view returns (uint256) {
if (_ownerOf(_tokenId) != _account) return 0;
return votingPowerAt(_tokenId, block.timestamp);
}

function getPastVotes(uint256 _tokenId, uint256 _timestamp) external view returns (uint256) {
return votingPowerAt(_tokenId, _timestamp);
}

function getPastVotes(
address _account,
uint256 _tokenId,
uint256 _timestamp
) external view returns (uint256) {
revert NotImplemented();
}

function getPastTotalSupply(uint256 _timestamp) external view returns (uint256) {
return totalVotingPowerAt(_timestamp);
}

/*///////////////////////////////////////////////////////////////
UUPS Upgrade
//////////////////////////////////////////////////////////////*/
Expand Down
9 changes: 9 additions & 0 deletions src/voting/GaugeVoting.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,12 @@ Gauge management:
- votes can't exceed max voting power
- Events are emit as expected f
-

Voting:

- only vote when voting is active
- only vote with tokens you own
-

- multiple votes resets voting power
- multiple voters calcs correctly
21 changes: 15 additions & 6 deletions src/voting/ISimpleGaugeVoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,26 @@ interface IGauge {
struct Gauge {
bool active;
uint256 created; // timestamp or epoch
bytes32 metadata; // TODO - check how OSx stores this, might just be IPFS
// address addr; // TODO do we need this
bytes32 metadata; // TODO => do we need this onchain or can just be event emitted?
// more space for data as this is a struct in a mapping
}
}

interface IGaugeVote {
/// @param votes gauge => votes cast at that time
/// @param gaugesVotedFor array of gauges we have active votes for
/// @param usedWeight total voting power used at the time of the vote
/// @dev this changes so we need an historic snapshot
/// @param lastVoted is the last time the user voted
struct TokenVoteData {
mapping(address => uint256) votes;
address[] gaugesVotedFor;
uint256 usedWeight;
uint256 lastVoted;
}

/// @param weight proportion of voting power the token will allocate to the gauge. Will be normalised.
/// @param gauge address of the gauge to vote for
struct GaugeVote {
uint256 weight;
address gauge;
Expand Down Expand Up @@ -61,15 +67,17 @@ interface IGaugeVoterEvents {
event Voted(
address indexed voter,
address indexed gauge,
uint256 indexed tokenId,
uint256 indexed epoch,
uint256 tokenId,
uint256 weight,
uint256 totalWeight,
uint256 timestamp
);
event Reset(
address indexed voter,
address indexed gauge,
uint256 indexed tokenId,
uint256 indexed epoch,
uint256 tokenId,
uint256 weight,
uint256 totalWeight,
uint256 timestamp
Expand All @@ -82,9 +90,9 @@ interface IGaugeVoterErrors {
error NotApprovedOrOwner();
error GaugeDoesNotExist(address _pool);
error GaugeInactive(address _gauge);
error NonZeroVotes();
error MustReset();
error NoVotes();
error ExceedMaxVoteOptions();
error NoVotingPower();
}

interface IGaugeVoter is IGaugeVoterEvents, IGaugeVoterErrors, IGaugeVote {
Expand All @@ -97,6 +105,7 @@ interface IGaugeVoter is IGaugeVoterEvents, IGaugeVoterErrors, IGaugeVote {
/// @param _tokenId Id of veNFT you are reseting.
function reset(uint256 _tokenId) external;

/// @notice Can be called to check if a token is currently voting
function isVoting(uint256 _tokenId) external view returns (bool);
}

Expand Down
Loading

0 comments on commit fd6d1a8

Please sign in to comment.