Skip to content

Commit

Permalink
rewards: added a view function to get hint params
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbrai committed Jan 8, 2024
1 parent b64f964 commit 62d5762
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 19 deletions.
65 changes: 55 additions & 10 deletions packages/nouns-contracts/contracts/Rewards.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ contract Rewards {
uint16 public proposalRewardBps = 100; // TODO make configurable
uint16 public votingRewardBps = 50; // TODO make configurable
uint16 public auctionRewardBps = 100; // TODO make configurable

mapping(uint32 clientId => uint256 balance) public clientBalances;

struct ClientData {
Expand Down Expand Up @@ -89,10 +90,10 @@ contract Rewards {
*
* @param expectedNumEligibleProposals should match the number of eligible proposals. TODO: a view function for this
*/
function bountyRewardForProposals(
function updateRewardsForProposalWritingAndVoting(
uint32 lastProposalId,
uint256 expectedNumEligibleProposals,
uint256 expectedNumEligibileVotes,
uint256 expectedNumEligibleVotes,
uint256 firstNounId,
uint256 lastNounId,
uint32[] calldata votingClientIds
Expand Down Expand Up @@ -121,23 +122,19 @@ contract Rewards {
lastNounId: lastNounId
});

require(auctionRevenue > 0, 'auctionRevenue must be > 0');

t.proposalRewardForPeriod = (auctionRevenue * proposalRewardBps) / 10000;
t.votingRewardForPeriod = (auctionRevenue * votingRewardBps) / 10000;

nextProposalRewardTimestamp = t.proposal.creationTimestamp + 1;

t.rewardPerProposal = t.proposalRewardForPeriod / expectedNumEligibleProposals;
t.rewardPerVote = t.votingRewardForPeriod / expectedNumEligibileVotes;
t.rewardPerVote = t.votingRewardForPeriod / expectedNumEligibleVotes;

uint32 lowestProposalIdToReward = nextProposalIdToReward;
nextProposalIdToReward = lastProposalId + 1;

// TODO: remove this, just for gas measuring purposes
for (uint256 i; i < votingClientIds.length; ++i) {
clientBalances[votingClientIds[i]] += 1;
}
// END TODO

for (uint32 pid = lastProposalId; pid >= lowestProposalIdToReward; pid--) {
if (pid != lastProposalId) {
t.proposal = nounsDAO.proposalDataForRewards(pid);
Expand Down Expand Up @@ -179,7 +176,55 @@ contract Rewards {
}

require(t.actualNumEligibleProposals == expectedNumEligibleProposals, 'wrong expectedNumEligibleProposals');
require(t.actualNumEligibleVotes == expectedNumEligibileVotes, 'wrong expectedNumEligibileVotes');
require(t.actualNumEligibleVotes == expectedNumEligibleVotes, 'wrong expectedNumEligibleVotes');
}

struct ProposalRewardsParams {
uint32 lastProposalId;
uint256 expectedNumEligibleProposals;
uint256 expectedNumEligibleVotes;
uint256 firstNounId;
uint256 lastNounId;
}

function getParamsForUpdatingProposalRewards(
uint32 lastProposalId
) public view returns (ProposalRewardsParams memory p) {
NounsDAOStorageV3.ProposalForRewards memory proposal;

for (uint32 pid = nextProposalIdToReward; pid <= lastProposalId; pid++) {
proposal = nounsDAO.proposalDataForRewards(pid);

// make sure proposal finished voting
uint endBlock = max(proposal.endBlock, proposal.objectionPeriodEndBlock);
require(block.number > endBlock, 'all proposals must be done with voting');

// skip non eligible proposals TODO: parameterize quorum
if (proposal.forVotes < (proposal.totalSupply * 1000) / 10000) continue;

// proposal is eligible for reward
++p.expectedNumEligibleProposals;

uint256 proposalTotalVotes = proposal.forVotes + proposal.againstVotes + proposal.abstainVotes;
p.expectedNumEligibleVotes += proposalTotalVotes;
}

p.firstNounId = findAuctionBefore(nextProposalRewardTimestamp);
p.lastNounId = findAuctionBefore(nounsDAO.proposalDataForRewards(lastProposalId).creationTimestamp) + 2; // TODO why + 2?
}

function findAuctionBefore(uint256 timestamp) internal view returns (uint256) {
uint256 maxAuctionId = auctionHouse.auction().nounId - 1;

INounsAuctionHouseV2.Settlement[] memory s;

for (uint256 nounId = maxAuctionId; nounId > 0; nounId--) {
s = auctionHouse.getSettlements(nounId, nounId + 1, true);

if (s.length == 0) continue; // nounder reward or missing data

if (s[0].blockTimestamp <= timestamp) return nounId;
}
}

function getAuctionRevenueForPeriod(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.19;

import { NounsDAOLogicV3BaseTest } from './NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol';
import { Rewards } from '../../contracts/Rewards.sol';
import { NounsToken } from '../../contracts/NounsToken.sol';
import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol';
import { AuctionHouseUpgrader } from './helpers/AuctionHouseUpgrader.sol';
import { NounsAuctionHouseProxy } from '../../contracts/proxies/NounsAuctionHouseProxy.sol';
import { NounsDAOLogicV3BaseTest } from '../NounsDAOLogicV3/NounsDAOLogicV3BaseTest.sol';
import { Rewards } from '../../../contracts/Rewards.sol';
import { NounsToken } from '../../../contracts/NounsToken.sol';
import { INounsAuctionHouseV2 } from '../../../contracts/interfaces/INounsAuctionHouseV2.sol';
import { AuctionHouseUpgrader } from '../helpers/AuctionHouseUpgrader.sol';
import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol';

abstract contract RewardsBaseTest is NounsDAOLogicV3BaseTest {
Rewards rewards;
Expand Down Expand Up @@ -105,6 +105,10 @@ contract AuctionRewards is RewardsBaseTest {
}

contract ProposalRewards is RewardsBaseTest {
// function test
}

contract ProposalRewardsHappyFlow is RewardsBaseTest {
uint256 proposalId;
uint256 settledNounIdBeforeProposal;
uint256 nounOnAuctionWhenLastProposalWasCreated;
Expand Down Expand Up @@ -177,16 +181,24 @@ contract ProposalRewards is RewardsBaseTest {
}
}

function test_auctionRevenueBounty_happyFlow() public {
function testHappyFlow() public {
clientIds = [0, CLIENT_ID, CLIENT_ID2];

rewards.bountyRewardForProposals({
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: uint32(proposalId),
expectedNumEligibleProposals: 11,
expectedNumEligibileVotes: 270,
expectedNumEligibleVotes: 270,
firstNounId: settledNounIdBeforeProposal,
lastNounId: nounOnAuctionWhenLastProposalWasCreated + 1, // TODO: why do we not include the lastNounId ?
votingClientIds: clientIds
});
}

function testGetHintParams() public {
Rewards.ProposalRewardsParams memory params = rewards.getParamsForUpdatingProposalRewards(uint32(proposalId));
assertEq(params.expectedNumEligibleProposals, 11);
assertEq(params.expectedNumEligibleVotes, 270);
assertEq(params.firstNounId, settledNounIdBeforeProposal);
assertEq(params.lastNounId, nounOnAuctionWhenLastProposalWasCreated + 1);
}
}

0 comments on commit 62d5762

Please sign in to comment.