Skip to content

Commit

Permalink
Merge branch 'main' into security/white-hat-fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
developerfred authored Mar 14, 2023
2 parents 8431c80 + 4262063 commit c7d937d
Show file tree
Hide file tree
Showing 21 changed files with 1,536 additions and 1,011 deletions.
4 changes: 2 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@

## Sector#3 Contribution

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

- [ ] Reported contribution at https://goerli.sector3.xyz/v0/priorities/0x6660626F3b51c0A7a9C558Ade45B17B7De6f91c1
- [ ] Reported contribution at https://sepolia.sector3.xyz/v1/daos/0xB1932B5ba9Dfd0a2dCFa08140eb272DC60804699
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ Deploy a smart contract to the local network:
npx hardhat run --network localhost scripts/deploy-<contract>.ts
```

Deploy a smart contract to the Goerli test network:
Deploy a smart contract to the Sepolia test network:

```shell
npx hardhat run --network goerli scripts/deploy-<contract>.ts
npx hardhat run --network sepolia scripts/deploy-<contract>.ts
```

Verify a contract on Etherscan:
Expand Down
34 changes: 0 additions & 34 deletions contracts/Lock.sol

This file was deleted.

2 changes: 1 addition & 1 deletion contracts/governance/Sector3Governor.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/governance/Governor.sol";
import "@openzeppelin/contracts/governance/extensions/GovernorSettings.sol";
Expand Down
4 changes: 0 additions & 4 deletions contracts/protocol/Enums.sol

This file was deleted.

7 changes: 2 additions & 5 deletions contracts/protocol/IPriority.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "./Enums.sol";
import "./Structs.sol";
pragma solidity ^0.8.19;

interface IPriority {

/**
* Add a contribution for the current epoch.
*/
function addContribution(Contribution memory contribution) external;
function addContribution(string memory description, string memory proofURL, uint8 hoursSpent, uint8 alignmentPercentage) external;

/**
* Claim reward for contributions made in a past epoch.
Expand Down
18 changes: 11 additions & 7 deletions contracts/protocol/Sector3DAO.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
pragma solidity ^0.8.19;

import './Sector3DAOPriority.sol';

Expand All @@ -12,7 +12,7 @@ contract Sector3DAO {
/**
* The protocol version.
*/
uint8 public constant version = 0;
uint8 public constant version = 1;

/**
* The smart contract owner.
Expand Down Expand Up @@ -43,7 +43,15 @@ contract Sector3DAO {
name = name_;
purpose = purpose_;
token = token_;
owner = msg.sender;
owner = tx.origin;
}

/**
* Updates the DAO's owner.
*/
function setOwner(address owner_) public {
require(msg.sender == owner, "You aren't the owner");
owner = owner_;
}

modifier onlyOwner() {
Expand Down Expand Up @@ -79,10 +87,6 @@ contract Sector3DAO {
return priority;
}

function getPriorityCount() public view returns (uint16) {
return uint16(priorities.length);
}

function getPriorities() public view returns (Sector3DAOPriority[] memory) {
return priorities;
}
Expand Down
7 changes: 1 addition & 6 deletions contracts/protocol/Sector3DAOFactory.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
pragma solidity ^0.8.19;

import './Sector3DAO.sol';

Expand All @@ -13,11 +13,6 @@ contract Sector3DAOFactory {

constructor() {
owner = msg.sender;
// daos.push(0x5FbDB2315678afecb367f032d93F642f64180aa3); // localhost
daos.push(0xEa98D59e4EF83822393AF87e587713c2674eD4FD); // Sector#3 DAO (v0)
daos.push(0xd87246302AE8f12485BB525f27778106c636166e); // BanklessDAO (v3)
daos.push(0x2D624a0bA38b40B4f7bE2bfeb56B6B0dD81Be6A1); // Nation3 (v0)
daos.push(0x9741B82017485759c9Bcc13FeA10c1105f82d25C); // Bankless Africa (v0)
}


Expand Down
109 changes: 66 additions & 43 deletions contracts/protocol/Sector3DAOPriority.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "./IPriority.sol";
import "./Enums.sol";
import "./Structs.sol";

contract Sector3DAOPriority is IPriority {
Expand All @@ -15,21 +15,28 @@ contract Sector3DAOPriority is IPriority {
uint256 public immutable startTime;
uint16 public immutable epochDuration;
uint256 public immutable epochBudget;
IERC721 public immutable gatingNFT;
Contribution[] contributions;
mapping(uint16 => mapping(address => bool)) claims;
uint256 public claimsBalance;

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

error EpochNotYetEnded();
error EpochNotYetFunded();
error NoRewardForEpoch();
error RewardAlreadyClaimed();
error NoGatingNFTOwnership();

constructor(address dao_, string memory title_, address rewardToken_, uint16 epochDurationInDays, uint256 epochBudget_) {
constructor(address dao_, string memory title_, address rewardToken_, uint16 epochDurationInDays, uint256 epochBudget_, address gatingNFT_) {
dao = dao_;
title = title_;
rewardToken = IERC20(rewardToken_);
startTime = block.timestamp;
epochDuration = epochDurationInDays;
epochBudget = epochBudget_;
gatingNFT = IERC721(gatingNFT_);
}

/**
Expand All @@ -41,40 +48,48 @@ contract Sector3DAOPriority is IPriority {
return uint16(timePassedSinceStart / epochDurationInSeconds);
}

function addContribution(Contribution memory contribution) public {
contribution.timestamp = block.timestamp;
contribution.epochIndex = getEpochIndex();
contribution.contributor = msg.sender;
contribution.alignmentPercentage = uint8(contribution.alignment) * 20;
contributions.push(contribution);
emit ContributionAdded(contribution);
}

function addContribution2(string memory description, string memory proofURL, uint8 hoursSpent, Alignment alignment) public {
/**
* @notice Adds a contribution to the current epoch.
*/
function addContribution(string memory description, string memory proofURL, uint8 hoursSpent, uint8 alignmentPercentage) public {
if (address(gatingNFT) != address(0x0)) {
if (gatingNFT.balanceOf(msg.sender) == 0) {
revert NoGatingNFTOwnership();
}
}
Contribution memory contribution = Contribution({
timestamp: block.timestamp,
epochIndex: getEpochIndex(),
contributor: msg.sender,
description: description,
proofURL: proofURL,
hoursSpent: hoursSpent,
alignment: alignment,
alignmentPercentage: uint8(alignment) * 20
alignmentPercentage: alignmentPercentage
});
contributions.push(contribution);
emit ContributionAdded(contribution);
}

function getContributionCount() public view returns (uint16) {
return uint16(contributions.length);
}

function getContributions() public view returns (Contribution[] memory) {
return contributions;
}

function getContribution(uint16 index) public view returns (Contribution memory) {
return contributions[index];
function getEpochContributions(uint16 epochIndex) public view returns (Contribution[] memory) {
uint16 count = 0;
for (uint16 i = 0; i < contributions.length; i++) {
if (contributions[i].epochIndex == epochIndex) {
count++;
}
}
Contribution[] memory epochContributions = new Contribution[](count);
count = 0;
for (uint16 i = 0; i < contributions.length; i++) {
if (contributions[i].epochIndex == epochIndex) {
epochContributions[count] = contributions[i];
count++;
}
}
return epochContributions;
}

/**
Expand Down Expand Up @@ -115,30 +130,12 @@ contract Sector3DAOPriority is IPriority {
}

/**
* @notice Checks if the smart contract has received enough funding to cover claims for a past epoch.
*
* @param epochIndex The index of the epoch to check.
* @return A boolean indicating whether the epoch is funded or not.
*
* @dev This function loops through all past epochs to calculate whether the current epoch is funded or not.
* If the number of past epochs becomes very large, the function may consume an excessive amount of gas and fail to execute,
* thereby preventing other legitimate functions from executing. Epochs without contributions are excluded from funding.
*/

function isEpochFunded(uint16 epochIndex) public view returns (bool) {
if (epochIndex >= getEpochIndex()) {
revert EpochNotYetEnded();
}
if (getEpochContributions(epochIndex).length == 0) {
return false;
}
uint256 totalBudget = epochBudget * (epochIndex + 1);
uint256 totalFundingReceived = rewardToken.balanceOf(address(this)) + claimsBalance;
uint16 numberOfEpochsWithContributions = epochIndex + 1;
return totalFundingReceived >= totalBudget;
* Checks if a contributor's reward has been claimed for a given epoch.
*/
function isRewardClaimed(uint16 epochIndex, address contributor) public view returns (bool) {
return claims[epochIndex][contributor];
}


/**
* Calculates a contributor's percentage allocation of the budget for a given epoch.
*
Expand All @@ -162,4 +159,30 @@ contract Sector3DAOPriority is IPriority {
return uint8(hoursSpentContributor * 100 / hoursSpentAllContributors);
}
}

/**
* @notice Checks if the smart contract has received enough funding to cover claims for a past epoch.
* @dev Epochs without contributions are excluded from funding.
*/
function isEpochFunded(uint16 epochIndex) public view returns (bool) {
if (epochIndex >= getEpochIndex()) {
revert EpochNotYetEnded();
}
if (getEpochContributions(epochIndex).length == 0) {
return false;
}
uint16 numberOfEpochsWithContributions = 0;
for (uint16 i = 0; i <= epochIndex; i++) {
if (getEpochContributions(i).length > 0) {
numberOfEpochsWithContributions++;
}
}
if (numberOfEpochsWithContributions == 0) {
return false;
} else {
uint256 totalBudget = epochBudget * numberOfEpochsWithContributions;
uint256 totalFundingReceived = rewardToken.balanceOf(address(this)) + claimsBalance;
return totalFundingReceived >= totalBudget;
}
}
}
7 changes: 2 additions & 5 deletions contracts/protocol/Structs.sol
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "./Enums.sol";
pragma solidity ^0.8.19;

struct Contribution {
uint256 timestamp;
uint16 epochIndex;
address contributor;
string description;
string proofURL;
Alignment alignment;
uint8 alignmentPercentage;
uint8 hoursSpent;
uint8 alignmentPercentage;
}
39 changes: 39 additions & 0 deletions contracts/token/S3DOVE.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract S3DOVE is ERC721, ERC721Enumerable, Ownable {
using Counters for Counters.Counter;

Counters.Counter private _tokenIdCounter;

constructor() ERC721(unicode"Sector#3 Dove 🕊️", "S3DOVE") {}

function safeMint(address to) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
}

// The following functions are overrides required by Solidity.

function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
internal
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId, batchSize);
}

function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
Loading

0 comments on commit c7d937d

Please sign in to comment.