Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions web3backend/contracts/writersDAO.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface ISoulNft {
function balanceOf(address owner) external view returns (uint256);

function burn(uint256 tokenId) external;

function showIds(address _member) external view returns (uint256);

function showMembers() external view returns (address[] memory);
}

contract WritersDAO {

struct Writer{
uint256 id_;
address owner;
string title;
string content;
uint yayvotes;
uint nayvotes;
Status status;
}


enum Status {
Pending,
Approved
}
uint256 public id;
uint256 votingTime;
uint256 _time;
address admin;
ISoulNft soulnft;

struct DAOTime {
uint256 daovotetime;
}

enum Votes {
YAY,
NAY
}

constructor(address _address, address _writersDAOToken) {
admin = _address;
soulnft = ISoulNft(_writersDAOToken);
votingTime = 1 days;
}

mapping(uint256 => Writer) _writer;
mapping(address => uint256[]) usersPost;
mapping(uint256 => DAOTime) public daotime;
mapping(address => uint256) memberVotes;
mapping(address => mapping(uint256 => bool)) public hasVoted;

error AlreadyVoted();
error VotingTimeElapsed();
error NotDAOMember();
error OnlyAdmin();
error NotYetTime();
error VotingInProgress();

event CreatePost(uint256 _id, string _title, string _content);
event Vote(address member, uint256 _id);
event ApproveImpact(uint256 _id);

function createPost(string memory _title, string memory _content) public returns (uint256 _id) {
id++;
_id = id;
if (_id == 1) {
_time = block.timestamp + 30 days;
}
Writer storage writer = _writer[_id];
DAOTime storage time = daotime[_id];
write.id_ = _id;
write.owner = msg.sender;
write.title = _title;
write.content = _content;
write.status = Status.Pending;

usersPost[msg.sender].push(_id);
emit CreatePost(_id, _title, _content);
}

function vote(uint256 _id, Votes votes) external {
if (soulnft.balanceOf(msg.sender) != 1) revert NotDAOMember();
Writer storage writer = _writer[_id];
if (hasVoted[msg.sender][_id] != false) revert AlreadyVoted();
if (block.timestamp > daotime[_id].daovotetime) {
revert VotingTimeElapsed();
}
hasVoted[msg.sender][_id] = true;

uint8 numVotes = 1;
if (votes == Votes.YAY) {
writer.yayvotes += numVotes;
} else {
writer.nayvotes += numVotes;
}
memberVotes[msg.sender]++;

emit Vote(msg.sender, _id);
}

function approveImpact(uint256 _id) external {
if (soulnft.balanceOf(msg.sender) != 1) revert NotDAOMember();
if (daotime[_id].daovotetime > block.timestamp) {
revert VotingInProgress();
}
Writer storage writer = _writer[_id];
if (writer.yayvotes > writer.nayvotes) {
writer.status = Status.Approved;
}

emit ApproveImpact(_id);
}


}
121 changes: 121 additions & 0 deletions web3backend/contracts/writersDAOToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

/// @title WildLifeGuardianToken - A unique NFT contract for Wildlife Guardians.

contract writersDAOToken is ERC721, ERC721URIStorage, Ownable {
uint256 private _tokenIdCounter;
bytes32 public rootHash;
string tokenUri;

address[] public members;

error InvalidAddress(address);
error AlreadyClaimed();
error NotWhitelisted();

/// @dev Mapping to keep track of claimed tokens.

mapping(address => bool) claimed;
mapping(address => uint256) addressToIds;

/// @notice Constructor to initialize the contract.
/// @param _owner The address of the contract owner.
/// @param _tokenUri The token URI for the new tokens.
constructor(address _owner, string memory _tokenUri) ERC721("Impact Token", "ITK") Ownable(_owner) {
tokenUri = _tokenUri;
}

/// @notice Safely mints new tokens and assigns them to specified addresses.
/// @param to An array of addresses to receive the newly minted tokens.

function safeMint(address[] calldata to) public onlyOwner {
string memory URI = tokenUri;
for (uint256 i = 0; i < to.length; ++i) {
if (to[i] == address(0)) {
revert InvalidAddress(to[i]);
}
if (balanceOf(to[i]) == 0) {
_setTokenURI(_tokenIdCounter, URI);
_safeMint(to[i], _tokenIdCounter);
members.push(to[i]);
addressToIds[to[i]] = _tokenIdCounter;
_tokenIdCounter++;
} else {
continue;
}
}
}

/// @notice Claims a token for an address using a Merkle proof.
/// @param _merkleProof The Merkle proof to verify the claim.
/// @param _account The address claiming the token.
/// @return true if the claim is successful, false otherwise.

function claimToken(bytes32[] calldata _merkleProof, address _account) external returns (bool) {
require(_account == msg.sender, "Only owner of account can claim");
require(balanceOf(_account) == 0, "You already own an nft");
if (claimed[_account]) {
revert AlreadyClaimed();
}
bytes32 leaf = keccak256(abi.encodePacked(_account, uint256(1)));
if (!MerkleProof.verify(_merkleProof, rootHash, leaf)) {
revert NotWhitelisted();
}

claimed[_account] = true;
_setTokenURI(_tokenIdCounter, tokenUri);
_safeMint(_account, _tokenIdCounter);
_tokenIdCounter++;

return true;
}

/// @notice Adds a new Merkle root hash for token whitelisting.
/// @param _rootHash The new Merkle root hash.

function addRootHash(bytes32 _rootHash) external onlyOwner {
rootHash = _rootHash;
}

/// @notice Burns a token by its ID.
/// @param tokenId The ID of the token to burn.

function burn(uint256 tokenId) external {
_burn(tokenId);
}

function showIds(address _member) public view returns (uint256) {
return addressToIds[_member];
}

function showMembers() external view returns (address[] memory) {
return members;
}

// function overrides

/// @dev Overrides the transferFrom function to disable transfers.

function transferFrom(address from, address to, uint256 tokenId) public pure override(ERC721, IERC721) {
(from, to, tokenId);
revert("SoulBoundToken: transfer is disabled");
}

/// @inheritdoc ERC721

function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) {
return super.tokenURI(tokenId);
}

/// @inheritdoc ERC721

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