Skip to content

Commit c7d937d

Browse files
Merge branch 'main' into security/white-hat-fixed
2 parents 8431c80 + 4262063 commit c7d937d

21 files changed

+1536
-1011
lines changed

.github/pull_request_template.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88

99
## Sector#3 Contribution
1010

11-
<!--- Please add this pull request as a DAO contribution on Sector#3: https://goerli.sector3.xyz/daos -->
11+
<!--- Please add this pull request as a DAO contribution on Sector#3: https://sepolia.sector3.xyz -->
1212

13-
- [ ] Reported contribution at https://goerli.sector3.xyz/v0/priorities/0x6660626F3b51c0A7a9C558Ade45B17B7De6f91c1
13+
- [ ] Reported contribution at https://sepolia.sector3.xyz/v1/daos/0xB1932B5ba9Dfd0a2dCFa08140eb272DC60804699

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,10 @@ Deploy a smart contract to the local network:
4343
npx hardhat run --network localhost scripts/deploy-<contract>.ts
4444
```
4545

46-
Deploy a smart contract to the Goerli test network:
46+
Deploy a smart contract to the Sepolia test network:
4747

4848
```shell
49-
npx hardhat run --network goerli scripts/deploy-<contract>.ts
49+
npx hardhat run --network sepolia scripts/deploy-<contract>.ts
5050
```
5151

5252
Verify a contract on Etherscan:

contracts/Lock.sol

Lines changed: 0 additions & 34 deletions
This file was deleted.

contracts/governance/Sector3Governor.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.17;
2+
pragma solidity ^0.8.19;
33

44
import "@openzeppelin/contracts/governance/Governor.sol";
55
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";

contracts/protocol/Enums.sol

Lines changed: 0 additions & 4 deletions
This file was deleted.

contracts/protocol/IPriority.sol

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.17;
3-
4-
import "./Enums.sol";
5-
import "./Structs.sol";
2+
pragma solidity ^0.8.19;
63

74
interface IPriority {
85

96
/**
107
* Add a contribution for the current epoch.
118
*/
12-
function addContribution(Contribution memory contribution) external;
9+
function addContribution(string memory description, string memory proofURL, uint8 hoursSpent, uint8 alignmentPercentage) external;
1310

1411
/**
1512
* Claim reward for contributions made in a past epoch.

contracts/protocol/Sector3DAO.sol

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.17;
2+
pragma solidity ^0.8.19;
33

44
import './Sector3DAOPriority.sol';
55

@@ -12,7 +12,7 @@ contract Sector3DAO {
1212
/**
1313
* The protocol version.
1414
*/
15-
uint8 public constant version = 0;
15+
uint8 public constant version = 1;
1616

1717
/**
1818
* The smart contract owner.
@@ -43,7 +43,15 @@ contract Sector3DAO {
4343
name = name_;
4444
purpose = purpose_;
4545
token = token_;
46-
owner = msg.sender;
46+
owner = tx.origin;
47+
}
48+
49+
/**
50+
* Updates the DAO's owner.
51+
*/
52+
function setOwner(address owner_) public {
53+
require(msg.sender == owner, "You aren't the owner");
54+
owner = owner_;
4755
}
4856

4957
modifier onlyOwner() {
@@ -79,10 +87,6 @@ contract Sector3DAO {
7987
return priority;
8088
}
8189

82-
function getPriorityCount() public view returns (uint16) {
83-
return uint16(priorities.length);
84-
}
85-
8690
function getPriorities() public view returns (Sector3DAOPriority[] memory) {
8791
return priorities;
8892
}

contracts/protocol/Sector3DAOFactory.sol

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.17;
2+
pragma solidity ^0.8.19;
33

44
import './Sector3DAO.sol';
55

@@ -13,11 +13,6 @@ contract Sector3DAOFactory {
1313

1414
constructor() {
1515
owner = msg.sender;
16-
// daos.push(0x5FbDB2315678afecb367f032d93F642f64180aa3); // localhost
17-
daos.push(0xEa98D59e4EF83822393AF87e587713c2674eD4FD); // Sector#3 DAO (v0)
18-
daos.push(0xd87246302AE8f12485BB525f27778106c636166e); // BanklessDAO (v3)
19-
daos.push(0x2D624a0bA38b40B4f7bE2bfeb56B6B0dD81Be6A1); // Nation3 (v0)
20-
daos.push(0x9741B82017485759c9Bcc13FeA10c1105f82d25C); // Bankless Africa (v0)
2116
}
2217

2318

contracts/protocol/Sector3DAOPriority.sol

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.17;
2+
pragma solidity ^0.8.19;
33

44
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
5+
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
56
import "./IPriority.sol";
6-
import "./Enums.sol";
77
import "./Structs.sol";
88

99
contract Sector3DAOPriority is IPriority {
@@ -15,21 +15,28 @@ contract Sector3DAOPriority is IPriority {
1515
uint256 public immutable startTime;
1616
uint16 public immutable epochDuration;
1717
uint256 public immutable epochBudget;
18+
IERC721 public immutable gatingNFT;
1819
Contribution[] contributions;
20+
mapping(uint16 => mapping(address => bool)) claims;
21+
uint256 public claimsBalance;
1922

2023
event ContributionAdded(Contribution contribution);
2124
event RewardClaimed(uint16 epochIndex, address contributor, uint256 amount);
2225

2326
error EpochNotYetEnded();
27+
error EpochNotYetFunded();
2428
error NoRewardForEpoch();
29+
error RewardAlreadyClaimed();
30+
error NoGatingNFTOwnership();
2531

26-
constructor(address dao_, string memory title_, address rewardToken_, uint16 epochDurationInDays, uint256 epochBudget_) {
32+
constructor(address dao_, string memory title_, address rewardToken_, uint16 epochDurationInDays, uint256 epochBudget_, address gatingNFT_) {
2733
dao = dao_;
2834
title = title_;
2935
rewardToken = IERC20(rewardToken_);
3036
startTime = block.timestamp;
3137
epochDuration = epochDurationInDays;
3238
epochBudget = epochBudget_;
39+
gatingNFT = IERC721(gatingNFT_);
3340
}
3441

3542
/**
@@ -41,40 +48,48 @@ contract Sector3DAOPriority is IPriority {
4148
return uint16(timePassedSinceStart / epochDurationInSeconds);
4249
}
4350

44-
function addContribution(Contribution memory contribution) public {
45-
contribution.timestamp = block.timestamp;
46-
contribution.epochIndex = getEpochIndex();
47-
contribution.contributor = msg.sender;
48-
contribution.alignmentPercentage = uint8(contribution.alignment) * 20;
49-
contributions.push(contribution);
50-
emit ContributionAdded(contribution);
51-
}
52-
53-
function addContribution2(string memory description, string memory proofURL, uint8 hoursSpent, Alignment alignment) public {
51+
/**
52+
* @notice Adds a contribution to the current epoch.
53+
*/
54+
function addContribution(string memory description, string memory proofURL, uint8 hoursSpent, uint8 alignmentPercentage) public {
55+
if (address(gatingNFT) != address(0x0)) {
56+
if (gatingNFT.balanceOf(msg.sender) == 0) {
57+
revert NoGatingNFTOwnership();
58+
}
59+
}
5460
Contribution memory contribution = Contribution({
5561
timestamp: block.timestamp,
5662
epochIndex: getEpochIndex(),
5763
contributor: msg.sender,
5864
description: description,
5965
proofURL: proofURL,
6066
hoursSpent: hoursSpent,
61-
alignment: alignment,
62-
alignmentPercentage: uint8(alignment) * 20
67+
alignmentPercentage: alignmentPercentage
6368
});
6469
contributions.push(contribution);
6570
emit ContributionAdded(contribution);
6671
}
6772

68-
function getContributionCount() public view returns (uint16) {
69-
return uint16(contributions.length);
70-
}
71-
7273
function getContributions() public view returns (Contribution[] memory) {
7374
return contributions;
7475
}
7576

76-
function getContribution(uint16 index) public view returns (Contribution memory) {
77-
return contributions[index];
77+
function getEpochContributions(uint16 epochIndex) public view returns (Contribution[] memory) {
78+
uint16 count = 0;
79+
for (uint16 i = 0; i < contributions.length; i++) {
80+
if (contributions[i].epochIndex == epochIndex) {
81+
count++;
82+
}
83+
}
84+
Contribution[] memory epochContributions = new Contribution[](count);
85+
count = 0;
86+
for (uint16 i = 0; i < contributions.length; i++) {
87+
if (contributions[i].epochIndex == epochIndex) {
88+
epochContributions[count] = contributions[i];
89+
count++;
90+
}
91+
}
92+
return epochContributions;
7893
}
7994

8095
/**
@@ -115,30 +130,12 @@ contract Sector3DAOPriority is IPriority {
115130
}
116131

117132
/**
118-
* @notice Checks if the smart contract has received enough funding to cover claims for a past epoch.
119-
*
120-
* @param epochIndex The index of the epoch to check.
121-
* @return A boolean indicating whether the epoch is funded or not.
122-
*
123-
* @dev This function loops through all past epochs to calculate whether the current epoch is funded or not.
124-
* If the number of past epochs becomes very large, the function may consume an excessive amount of gas and fail to execute,
125-
* thereby preventing other legitimate functions from executing. Epochs without contributions are excluded from funding.
126-
*/
127-
128-
function isEpochFunded(uint16 epochIndex) public view returns (bool) {
129-
if (epochIndex >= getEpochIndex()) {
130-
revert EpochNotYetEnded();
131-
}
132-
if (getEpochContributions(epochIndex).length == 0) {
133-
return false;
134-
}
135-
uint256 totalBudget = epochBudget * (epochIndex + 1);
136-
uint256 totalFundingReceived = rewardToken.balanceOf(address(this)) + claimsBalance;
137-
uint16 numberOfEpochsWithContributions = epochIndex + 1;
138-
return totalFundingReceived >= totalBudget;
133+
* Checks if a contributor's reward has been claimed for a given epoch.
134+
*/
135+
function isRewardClaimed(uint16 epochIndex, address contributor) public view returns (bool) {
136+
return claims[epochIndex][contributor];
139137
}
140138

141-
142139
/**
143140
* Calculates a contributor's percentage allocation of the budget for a given epoch.
144141
*
@@ -162,4 +159,30 @@ contract Sector3DAOPriority is IPriority {
162159
return uint8(hoursSpentContributor * 100 / hoursSpentAllContributors);
163160
}
164161
}
162+
163+
/**
164+
* @notice Checks if the smart contract has received enough funding to cover claims for a past epoch.
165+
* @dev Epochs without contributions are excluded from funding.
166+
*/
167+
function isEpochFunded(uint16 epochIndex) public view returns (bool) {
168+
if (epochIndex >= getEpochIndex()) {
169+
revert EpochNotYetEnded();
170+
}
171+
if (getEpochContributions(epochIndex).length == 0) {
172+
return false;
173+
}
174+
uint16 numberOfEpochsWithContributions = 0;
175+
for (uint16 i = 0; i <= epochIndex; i++) {
176+
if (getEpochContributions(i).length > 0) {
177+
numberOfEpochsWithContributions++;
178+
}
179+
}
180+
if (numberOfEpochsWithContributions == 0) {
181+
return false;
182+
} else {
183+
uint256 totalBudget = epochBudget * numberOfEpochsWithContributions;
184+
uint256 totalFundingReceived = rewardToken.balanceOf(address(this)) + claimsBalance;
185+
return totalFundingReceived >= totalBudget;
186+
}
187+
}
165188
}

contracts/protocol/Structs.sol

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
// SPDX-License-Identifier: MIT
2-
pragma solidity ^0.8.17;
3-
4-
import "./Enums.sol";
2+
pragma solidity ^0.8.19;
53

64
struct Contribution {
75
uint256 timestamp;
86
uint16 epochIndex;
97
address contributor;
108
string description;
119
string proofURL;
12-
Alignment alignment;
13-
uint8 alignmentPercentage;
1410
uint8 hoursSpent;
11+
uint8 alignmentPercentage;
1512
}

0 commit comments

Comments
 (0)