Skip to content

Commit

Permalink
rewards: remove lastNounId param
Browse files Browse the repository at this point in the history
Auction house finds the last relevant auction id given the timestamp
  • Loading branch information
davidbrai committed Jan 30, 2024
1 parent ba075c6 commit 500fc13
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 59 deletions.
36 changes: 35 additions & 1 deletion packages/nouns-contracts/contracts/NounsAuctionHouseV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,40 @@ contract NounsAuctionHouseV2 is
require(auctionCount == actualCount, 'Not enough history');
}

function getSettlementsFromIdtoTimestamp(
uint256 startId,
uint256 endTimestamp,
bool skipEmptyValues
) public view returns (Settlement[] memory settlements) {
uint256 maxId = auctionStorage.nounId;
settlements = new Settlement[](maxId - startId + 1);
uint256 actualCount = 0;
SettlementState memory settlementState;
for (uint256 id = startId; id <= maxId; ++id) {
settlementState = settlementHistory[id];

if (skipEmptyValues && settlementState.blockTimestamp <= 1) continue;

if (settlementState.blockTimestamp > endTimestamp) break;

settlements[actualCount] = Settlement({
blockTimestamp: settlementState.blockTimestamp,
amount: uint64PriceToUint256(settlementState.amount),
winner: settlementState.winner,
nounId: id,
clientId: settlementState.clientId
});
++actualCount;
}

if (settlements.length > actualCount) {
// this assembly trims the settlements array, getting rid of unused cells
assembly {
mstore(settlements, actualCount)
}
}
}

/**
* @notice Get a range of past auction settlements.
* @dev Returns prices in chronological order, as opposed to `getSettlements(count)` which returns prices in reverse order.
Expand Down Expand Up @@ -476,7 +510,7 @@ contract NounsAuctionHouseV2 is
}

if (settlements.length > actualCount) {
// this assembly trims the observations array, getting rid of unused cells
// this assembly trims the settlements array, getting rid of unused cells
assembly {
mstore(settlements, actualCount)
}
Expand Down
53 changes: 22 additions & 31 deletions packages/nouns-contracts/contracts/Rewards.sol
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,6 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives'), Ow
params = rewardParams;
}

struct Temp {
uint256 numEligibleVotes;
uint256 rewardPerProposal;
uint256 rewardPerVote;
}

function setParams(RewardParams calldata newParams) public onlyOwner {
params = newParams;
}
Expand All @@ -99,19 +93,20 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives'), Ow
}
}

struct Temp {
uint256 numEligibleVotes;
uint256 rewardPerProposal;
uint256 rewardPerVote;
uint256 proposalRewardForPeriod;
}

/**
* @param lastProposalId id of the last proposal to include in the rewards distribution. all proposals up to and
* including this id must have ended voting.
* @param lastAuctionedNounId the noun id that was auctioned when proposal with id `lastProposalId` was created.
* The auction revenue up to this noun id are included in the bounty.
* @param votingClientIds array of client ids that were used to vote on of all eligible the eligible proposals in
* this rewards distribution
*/
function updateRewardsForProposalWritingAndVoting(
uint32 lastProposalId,
uint256 lastAuctionedNounId,
uint32[] calldata votingClientIds
) public {
function updateRewardsForProposalWritingAndVoting(uint32 lastProposalId, uint32[] calldata votingClientIds) public {
require(lastProposalId <= nounsDAO.proposalCount(), 'bad lastProposalId');
require(lastProposalId >= nextProposalIdToReward, 'bad lastProposalId');

Expand All @@ -124,20 +119,19 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives'), Ow

NounsDAOV3Types.ProposalForRewards memory lastProposal = proposals[proposals.length - 1];

uint256 auctionRevenue = getAuctionRevenueBetweenNouns({
(uint256 auctionRevenue, uint256 lastAuctionId) = getAuctionRevenue({
firstNounId: nextProposalRewardFirstAuctionId,
oneAfterLastNounId: lastAuctionedNounId,
endTimestamp: lastProposal.creationTimestamp
});
nextProposalRewardFirstAuctionId = lastAuctionedNounId;
nextProposalRewardFirstAuctionId = lastAuctionId + 1;

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

uint256 proposalRewardForPeriod = (auctionRevenue * params.proposalRewardBps) / 10_000;
uint256 votingRewardForPeriod = (auctionRevenue * params.votingRewardBps) / 10_000;

Temp memory t;

t.proposalRewardForPeriod = (auctionRevenue * params.proposalRewardBps) / 10_000;
uint256 votingRewardForPeriod = (auctionRevenue * params.votingRewardBps) / 10_000;

uint16 proposalEligibilityQuorumBps_ = params.proposalEligibilityQuorumBps;

//// First loop over the proposals:
Expand Down Expand Up @@ -181,7 +175,7 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives'), Ow
lastProposalRewardsUpdate = lastProposal.creationTimestamp;

// Calculate the reward per proposal and per vote
t.rewardPerProposal = proposalRewardForPeriod / numEligibleProposals;
t.rewardPerProposal = t.proposalRewardForPeriod / numEligibleProposals;
t.rewardPerVote = votingRewardForPeriod / t.numEligibleVotes;

//// Second loop over the proposals:
Expand Down Expand Up @@ -234,24 +228,21 @@ contract Rewards is ERC721('NounsClientIncentives', 'NounsClientIncentives'), Ow
uint32[] votingClientIds;
}

function getAuctionRevenueBetweenNouns(
function getAuctionRevenue(
uint256 firstNounId,
uint256 oneAfterLastNounId,
uint256 endTimestamp
) internal view returns (uint256) {
INounsAuctionHouseV2.Settlement[] memory s = auctionHouse.getSettlements(
) internal view returns (uint256 sumRevenue, uint256 lastAuctionId) {
INounsAuctionHouseV2.Settlement[] memory s = auctionHouse.getSettlementsFromIdtoTimestamp(
firstNounId,
oneAfterLastNounId + 1,
endTimestamp,
true
);
require(s[s.length - 2].blockTimestamp <= endTimestamp, 'second to last auction must be before end ts');
require(s[s.length - 1].blockTimestamp > endTimestamp, 'last auction must be after end ts');

return sumAuctionsExcludingLast(s);
sumRevenue = sumAuctions(s);
lastAuctionId = s[s.length - 1].nounId;
}

function sumAuctionsExcludingLast(INounsAuctionHouseV2.Settlement[] memory s) internal pure returns (uint256 sum) {
for (uint256 i = 0; i < s.length - 1; ++i) {
function sumAuctions(INounsAuctionHouseV2.Settlement[] memory s) internal pure returns (uint256 sum) {
for (uint256 i = 0; i < s.length; ++i) {
sum += s[i].amount;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ interface INounsAuctionHouseV2 {
bool skipEmptyValues
) external view returns (Settlement[] memory settlements);

function getSettlementsFromIdtoTimestamp(
uint256 startId,
uint256 endTimestamp,
bool skipEmptyValues
) external view returns (Settlement[] memory settlements);

function warmUpSettlementState(uint256[] calldata nounIds) external;

function duration() external view returns (uint256);
Expand Down
38 changes: 12 additions & 26 deletions packages/nouns-contracts/test/foundry/rewards/ProposalRewards.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,11 @@ contract ProposalRewardsTest is BaseProposalRewardsTest {
vm.warp(block.timestamp + 2 weeks + 1);
uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1);

uint256 lastNounId = settleAuction();
settleAuction();
votingClientIds = [0];
vm.expectRevert('auctionRevenue must be > 0');
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});
}
Expand All @@ -165,12 +164,11 @@ contract ProposalRewardsTest is BaseProposalRewardsTest {
vm.warp(block.timestamp + 2 weeks + 1);
uint32 proposalId = proposeAndVote(clientId1);

uint256 lastNounId = settleAuction();
settleAuction();
votingClientIds = [0];
vm.expectRevert('all proposals must be done with voting');
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});
}
Expand All @@ -184,11 +182,10 @@ contract ProposalRewardsTest is BaseProposalRewardsTest {
vm.warp(startTimestamp + 2 weeks + 1);
uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1);

uint256 lastNounId = settleAuction();
settleAuction();
votingClientIds = [0];
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});

Expand All @@ -205,11 +202,10 @@ contract ProposalRewardsTest is BaseProposalRewardsTest {
propose(bidder2, address(1), 1 ether, '', '', 'my proposal', clientId1);
uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId2);

uint256 lastNounId = settleAuction();
settleAuction();
votingClientIds = [0];
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});

Expand All @@ -227,11 +223,10 @@ contract ProposalRewardsTest is BaseProposalRewardsTest {
proposeVoteAndEndVotingPeriod(clientId1);
uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId2);

uint256 lastNounId = settleAuction();
settleAuction();
votingClientIds = [0];
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});

Expand All @@ -249,13 +244,12 @@ contract ProposalRewardsTest is BaseProposalRewardsTest {

uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1);

uint256 lastNounId = settleAuction();
settleAuction();

votingClientIds = [0];
vm.expectRevert('not enough time passed');
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});
}
Expand Down Expand Up @@ -283,12 +277,11 @@ contract ProposalRewardsTest is BaseProposalRewardsTest {

uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1);

uint256 lastNounId = settleAuction();
settleAuction();

votingClientIds = [0];
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});
assertEq(rewards.clientBalances(clientId1), 0.15 ether); // 15 eth * 1%
Expand Down Expand Up @@ -325,7 +318,6 @@ contract ProposalRewardsEligibilityTest is BaseProposalRewardsTest {
vm.expectRevert('at least one eligible proposal');
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});
}
Expand All @@ -337,7 +329,6 @@ contract ProposalRewardsEligibilityTest is BaseProposalRewardsTest {

rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});
}
Expand All @@ -357,11 +348,10 @@ contract AfterOneSuccessfulRewardsDistributionTest is BaseProposalRewardsTest {
lastProposalCreationTimestamp = block.timestamp;
uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1);

uint256 lastNounId = settleAuction();
settleAuction();
votingClientIds = [0];
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});

Expand All @@ -374,11 +364,10 @@ contract AfterOneSuccessfulRewardsDistributionTest is BaseProposalRewardsTest {
vm.warp(lastProposalCreationTimestamp + 2 weeks - 10);
uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1);

uint256 lastNounId = settleAuction();
settleAuction();
vm.expectRevert('not enough time passed');
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});
}
Expand All @@ -389,10 +378,9 @@ contract AfterOneSuccessfulRewardsDistributionTest is BaseProposalRewardsTest {
vm.warp(lastProposalCreationTimestamp + 2 weeks + 10);
uint32 proposalId = proposeVoteAndEndVotingPeriod(clientId1);

uint256 lastNounId = settleAuction();
settleAuction();
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});

Expand All @@ -418,11 +406,10 @@ contract VotesRewardsTest is BaseProposalRewardsTest {
vote(bidder1, proposalId, 1, 'i support', clientId1);
mineBlocks(VOTING_PERIOD);

uint256 lastNounId = settleAuction();
settleAuction();
votingClientIds = [clientId1];
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});

Expand All @@ -440,11 +427,10 @@ contract VotesRewardsTest is BaseProposalRewardsTest {

mineBlocks(VOTING_PERIOD);

uint256 lastNounId = settleAuction();
settleAuction();
votingClientIds = [clientId1, clientId2];
rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: proposalId,
lastAuctionedNounId: lastNounId,
votingClientIds: votingClientIds
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,6 @@ contract ProposalRewardsHappyFlow is RewardsBaseTest {

rewards.updateRewardsForProposalWritingAndVoting({
lastProposalId: uint32(proposalId),
lastAuctionedNounId: nounOnAuctionWhenLastProposalWasCreated,
votingClientIds: clientIds
});
}
Expand Down

0 comments on commit 500fc13

Please sign in to comment.